/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Advertisement = Container.expand(function (textIndex) {
var self = Container.call(this);
// Create advertisement frame
var frame = self.addChild(LK.getAsset('adFrame', {
anchorX: 0.5,
anchorY: 0.5
}));
// Create advertisement board
var board = self.addChild(LK.getAsset('adBoard', {
anchorX: 0.5,
anchorY: 0.5
}));
// Add advertisement text with different content based on index
var adTextContent = adTexts[textIndex % adTexts.length];
var adText = new Text2(adTextContent, {
size: 28,
fill: 0xffffff
});
adText.anchor.set(0.5, 0.5);
board.addChild(adText);
// Add flashing effect to make it more eye-catching
self.animationTimer = 0;
self.update = function () {
self.animationTimer += 0.05;
// Subtle pulsing effect
var scale = 1 + Math.sin(self.animationTimer) * 0.05;
board.scaleX = scale;
board.scaleY = scale;
// Subtle color shift effect
var colorShift = Math.sin(self.animationTimer * 0.3) * 0.1;
board.alpha = 0.9 + colorShift;
};
return self;
});
var Cashier = Container.expand(function () {
var self = Container.call(this);
// Create cashier counter
var counter = self.addChild(LK.getAsset('cashierCounter', {
anchorX: 0.5,
anchorY: 0.5
}));
// Create human-like cashier
var head = self.addChild(LK.getAsset('cashierHead', {
anchorX: 0.5,
anchorY: 0.5
}));
head.y = -35;
var body = self.addChild(LK.getAsset('cashierBody', {
anchorX: 0.5,
anchorY: 0.5
}));
body.y = -15;
var leftArm = self.addChild(LK.getAsset('cashierArm', {
anchorX: 0.5,
anchorY: 0
}));
leftArm.x = -12;
leftArm.y = -22;
var rightArm = self.addChild(LK.getAsset('cashierArm', {
anchorX: 0.5,
anchorY: 0
}));
rightArm.x = 12;
rightArm.y = -22;
self.bodyParts = {
head: head,
body: body,
leftArm: leftArm,
rightArm: rightArm
};
self.isProcessing = false;
self.processingTimer = 0;
self.processCustomer = function (customer) {
if (!self.isProcessing) {
self.isProcessing = true;
self.processingTimer = 60; // 1 second processing time
// Animate cashier working
tween(self.bodyParts.rightArm, {
rotation: -0.5
}, {
duration: 300,
onComplete: function onComplete() {
tween(self.bodyParts.rightArm, {
rotation: 0
}, {
duration: 300
});
}
});
}
};
self.update = function () {
if (self.isProcessing) {
self.processingTimer--;
if (self.processingTimer <= 0) {
self.isProcessing = false;
}
// Slight head bob while processing
self.bodyParts.head.y = -35 + Math.sin(LK.ticks * 0.3) * 1;
} else {
self.bodyParts.head.y = -35;
}
};
return self;
});
var Customer = Container.expand(function () {
var self = Container.call(this);
// Create human-like customer with body parts
var head = self.addChild(LK.getAsset('customerHead', {
anchorX: 0.5,
anchorY: 0.5
}));
head.y = -20;
var body = self.addChild(LK.getAsset('customerBody', {
anchorX: 0.5,
anchorY: 0.5
}));
body.y = 0;
var leftArm = self.addChild(LK.getAsset('customerArm', {
anchorX: 0.5,
anchorY: 0
}));
leftArm.x = -15;
leftArm.y = -8;
var rightArm = self.addChild(LK.getAsset('customerArm', {
anchorX: 0.5,
anchorY: 0
}));
rightArm.x = 15;
rightArm.y = -8;
var leftLeg = self.addChild(LK.getAsset('customerLeg', {
anchorX: 0.5,
anchorY: 0
}));
leftLeg.x = -8;
leftLeg.y = 16;
var rightLeg = self.addChild(LK.getAsset('customerLeg', {
anchorX: 0.5,
anchorY: 0
}));
rightLeg.x = 8;
rightLeg.y = 16;
// Store body parts for animation
self.bodyParts = {
head: head,
body: body,
leftArm: leftArm,
rightArm: rightArm,
leftLeg: leftLeg,
rightLeg: rightLeg
};
self.speed = 1 + Math.random() * 2;
self.targetShelf = null;
self.state = 'browsing'; // browsing, shopping, checkout, leaving
self.patience = 300 + Math.random() * 200;
self.maxPatience = self.patience;
self.walkCycle = 0;
self.shoppingCart = [];
self.hasComplained = false;
self.complain = function () {
// Visual complaint effect - flash red
LK.effects.flashObject(self, 0xff0000, 800);
// Create complaint text above customer
var complaintText = new Text2('No products!', {
size: 20,
fill: 0xff0000
});
complaintText.anchor.set(0.5, 1);
complaintText.x = self.x;
complaintText.y = self.y - 40;
game.addChild(complaintText);
// Animate complaint text
tween(complaintText, {
y: complaintText.y - 30,
alpha: 0
}, {
duration: 1500,
onComplete: function onComplete() {
complaintText.destroy();
}
});
// Reduce customer patience significantly
self.patience = Math.min(self.patience, 30);
};
self.findNearestShelf = function () {
var nearestShelf = null;
var minDistance = Infinity;
var hasProductsAvailable = false;
shelves.forEach(function (shelf) {
if (shelf.products.length > 0) {
hasProductsAvailable = true;
var distance = Math.sqrt(Math.pow(self.x - shelf.x, 2) + Math.pow(self.y - shelf.y, 2));
if (distance < minDistance) {
minDistance = distance;
nearestShelf = shelf;
}
}
});
// If no products available, customer complains
if (!hasProductsAvailable && !self.hasComplained) {
self.hasComplained = true;
self.complain();
}
return nearestShelf;
};
self.update = function () {
self.patience--;
if (self.patience <= 0) {
self.state = 'leaving';
}
// Walking animation
self.walkCycle += 0.2;
if (self.state === 'browsing' || self.state === 'checkout') {
self.bodyParts.leftLeg.rotation = Math.sin(self.walkCycle) * 0.3;
self.bodyParts.rightLeg.rotation = Math.sin(self.walkCycle + Math.PI) * 0.3;
self.bodyParts.leftArm.rotation = Math.sin(self.walkCycle + Math.PI) * 0.2;
self.bodyParts.rightArm.rotation = Math.sin(self.walkCycle) * 0.2;
self.bodyParts.body.y = Math.sin(self.walkCycle * 2) * 1;
}
if (self.state === 'browsing') {
if (!self.targetShelf) {
self.targetShelf = self.findNearestShelf();
}
if (self.targetShelf) {
var dx = self.targetShelf.x - self.x;
var dy = self.targetShelf.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 60) {
self.state = 'shopping';
self.patience = 60;
// Stop walking animation
self.bodyParts.leftLeg.rotation = 0;
self.bodyParts.rightLeg.rotation = 0;
self.bodyParts.leftArm.rotation = 0;
self.bodyParts.rightArm.rotation = 0;
} else {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else {
// No shelves with products available, customer becomes impatient
if (!self.hasComplained) {
self.hasComplained = true;
self.complain();
}
self.state = 'leaving';
}
} else if (self.state === 'shopping') {
if (self.targetShelf && self.targetShelf.products.length > 0) {
// 73% chance to make a purchase
if (Math.random() < 0.73) {
// Add item to shopping cart instead of direct purchase
self.shoppingCart.push({
item: self.targetShelf.productType,
price: self.targetShelf.price
});
self.targetShelf.sellProduct();
// Move to checkout
self.state = 'checkout';
self.targetShelf = null;
} else {
// Customer decides not to buy, leaves the store
self.state = 'leaving';
self.targetShelf = null;
}
} else {
self.state = 'browsing';
self.targetShelf = null;
}
} else if (self.state === 'checkout') {
// Move to cashier
var cashier = findNearestCashier();
if (cashier) {
var dx = cashier.x - self.x;
var dy = cashier.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 80) {
// Process purchase at cashier
var total = 0;
self.shoppingCart.forEach(function (item) {
total += item.price;
});
// Apply mascot money multiplier if mascot is active
if (mascot) {
total = Math.floor(total * mascotMoneyMultiplier);
}
money += total;
cashier.processCustomer(self);
createMoneyEffect(cashier.x, cashier.y - 50, total);
updateUI();
LK.getSound('cashRegister').play();
self.state = 'leaving';
} else {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else {
self.state = 'leaving';
}
} else if (self.state === 'leaving') {
// Move towards exit door
var dx = 1800 - self.x;
var dy = 600 - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 20) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else {
// Customer reached exit, remove them
self.destroy();
customers.splice(customers.indexOf(self), 1);
}
}
};
return self;
});
var CustomizePanel = Container.expand(function () {
var self = Container.call(this);
// Create panel background
var panelBg = self.attachAsset('customizePanel', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.4
});
// Panel title
var titleText = new Text2('BAM Market Customization', {
size: 70,
fill: 0xffffff
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 0;
titleText.y = -420;
self.addChild(titleText);
// Floor materials section
var floorMaterialLabel = new Text2('Floor Materials', {
size: 50,
fill: 0xffffff
});
floorMaterialLabel.anchor.set(0.5, 0.5);
floorMaterialLabel.x = 0;
floorMaterialLabel.y = -350;
self.addChild(floorMaterialLabel);
// Floor material options with different prices
var floorMaterials = [{
color: 0xf0f0f0,
name: 'Basic Tile',
price: 50,
pattern: 'solid'
}, {
color: 0x8b4513,
name: 'Wood Floor',
price: 100,
pattern: 'wood'
}, {
color: 0x696969,
name: 'Marble',
price: 200,
pattern: 'marble'
}, {
color: 0x228b22,
name: 'Carpet',
price: 75,
pattern: 'carpet'
}, {
color: 0x4169e1,
name: 'Premium Tile',
price: 150,
pattern: 'premium'
}, {
color: 0xff69b4,
name: 'Designer Floor',
price: 300,
pattern: 'designer'
}];
for (var i = 0; i < floorMaterials.length; i++) {
var materialOption = self.addChild(LK.getAsset('colorOption', {
anchorX: 0.5,
anchorY: 0.5
}));
materialOption.tint = floorMaterials[i].color;
materialOption.x = (i - 2.5) * 130;
materialOption.y = -250;
materialOption.scaleX = 1.2;
materialOption.scaleY = 1.2;
materialOption.colorValue = floorMaterials[i].color;
materialOption.materialPrice = floorMaterials[i].price;
materialOption.materialName = floorMaterials[i].name;
materialOption.optionType = 'floor';
// Add price text to material option
var priceText = new Text2('$' + floorMaterials[i].price, {
size: 30,
fill: 0xffffff
});
priceText.anchor.set(0.5, 0.5);
priceText.y = 60;
materialOption.addChild(priceText);
// Add material name text
var nameText = new Text2(floorMaterials[i].name, {
size: 28,
fill: 0xffffff
});
nameText.anchor.set(0.5, 0.5);
nameText.y = -60;
materialOption.addChild(nameText);
materialOption.down = function (x, y, obj) {
if (money >= obj.materialPrice) {
money -= obj.materialPrice;
storeFloor.tint = obj.colorValue;
// Add visual effect based on material type
if (obj.materialName === 'Marble') {
storeFloor.alpha = 0.9;
} else if (obj.materialName === 'Wood Floor') {
storeFloor.alpha = 0.95;
} else {
storeFloor.alpha = 1.0;
}
updateUI();
LK.getSound('purchase').play();
LK.effects.flashObject(obj, 0x00ff00, 300);
} else {
LK.effects.flashObject(obj, 0xff0000, 300);
}
};
}
// Shelf styles section
var shelfStyleLabel = new Text2('Shelf Styles', {
size: 50,
fill: 0xffffff
});
shelfStyleLabel.anchor.set(0.5, 0.5);
shelfStyleLabel.x = 0;
shelfStyleLabel.y = -80;
self.addChild(shelfStyleLabel);
var shelfStyles = [{
color: 0x8b4513,
name: 'Classic Wood',
price: 75,
style: 'classic'
}, {
color: 0x2f4f4f,
name: 'Modern Metal',
price: 125,
style: 'modern'
}, {
color: 0xffffff,
name: 'Premium White',
price: 150,
style: 'premium'
}, {
color: 0x000000,
name: 'Luxury Black',
price: 200,
style: 'luxury'
}, {
color: 0xffd700,
name: 'Gold Edition',
price: 350,
style: 'gold'
}, {
color: 0xc0c0c0,
name: 'Silver Style',
price: 250,
style: 'silver'
}];
for (var i = 0; i < shelfStyles.length; i++) {
var styleOption = self.addChild(LK.getAsset('colorOption', {
anchorX: 0.5,
anchorY: 0.5
}));
styleOption.tint = shelfStyles[i].color;
styleOption.x = (i - 2.5) * 130;
styleOption.y = 0;
styleOption.scaleX = 1.2;
styleOption.scaleY = 1.2;
styleOption.colorValue = shelfStyles[i].color;
styleOption.stylePrice = shelfStyles[i].price;
styleOption.styleName = shelfStyles[i].name;
styleOption.optionType = 'shelf';
// Add price text to style option
var priceText = new Text2('$' + shelfStyles[i].price, {
size: 30,
fill: 0xffffff
});
priceText.anchor.set(0.5, 0.5);
priceText.y = 60;
styleOption.addChild(priceText);
// Add style name text
var nameText = new Text2(shelfStyles[i].name, {
size: 28,
fill: 0xffffff
});
nameText.anchor.set(0.5, 0.5);
nameText.y = -60;
styleOption.addChild(nameText);
styleOption.down = function (x, y, obj) {
if (money >= obj.stylePrice) {
money -= obj.stylePrice;
shelves.forEach(function (shelf) {
shelf.children[0].tint = obj.colorValue;
// Add special effects for premium styles
if (obj.styleName === 'Gold Edition') {
shelf.children[0].alpha = 0.9;
// Add golden glow effect
tween(shelf.children[0], {
alpha: 1.0
}, {
duration: 1000,
yoyo: true,
repeat: -1
});
} else if (obj.styleName === 'Luxury Black') {
shelf.children[0].alpha = 0.95;
}
});
updateUI();
LK.getSound('purchase').play();
LK.effects.flashObject(obj, 0x00ff00, 300);
} else {
LK.effects.flashObject(obj, 0xff0000, 300);
}
};
}
// Lighting section
var lightingLabel = new Text2('Store Lighting', {
size: 50,
fill: 0xffffff
});
lightingLabel.anchor.set(0.5, 0.5);
lightingLabel.x = 0;
lightingLabel.y = 140;
self.addChild(lightingLabel);
var lightingOptions = [{
color: 0xffffff,
name: 'Bright White',
price: 100,
effect: 'bright'
}, {
color: 0xfff8dc,
name: 'Warm Light',
price: 125,
effect: 'warm'
}, {
color: 0xe6e6fa,
name: 'Cool Light',
price: 125,
effect: 'cool'
}, {
color: 0xffd700,
name: 'Luxury Gold',
price: 250,
effect: 'luxury'
}];
for (var i = 0; i < lightingOptions.length; i++) {
var lightOption = self.addChild(LK.getAsset('colorOption', {
anchorX: 0.5,
anchorY: 0.5
}));
lightOption.tint = lightingOptions[i].color;
lightOption.x = (i - 1.5) * 160;
lightOption.y = 220;
lightOption.scaleX = 1.2;
lightOption.scaleY = 1.2;
lightOption.colorValue = lightingOptions[i].color;
lightOption.lightPrice = lightingOptions[i].price;
lightOption.lightName = lightingOptions[i].name;
lightOption.optionType = 'lighting';
// Add price text
var priceText = new Text2('$' + lightingOptions[i].price, {
size: 30,
fill: 0x000000
});
priceText.anchor.set(0.5, 0.5);
priceText.y = 60;
lightOption.addChild(priceText);
// Add lighting name
var nameText = new Text2(lightingOptions[i].name, {
size: 28,
fill: 0x000000
});
nameText.anchor.set(0.5, 0.5);
nameText.y = -60;
lightOption.addChild(nameText);
lightOption.down = function (x, y, obj) {
if (money >= obj.lightPrice) {
money -= obj.lightPrice;
// Apply lighting effect to entire game background
game.setBackgroundColor(obj.colorValue);
// Add lighting effects to shelves and other elements
shelves.forEach(function (shelf) {
if (obj.lightName === 'Luxury Gold') {
// Add golden shimmer to shelves
tween(shelf, {
alpha: 0.9
}, {
duration: 2000,
yoyo: true,
repeat: -1
});
}
});
updateUI();
LK.getSound('purchase').play();
LK.effects.flashObject(obj, 0x00ff00, 300);
} else {
LK.effects.flashObject(obj, 0xff0000, 300);
}
};
}
// Close button
var closeBtn = self.addChild(LK.getAsset('closeButton', {
anchorX: 0.5,
anchorY: 0.5
}));
closeBtn.x = 0;
// Store decorations section
var decorLabel = new Text2('Store Decorations (One-time purchase)', {
size: 44,
fill: 0xffffff
});
decorLabel.anchor.set(0.5, 0.5);
decorLabel.x = 0;
decorLabel.y = 370;
self.addChild(decorLabel);
var decorations = [{
name: 'Golden Statue',
price: 500,
asset: 'decorativeItem',
color: 0xffd700
}, {
name: 'Store Plants',
price: 150,
asset: 'plantDecor',
color: 0x228b22
}, {
name: 'Neon Sign',
price: 300,
asset: 'signDecor',
color: 0x00ffff
}];
for (var i = 0; i < decorations.length; i++) {
var decorOption = self.addChild(LK.getAsset('colorOption', {
anchorX: 0.5,
anchorY: 0.5
}));
decorOption.tint = decorations[i].color;
decorOption.x = (i - 1) * 200;
decorOption.y = 450;
decorOption.scaleX = 1.2;
decorOption.scaleY = 1.2;
decorOption.decorName = decorations[i].name;
decorOption.decorPrice = decorations[i].price;
decorOption.decorAsset = decorations[i].asset;
decorOption.decorColor = decorations[i].color;
// Add price text
var priceText = new Text2('$' + decorations[i].price, {
size: 30,
fill: 0x000000
});
priceText.anchor.set(0.5, 0.5);
priceText.y = 60;
decorOption.addChild(priceText);
// Add decoration name
var nameText = new Text2(decorations[i].name, {
size: 28,
fill: 0x000000
});
nameText.anchor.set(0.5, 0.5);
nameText.y = -60;
decorOption.addChild(nameText);
decorOption.down = function (x, y, obj) {
if (money >= obj.decorPrice) {
money -= obj.decorPrice;
// Add decoration to store
var decoration = game.addChild(LK.getAsset(obj.decorAsset, {
anchorX: 0.5,
anchorY: 0.5
}));
decoration.tint = obj.decorColor;
decoration.x = 1200 + Math.random() * 400; // Random position in store
decoration.y = 600 + Math.random() * 200;
// Add decorative animation
tween(decoration, {
rotation: Math.PI * 2
}, {
duration: 5000,
repeat: -1
});
updateUI();
LK.getSound('purchase').play();
LK.effects.flashObject(obj, 0x00ff00, 300);
// Disable button after purchase
obj.alpha = 0.5;
obj.down = null;
} else {
LK.effects.flashObject(obj, 0xff0000, 300);
}
};
}
closeBtn.y = 570;
closeBtn.scaleX = 1.2;
closeBtn.scaleY = 1.2;
var closeText = new Text2('X', {
size: 50,
fill: 0xffffff
});
closeText.anchor.set(0.5, 0.5);
closeBtn.addChild(closeText);
closeBtn.down = function (x, y, obj) {
self.destroy();
customizePanel = null;
};
// Center panel on screen
self.x = 1024;
self.y = 1366;
return self;
});
var Door = Container.expand(function () {
var self = Container.call(this);
// Create door frame
var frame = self.addChild(LK.getAsset('doorFrame', {
anchorX: 0.5,
anchorY: 0.5
}));
// Create door
var door = self.addChild(LK.getAsset('entranceDoor', {
anchorX: 0.5,
anchorY: 0.5
}));
self.doorType = 'entrance'; // 'entrance' or 'exit'
self.isOpen = false;
self.openTimer = 0;
self.setDoorType = function (type) {
self.doorType = type;
if (type === 'exit') {
door.destroy();
door = self.addChild(LK.getAsset('exitDoor', {
anchorX: 0.5,
anchorY: 0.5
}));
}
};
self.openDoor = function () {
if (!self.isOpen) {
self.isOpen = true;
self.openTimer = 60; // Keep door open for 1 second
// Animate door opening
tween(door, {
scaleX: 0.3,
alpha: 0.7
}, {
duration: 300
});
}
};
self.closeDoor = function () {
if (self.isOpen) {
self.isOpen = false;
// Animate door closing
tween(door, {
scaleX: 1,
alpha: 1
}, {
duration: 300
});
}
};
self.update = function () {
if (self.isOpen) {
self.openTimer--;
if (self.openTimer <= 0) {
self.closeDoor();
}
}
// Check for nearby customers to open door
var nearbyCustomer = false;
customers.forEach(function (customer) {
var distance = Math.sqrt(Math.pow(customer.x - self.x, 2) + Math.pow(customer.y - self.y, 2));
if (distance < 100) {
nearbyCustomer = true;
}
});
if (nearbyCustomer && !self.isOpen) {
self.openDoor();
}
};
return self;
});
var Mascot = Container.expand(function () {
var self = Container.call(this);
// Create mascot body
var mascotBody = self.attachAsset('mascot', {
anchorX: 0.5,
anchorY: 0.5
});
// Mascot animation
self.animationTimer = 0;
self.update = function () {
self.animationTimer += 0.1;
// Bouncing animation
mascotBody.y = Math.sin(self.animationTimer) * 10;
mascotBody.rotation = Math.sin(self.animationTimer * 0.5) * 0.2;
};
return self;
});
var MoneyEffect = Container.expand(function () {
var self = Container.call(this);
var moneyIcon = self.attachAsset('money', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocity = {
x: (Math.random() - 0.5) * 4,
y: -2 - Math.random() * 2
};
self.lifetime = 120; // 2 seconds at 60fps
self.age = 0;
self.update = function () {
self.age++;
// Move upward and slightly sideways
self.x += self.velocity.x;
self.y += self.velocity.y;
// Fade out over time
self.alpha = 1 - self.age / self.lifetime;
// Scale effect
var scale = 1 + self.age / self.lifetime * 0.5;
self.scaleX = scale;
self.scaleY = scale;
// Remove when lifetime expires
if (self.age >= self.lifetime) {
self.destroy();
var index = moneyEffects.indexOf(self);
if (index > -1) {
moneyEffects.splice(index, 1);
}
}
};
return self;
});
var Security = Container.expand(function () {
var self = Container.call(this);
// Create security guard body
var body = self.addChild(LK.getAsset('securityGuard', {
anchorX: 0.5,
anchorY: 0.5
}));
// Create security guard head
var head = self.addChild(LK.getAsset('securityHead', {
anchorX: 0.5,
anchorY: 0.5
}));
head.y = -35;
// Create security guard arms
var leftArm = self.addChild(LK.getAsset('securityArm', {
anchorX: 0.5,
anchorY: 0
}));
leftArm.x = -18;
leftArm.y = -15;
var rightArm = self.addChild(LK.getAsset('securityArm', {
anchorX: 0.5,
anchorY: 0
}));
rightArm.x = 18;
rightArm.y = -15;
// Create security guard legs
var leftLeg = self.addChild(LK.getAsset('securityLeg', {
anchorX: 0.5,
anchorY: 0
}));
leftLeg.x = -8;
leftLeg.y = 15;
var rightLeg = self.addChild(LK.getAsset('securityLeg', {
anchorX: 0.5,
anchorY: 0
}));
rightLeg.x = 8;
rightLeg.y = 15;
// Store body parts for animation
self.bodyParts = {
head: head,
body: body,
leftArm: leftArm,
rightArm: rightArm,
leftLeg: leftLeg,
rightLeg: rightLeg
};
self.isActive = true;
self.animationTimer = 0;
// Security guard patrol animation
self.update = function () {
self.animationTimer += 0.1;
// Subtle walking animation while patrolling
if (self.isActive) {
self.bodyParts.leftArm.rotation = Math.sin(self.animationTimer) * 0.2;
self.bodyParts.rightArm.rotation = Math.sin(self.animationTimer + Math.PI) * 0.2;
self.bodyParts.head.rotation = Math.sin(self.animationTimer * 0.5) * 0.1;
self.bodyParts.body.y = Math.sin(self.animationTimer * 2) * 1;
}
// Check for customers trying to leave without paying
customers.forEach(function (customer) {
if (customer.state === 'leaving' && customer.shoppingCart.length > 0) {
var distance = Math.sqrt(Math.pow(customer.x - self.x, 2) + Math.pow(customer.y - self.y, 2));
if (distance < 100) {
// Stop the customer
customer.state = 'checkout';
customer.targetShelf = null;
// Security guard alert animation
tween(self.bodyParts.rightArm, {
rotation: -0.8
}, {
duration: 200,
onComplete: function onComplete() {
tween(self.bodyParts.rightArm, {
rotation: 0
}, {
duration: 200
});
}
});
// Flash red to indicate security alert
LK.effects.flashObject(self, 0xff0000, 500);
}
}
});
};
return self;
});
var Shelf = Container.expand(function () {
var self = Container.call(this);
var shelfGraphics = self.attachAsset('shelf', {
anchorX: 0.5,
anchorY: 0.5
});
self.products = [];
self.maxProducts = 5;
self.productType = 'basic';
self.price = 10;
self.addProduct = function () {
if (self.products.length < self.maxProducts) {
var product = self.addChild(LK.getAsset('product', {
anchorX: 0.5,
anchorY: 0.5
}));
product.x = (self.products.length - 2) * 20;
product.y = -25;
self.products.push(product);
}
};
self.sellProduct = function () {
if (self.products.length > 0) {
var product = self.products.pop();
product.destroy();
return self.price;
}
return 0;
};
self.down = function (x, y, obj) {
// Shelves no longer sell products when clicked
// Products can only be sold through customer interactions
};
return self;
});
var StoreManager = Container.expand(function () {
var self = Container.call(this);
self.customerSpawnTimer = 0;
self.customerSpawnRate = 120; // spawn every 2 seconds at 60fps
self.spawnCustomer = function () {
if (customers.length < 8) {
var customer = new Customer();
customer.x = 250; // Near entrance door
customer.y = 600 + (Math.random() - 0.5) * 100;
customers.push(customer);
game.addChild(customer);
}
};
self.update = function () {
self.customerSpawnTimer++;
// Check if store has products available
var hasProducts = shelves.some(function (shelf) {
return shelf.products.length > 0;
});
// Adjust spawn rate based on product availability
var currentSpawnRate = self.customerSpawnRate;
if (!hasProducts) {
// Much fewer customers when no products (5x slower spawn rate)
currentSpawnRate = self.customerSpawnRate * 5;
}
// Apply advertisement board bonus - 4% more customers per board
var adBoardMultiplier = 1 + advertisementBoards.length * 0.04;
currentSpawnRate = currentSpawnRate / adBoardMultiplier;
if (self.customerSpawnTimer >= currentSpawnRate) {
self.customerSpawnTimer = 0;
self.spawnCustomer();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game variables
var money = 45;
var level = 1;
var shelves = [];
var customers = [];
var cashiers = [];
var moneyEffects = [];
var storeSize = storage.storeSize || 1;
var emptyShelfPenaltyTimer = 0;
var warningText = null;
var taxTimer = 0;
var taxInterval = 72000; // 20 minutes at 60fps (20 * 60 * 60)
var mascot = null;
var mascotButton = null;
var mascotMoneyMultiplier = 1.5; // 1.5x money when mascot is active
var customizePanel = null;
var securityGuard = null;
var adBoardCounter = 0;
var adTexts = ['BAM MARKET\nBest Deals!', 'FRESH PRODUCTS\nDaily!', 'SAVE MORE\nSpend Less!', 'QUALITY ITEMS\nLow Prices!', 'NEW ARRIVALS\nEvery Week!', 'PREMIUM GOODS\nAffordable!', 'SHOP SMART\nSave Big!', 'EXCLUSIVE\nOffers Here!'];
var advertisementBoards = [];
// Helper function to find nearest cashier
function findNearestCashier() {
if (cashiers.length === 0) return null;
var nearestCashier = cashiers[0];
var minDistance = Infinity;
cashiers.forEach(function (cashier) {
var distance = Math.sqrt(Math.pow(cashier.x, 2) + Math.pow(cashier.y, 2));
if (distance < minDistance && !cashier.isProcessing) {
minDistance = distance;
nearestCashier = cashier;
}
});
return nearestCashier;
}
// Helper function to check if all shelves are empty
function areAllShelvesEmpty() {
return shelves.every(function (shelf) {
return shelf.products.length === 0;
});
}
// Function to show warning message
function showWarningMessage() {
if (warningText) {
warningText.destroy();
}
warningText = new Text2('Please buy products!', {
size: 80,
fill: 0xff0000
});
warningText.anchor.set(0.5, 0.5);
warningText.x = 1024;
warningText.y = 1366;
game.addChild(warningText);
// Flash the warning text
LK.effects.flashObject(warningText, 0xffff00, 1000);
}
// Function to show penalty message
function showPenaltyMessage() {
if (warningText) {
warningText.destroy();
}
warningText = new Text2('Buy products -$2', {
size: 80,
fill: 0xff0000
});
warningText.anchor.set(0.5, 0.5);
warningText.x = 1024;
warningText.y = 1366;
game.addChild(warningText);
// Flash the penalty text
LK.effects.flashObject(warningText, 0xffff00, 1000);
// Create penalty indicator next to money display
var penaltyIndicator = new Text2('-$2', {
size: 60,
fill: 0xff0000
});
penaltyIndicator.anchor.set(0, 0);
penaltyIndicator.x = moneyText.x + 100;
penaltyIndicator.y = moneyText.y;
LK.gui.top.addChild(penaltyIndicator);
// Animate penalty indicator
tween(penaltyIndicator, {
y: penaltyIndicator.y - 30,
alpha: 0
}, {
duration: 2000,
onComplete: function onComplete() {
penaltyIndicator.destroy();
}
});
}
// Function to hide warning message
function hideWarningMessage() {
if (warningText) {
warningText.destroy();
warningText = null;
}
}
// Function to collect tax
function collectTax() {
// Show tax warning message
if (warningText) {
warningText.destroy();
}
warningText = new Text2('Tax Time! -$110', {
size: 80,
fill: 0xff0000
});
warningText.anchor.set(0.5, 0.5);
warningText.x = 1024;
warningText.y = 1366;
game.addChild(warningText);
// Flash the tax warning
LK.effects.flashObject(warningText, 0xffff00, 2000);
// Deduct tax amount
money -= 110;
updateUI();
// Flash screen red for tax collection
LK.effects.flashScreen(0xff0000, 1000);
// Create tax penalty indicator
var taxIndicator = new Text2('-$110 TAX', {
size: 60,
fill: 0xff0000
});
taxIndicator.anchor.set(0, 0);
taxIndicator.x = moneyText.x + 100;
taxIndicator.y = moneyText.y;
LK.gui.top.addChild(taxIndicator);
// Animate tax indicator
tween(taxIndicator, {
y: taxIndicator.y - 50,
alpha: 0
}, {
duration: 3000,
onComplete: function onComplete() {
taxIndicator.destroy();
}
});
}
// Function to create money effect at position
function createMoneyEffect(x, y, amount) {
// Create multiple money icons based on amount
var numEffects = Math.min(Math.floor(amount / 10) + 1, 5);
for (var i = 0; i < numEffects; i++) {
var effect = new MoneyEffect();
effect.x = x + (Math.random() - 0.5) * 40;
effect.y = y + (Math.random() - 0.5) * 20;
// Add slight delay between effects
var delay = i * 100;
if (delay > 0) {
effect.alpha = 0;
tween(effect, {
alpha: 1
}, {
duration: 200,
delay: delay
});
}
moneyEffects.push(effect);
game.addChild(effect);
}
}
// UI Elements
var gameTitle = new Text2('BAM Market', {
size: 80,
fill: 0x000000
});
gameTitle.anchor.set(0.5, 0);
gameTitle.x = 0;
gameTitle.y = 20;
LK.gui.top.addChild(gameTitle);
var moneyText = new Text2('$' + money, {
size: 60,
fill: 0x000000
});
moneyText.anchor.set(0.5, 0);
moneyText.y = 120;
LK.gui.top.addChild(moneyText);
var levelText = new Text2('Level ' + level, {
size: 40,
fill: 0x000000
});
levelText.anchor.set(0, 0);
levelText.x = 50;
levelText.y = 50;
LK.gui.topLeft.addChild(levelText);
// Store floor
var storeFloor = game.addChild(LK.getAsset('storeFloor', {
anchorX: 0.5,
anchorY: 0.5
}));
storeFloor.x = 1024;
storeFloor.y = 866;
// Initial shelves
function createShelf(x, y) {
var shelf = new Shelf();
shelf.x = x;
shelf.y = y;
// Set price based on current level
shelf.price = Math.floor(10 * Math.pow(1.5, level - 1));
// Stock with initial products
for (var i = 0; i < 3; i++) {
shelf.addProduct();
}
shelves.push(shelf);
game.addChild(shelf);
return shelf;
}
// Create entrance and exit doors
var entranceDoor = new Door();
entranceDoor.x = 200; // Far left edge of store
entranceDoor.y = 600; // Middle height
entranceDoor.setDoorType('entrance');
game.addChild(entranceDoor);
var exitDoor = new Door();
exitDoor.x = 1800; // Far right edge of store
exitDoor.y = 600; // Middle height
exitDoor.setDoorType('exit');
game.addChild(exitDoor);
// Create security guard at exit door
securityGuard = new Security();
securityGuard.x = 1750; // Position right next to exit door
securityGuard.y = 600; // Same height as exit door
game.addChild(securityGuard);
// Add "SECURITY" text above the security guard
var securityText = new Text2('SECURITY', {
size: 24,
fill: 0x000000
});
securityText.anchor.set(0.5, 0.5);
securityText.x = securityGuard.x;
securityText.y = securityGuard.y - 80;
game.addChild(securityText);
// Create and position advertisement board
var adBoard = new Advertisement(adBoardCounter);
// Position in organized grid pattern
var boardsPerRow = 4;
var gridSpacingX = 250;
var gridSpacingY = 200;
var startX = 1200;
var startY = 250;
var row = Math.floor(adBoardCounter / boardsPerRow);
var col = adBoardCounter % boardsPerRow;
adBoard.x = startX + col * gridSpacingX;
adBoard.y = startY + row * gridSpacingY;
game.addChild(adBoard);
advertisementBoards.push(adBoard);
adBoardCounter++;
// Create initial store layout
createShelf(600, 500);
createShelf(800, 500);
createShelf(1000, 500);
createShelf(600, 700);
createShelf(800, 700);
// Create initial cashiers - positioned at front of store for easy customer access
for (var i = 0; i < 1; i++) {
var cashier = new Cashier();
cashier.x = 600 + i * 200; // Space cashiers 200 pixels apart
cashier.y = 400; // Front of store for easy access
cashiers.push(cashier);
game.addChild(cashier);
}
// Expand store button
var expandButton = game.addChild(LK.getAsset('expandButton', {
anchorX: 0.5,
anchorY: 0.5
}));
expandButton.x = 1024;
expandButton.y = 1700;
expandButton.scaleX = 1.3;
expandButton.scaleY = 1.3;
var expandText = new Text2('Expand\n$150', {
size: 30,
fill: 0xFFFFFF
});
expandText.anchor.set(0.5, 0.5);
expandButton.addChild(expandText);
expandButton.down = function (x, y, obj) {
var expandCost = Math.floor(150 * Math.pow(1.5, level - 1));
if (shelves.length >= 15) {
// Maximum 15 shelves reached (5 initial + 10 additional = 15 total, but we want max 5 additional)
LK.effects.flashObject(expandButton, 0xFF0000, 500);
return;
}
if (money >= expandCost) {
money -= expandCost;
storeSize++;
// Find the rightmost shelf position
var rightmostX = 0;
shelves.forEach(function (shelf) {
if (shelf.x > rightmostX) {
rightmostX = shelf.x;
}
});
// Check if we can fit horizontally (within store bounds)
var newShelfX = rightmostX + 200; // 200 pixels spacing between shelves
var maxStoreWidth = 1800; // Store width limit
if (newShelfX <= maxStoreWidth) {
// Add new shelves next to existing ones horizontally
createShelf(newShelfX, 500);
createShelf(newShelfX, 700);
} else {
// Find bottom-most shelf position to stack vertically
var bottommostY = 0;
shelves.forEach(function (shelf) {
if (shelf.y > bottommostY) {
bottommostY = shelf.y;
}
});
// Add new shelves below existing ones
var newShelfY = bottommostY + 200; // 200 pixels spacing between shelf rows
createShelf(600, newShelfY); // Start new row at initial X position
createShelf(800, newShelfY);
}
// Hide button if maximum reached
if (shelves.length >= 15) {
expandButton.visible = false;
}
// Level up when expanding store (buying shelves)
level++;
levelText.setText('Level ' + level);
LK.effects.flashScreen(0x00FF00, 1000);
updateUI();
LK.getSound('expand').play();
LK.effects.flashObject(expandButton, 0x00FF00, 500);
} else {
LK.effects.flashObject(expandButton, 0xFF0000, 500);
}
};
// Restock button
var stockButton = game.addChild(LK.getAsset('stockButton', {
anchorX: 0.5,
anchorY: 0.5
}));
stockButton.x = 1024;
stockButton.y = 1820;
stockButton.scaleX = 1.3;
stockButton.scaleY = 1.3;
var stockText = new Text2('Restock\n$50', {
size: 30,
fill: 0xFFFFFF
});
stockText.anchor.set(0.5, 0.5);
stockButton.addChild(stockText);
stockButton.down = function (x, y, obj) {
var stockCost = Math.floor(50 * Math.pow(1.5, level - 1));
if (money >= stockCost) {
money -= stockCost;
// Restock all shelves
shelves.forEach(function (shelf) {
while (shelf.products.length < shelf.maxProducts) {
shelf.addProduct();
}
});
updateUI();
LK.getSound('purchase').play();
LK.effects.flashObject(stockButton, 0x00FF00, 500);
} else {
LK.effects.flashObject(stockButton, 0xFF0000, 500);
}
};
// Hire cashier button
var hireCashierButton = game.addChild(LK.getAsset('hireCashierButton', {
anchorX: 0.5,
anchorY: 0.5
}));
hireCashierButton.x = 1024;
hireCashierButton.y = 1940;
hireCashierButton.scaleX = 1.3;
hireCashierButton.scaleY = 1.3;
var hireCashierText = new Text2('Hire\nCashier\n$175', {
size: 26,
fill: 0xFFFFFF
});
hireCashierText.anchor.set(0.5, 0.5);
hireCashierButton.addChild(hireCashierText);
hireCashierButton.down = function (x, y, obj) {
var hireCost = Math.floor(175 * Math.pow(1.5, level - 1));
if (cashiers.length >= 4) {
// Maximum 4 cashiers reached
LK.effects.flashObject(hireCashierButton, 0xFF0000, 500);
return;
}
if (money >= hireCost) {
money -= hireCost;
// Create new cashier
var newCashier = new Cashier();
// Position new cashier next to existing cashiers
var cashierX = 600 + cashiers.length * 200;
var cashierY = 400;
var maxStoreWidth = 1800; // Store width limit
// If cashier would go beyond store width, stack vertically
if (cashierX > maxStoreWidth) {
// Find how many cashiers fit horizontally
var cashiersPerRow = Math.floor((maxStoreWidth - 600) / 200) + 1;
var row = Math.floor(cashiers.length / cashiersPerRow);
var col = cashiers.length % cashiersPerRow;
cashierX = 600 + col * 200;
cashierY = 400 + row * 150; // Stack with 150 pixel spacing vertically
}
newCashier.x = cashierX;
newCashier.y = cashierY;
cashiers.push(newCashier);
game.addChild(newCashier);
// Hide button if maximum reached
if (cashiers.length >= 4) {
hireCashierButton.visible = false;
}
// Level up when hiring cashier
level++;
levelText.setText('Level ' + level);
LK.effects.flashScreen(0x00FF00, 1000);
updateUI();
LK.getSound('cashRegister').play();
LK.effects.flashObject(hireCashierButton, 0x00FF00, 500);
} else {
LK.effects.flashObject(hireCashierButton, 0xFF0000, 500);
}
};
// Create mascot button (initially hidden)
mascotButton = game.addChild(LK.getAsset('mascotButton', {
anchorX: 0.5,
anchorY: 0.5
}));
mascotButton.x = 1024;
mascotButton.y = 2060;
mascotButton.scaleX = 1.3;
mascotButton.scaleY = 1.3;
mascotButton.visible = false; // Hide initially
var mascotButtonText = new Text2('Buy\nMascot\n$670', {
size: 26,
fill: 0xFFFFFF
});
mascotButtonText.anchor.set(0.5, 0.5);
mascotButton.addChild(mascotButtonText);
mascotButton.down = function (x, y, obj) {
var mascotCost = 670;
if (money >= mascotCost && level >= 10 && !mascot) {
money -= mascotCost;
// Create mascot
mascot = new Mascot();
mascot.x = 400; // Position near entrance
mascot.y = 500;
game.addChild(mascot);
// Hide mascot button after purchase
mascotButton.visible = false;
// Double customer spawn rate (2x more customers)
storeManager.customerSpawnRate = Math.max(30, storeManager.customerSpawnRate * 0.5);
updateUI();
LK.getSound('purchase').play();
LK.effects.flashObject(mascotButton, 0x00FF00, 500);
LK.effects.flashScreen(0x00FF00, 1000);
} else {
LK.effects.flashObject(mascotButton, 0xFF0000, 500);
}
};
// Add advertisement board button
var adBoardButton = game.addChild(LK.getAsset('stockButton', {
anchorX: 0.5,
anchorY: 0.5
}));
adBoardButton.x = 1024;
adBoardButton.y = 2180;
adBoardButton.scaleX = 1.3;
adBoardButton.scaleY = 1.3;
var adBoardText = new Text2('Add\nAd Board\n$75', {
size: 26,
fill: 0xFFFFFF
});
adBoardText.anchor.set(0.5, 0.5);
adBoardButton.addChild(adBoardText);
adBoardButton.down = function (x, y, obj) {
var adBoardCost = 75;
if (advertisementBoards.length >= 3) {
// Maximum 3 advertisement boards reached
LK.effects.flashObject(adBoardButton, 0xFF0000, 500);
return;
}
if (money >= adBoardCost) {
money -= adBoardCost;
// Create new advertisement board with unique text
var newAdBoard = new Advertisement(adBoardCounter);
// Position in organized grid pattern
var boardsPerRow = 4;
var gridSpacingX = 250;
var gridSpacingY = 200;
var startX = 1200;
var startY = 250;
var row = Math.floor(adBoardCounter / boardsPerRow);
var col = adBoardCounter % boardsPerRow;
newAdBoard.x = startX + col * gridSpacingX;
newAdBoard.y = startY + row * gridSpacingY;
game.addChild(newAdBoard);
advertisementBoards.push(newAdBoard);
adBoardCounter++;
// Hide button if maximum reached
if (advertisementBoards.length >= 3) {
adBoardButton.visible = false;
}
updateUI();
LK.getSound('purchase').play();
LK.effects.flashObject(adBoardButton, 0x00FF00, 500);
} else {
LK.effects.flashObject(adBoardButton, 0xFF0000, 500);
}
};
// Customize store button
var customizeButton = game.addChild(LK.getAsset('customizeButton', {
anchorX: 0.5,
anchorY: 0.5
}));
customizeButton.x = 1024;
customizeButton.y = 2300;
customizeButton.scaleX = 1.3;
customizeButton.scaleY = 1.3;
var customizeText = new Text2('Customize\nStore', {
size: 30,
fill: 0xFFFFFF
});
customizeText.anchor.set(0.5, 0.5);
customizeButton.addChild(customizeText);
customizeButton.down = function (x, y, obj) {
if (!customizePanel) {
customizePanel = new CustomizePanel();
game.addChild(customizePanel);
LK.getSound('purchase').play();
}
};
// Store manager
var storeManager = new StoreManager();
game.addChild(storeManager);
function updateUI() {
moneyText.setText('$' + money);
// Level up system
if (money >= level * 1000) {
level++;
levelText.setText('Level ' + level);
LK.effects.flashScreen(0x00FF00, 1000);
}
// Show mascot button at level 10
if (level >= 10 && !mascot && mascotButton) {
mascotButton.visible = true;
}
// Save progress
storage.money = money;
storage.level = level;
storage.storeSize = storeSize;
}
// Game loop
game.update = function () {
// Update customers
for (var i = customers.length - 1; i >= 0; i--) {
var customer = customers[i];
if (customer.update) {
customer.update();
}
}
// Update cashiers
for (var i = 0; i < cashiers.length; i++) {
var cashier = cashiers[i];
if (cashier.update) {
cashier.update();
}
}
// Update store manager
if (storeManager.update) {
storeManager.update();
}
// Update doors
if (entranceDoor.update) {
entranceDoor.update();
}
if (exitDoor.update) {
exitDoor.update();
}
// Update money effects
for (var i = moneyEffects.length - 1; i >= 0; i--) {
var effect = moneyEffects[i];
if (effect.update) {
effect.update();
}
}
// Update mascot
if (mascot && mascot.update) {
mascot.update();
}
// Update security guard
if (securityGuard && securityGuard.update) {
securityGuard.update();
}
// Update advertisement board
if (adBoard && adBoard.update) {
adBoard.update();
}
// Check for empty shelves penalty
if (areAllShelvesEmpty()) {
emptyShelfPenaltyTimer++;
// Show warning message
showWarningMessage();
// Apply penalty every 10 seconds (600 ticks at 60fps)
if (emptyShelfPenaltyTimer >= 600) {
money -= 2;
emptyShelfPenaltyTimer = 0;
updateUI();
// Show penalty message
showPenaltyMessage();
// Flash screen red for penalty
LK.effects.flashScreen(0xff0000, 500);
}
} else {
emptyShelfPenaltyTimer = 0;
hideWarningMessage();
}
// Check win condition
if (money >= 10000) {
LK.showYouWin();
}
// Tax collection every 20 minutes
taxTimer++;
if (taxTimer >= taxInterval) {
collectTax();
taxTimer = 0; // Reset timer
}
// Check lose condition (bankruptcy)
if (money < 0 && shelves.every(function (shelf) {
return shelf.products.length === 0;
})) {
LK.showGameOver();
}
};
// Handle pause menu with reset option
LK.on('pauseMenuShow', function () {
// Add reset button to pause menu
var resetButton = LK.gui.center.addChild(LK.getAsset('stockButton', {
anchorX: 0.5,
anchorY: 0.5
}));
resetButton.x = 0;
resetButton.y = 100;
resetButton.scaleX = 1.5;
resetButton.scaleY = 1.5;
var resetText = new Text2('Reset Game', {
size: 32,
fill: 0xFFFFFF
});
resetText.anchor.set(0.5, 0.5);
resetButton.addChild(resetText);
resetButton.down = function () {
// Clear storage
storage.money = undefined;
storage.level = undefined;
storage.storeSize = undefined;
// Reset game by showing game over (which resets the game)
LK.showGameOver();
};
// Store reference to clean up later
resetButton.pauseMenuButton = true;
});
LK.on('pauseMenuHide', function () {
// Clean up reset button when pause menu is hidden
var children = LK.gui.center.children.slice();
for (var i = 0; i < children.length; i++) {
if (children[i].pauseMenuButton) {
children[i].destroy();
}
}
});
// Initialize UI
updateUI(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Advertisement = Container.expand(function (textIndex) {
var self = Container.call(this);
// Create advertisement frame
var frame = self.addChild(LK.getAsset('adFrame', {
anchorX: 0.5,
anchorY: 0.5
}));
// Create advertisement board
var board = self.addChild(LK.getAsset('adBoard', {
anchorX: 0.5,
anchorY: 0.5
}));
// Add advertisement text with different content based on index
var adTextContent = adTexts[textIndex % adTexts.length];
var adText = new Text2(adTextContent, {
size: 28,
fill: 0xffffff
});
adText.anchor.set(0.5, 0.5);
board.addChild(adText);
// Add flashing effect to make it more eye-catching
self.animationTimer = 0;
self.update = function () {
self.animationTimer += 0.05;
// Subtle pulsing effect
var scale = 1 + Math.sin(self.animationTimer) * 0.05;
board.scaleX = scale;
board.scaleY = scale;
// Subtle color shift effect
var colorShift = Math.sin(self.animationTimer * 0.3) * 0.1;
board.alpha = 0.9 + colorShift;
};
return self;
});
var Cashier = Container.expand(function () {
var self = Container.call(this);
// Create cashier counter
var counter = self.addChild(LK.getAsset('cashierCounter', {
anchorX: 0.5,
anchorY: 0.5
}));
// Create human-like cashier
var head = self.addChild(LK.getAsset('cashierHead', {
anchorX: 0.5,
anchorY: 0.5
}));
head.y = -35;
var body = self.addChild(LK.getAsset('cashierBody', {
anchorX: 0.5,
anchorY: 0.5
}));
body.y = -15;
var leftArm = self.addChild(LK.getAsset('cashierArm', {
anchorX: 0.5,
anchorY: 0
}));
leftArm.x = -12;
leftArm.y = -22;
var rightArm = self.addChild(LK.getAsset('cashierArm', {
anchorX: 0.5,
anchorY: 0
}));
rightArm.x = 12;
rightArm.y = -22;
self.bodyParts = {
head: head,
body: body,
leftArm: leftArm,
rightArm: rightArm
};
self.isProcessing = false;
self.processingTimer = 0;
self.processCustomer = function (customer) {
if (!self.isProcessing) {
self.isProcessing = true;
self.processingTimer = 60; // 1 second processing time
// Animate cashier working
tween(self.bodyParts.rightArm, {
rotation: -0.5
}, {
duration: 300,
onComplete: function onComplete() {
tween(self.bodyParts.rightArm, {
rotation: 0
}, {
duration: 300
});
}
});
}
};
self.update = function () {
if (self.isProcessing) {
self.processingTimer--;
if (self.processingTimer <= 0) {
self.isProcessing = false;
}
// Slight head bob while processing
self.bodyParts.head.y = -35 + Math.sin(LK.ticks * 0.3) * 1;
} else {
self.bodyParts.head.y = -35;
}
};
return self;
});
var Customer = Container.expand(function () {
var self = Container.call(this);
// Create human-like customer with body parts
var head = self.addChild(LK.getAsset('customerHead', {
anchorX: 0.5,
anchorY: 0.5
}));
head.y = -20;
var body = self.addChild(LK.getAsset('customerBody', {
anchorX: 0.5,
anchorY: 0.5
}));
body.y = 0;
var leftArm = self.addChild(LK.getAsset('customerArm', {
anchorX: 0.5,
anchorY: 0
}));
leftArm.x = -15;
leftArm.y = -8;
var rightArm = self.addChild(LK.getAsset('customerArm', {
anchorX: 0.5,
anchorY: 0
}));
rightArm.x = 15;
rightArm.y = -8;
var leftLeg = self.addChild(LK.getAsset('customerLeg', {
anchorX: 0.5,
anchorY: 0
}));
leftLeg.x = -8;
leftLeg.y = 16;
var rightLeg = self.addChild(LK.getAsset('customerLeg', {
anchorX: 0.5,
anchorY: 0
}));
rightLeg.x = 8;
rightLeg.y = 16;
// Store body parts for animation
self.bodyParts = {
head: head,
body: body,
leftArm: leftArm,
rightArm: rightArm,
leftLeg: leftLeg,
rightLeg: rightLeg
};
self.speed = 1 + Math.random() * 2;
self.targetShelf = null;
self.state = 'browsing'; // browsing, shopping, checkout, leaving
self.patience = 300 + Math.random() * 200;
self.maxPatience = self.patience;
self.walkCycle = 0;
self.shoppingCart = [];
self.hasComplained = false;
self.complain = function () {
// Visual complaint effect - flash red
LK.effects.flashObject(self, 0xff0000, 800);
// Create complaint text above customer
var complaintText = new Text2('No products!', {
size: 20,
fill: 0xff0000
});
complaintText.anchor.set(0.5, 1);
complaintText.x = self.x;
complaintText.y = self.y - 40;
game.addChild(complaintText);
// Animate complaint text
tween(complaintText, {
y: complaintText.y - 30,
alpha: 0
}, {
duration: 1500,
onComplete: function onComplete() {
complaintText.destroy();
}
});
// Reduce customer patience significantly
self.patience = Math.min(self.patience, 30);
};
self.findNearestShelf = function () {
var nearestShelf = null;
var minDistance = Infinity;
var hasProductsAvailable = false;
shelves.forEach(function (shelf) {
if (shelf.products.length > 0) {
hasProductsAvailable = true;
var distance = Math.sqrt(Math.pow(self.x - shelf.x, 2) + Math.pow(self.y - shelf.y, 2));
if (distance < minDistance) {
minDistance = distance;
nearestShelf = shelf;
}
}
});
// If no products available, customer complains
if (!hasProductsAvailable && !self.hasComplained) {
self.hasComplained = true;
self.complain();
}
return nearestShelf;
};
self.update = function () {
self.patience--;
if (self.patience <= 0) {
self.state = 'leaving';
}
// Walking animation
self.walkCycle += 0.2;
if (self.state === 'browsing' || self.state === 'checkout') {
self.bodyParts.leftLeg.rotation = Math.sin(self.walkCycle) * 0.3;
self.bodyParts.rightLeg.rotation = Math.sin(self.walkCycle + Math.PI) * 0.3;
self.bodyParts.leftArm.rotation = Math.sin(self.walkCycle + Math.PI) * 0.2;
self.bodyParts.rightArm.rotation = Math.sin(self.walkCycle) * 0.2;
self.bodyParts.body.y = Math.sin(self.walkCycle * 2) * 1;
}
if (self.state === 'browsing') {
if (!self.targetShelf) {
self.targetShelf = self.findNearestShelf();
}
if (self.targetShelf) {
var dx = self.targetShelf.x - self.x;
var dy = self.targetShelf.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 60) {
self.state = 'shopping';
self.patience = 60;
// Stop walking animation
self.bodyParts.leftLeg.rotation = 0;
self.bodyParts.rightLeg.rotation = 0;
self.bodyParts.leftArm.rotation = 0;
self.bodyParts.rightArm.rotation = 0;
} else {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else {
// No shelves with products available, customer becomes impatient
if (!self.hasComplained) {
self.hasComplained = true;
self.complain();
}
self.state = 'leaving';
}
} else if (self.state === 'shopping') {
if (self.targetShelf && self.targetShelf.products.length > 0) {
// 73% chance to make a purchase
if (Math.random() < 0.73) {
// Add item to shopping cart instead of direct purchase
self.shoppingCart.push({
item: self.targetShelf.productType,
price: self.targetShelf.price
});
self.targetShelf.sellProduct();
// Move to checkout
self.state = 'checkout';
self.targetShelf = null;
} else {
// Customer decides not to buy, leaves the store
self.state = 'leaving';
self.targetShelf = null;
}
} else {
self.state = 'browsing';
self.targetShelf = null;
}
} else if (self.state === 'checkout') {
// Move to cashier
var cashier = findNearestCashier();
if (cashier) {
var dx = cashier.x - self.x;
var dy = cashier.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 80) {
// Process purchase at cashier
var total = 0;
self.shoppingCart.forEach(function (item) {
total += item.price;
});
// Apply mascot money multiplier if mascot is active
if (mascot) {
total = Math.floor(total * mascotMoneyMultiplier);
}
money += total;
cashier.processCustomer(self);
createMoneyEffect(cashier.x, cashier.y - 50, total);
updateUI();
LK.getSound('cashRegister').play();
self.state = 'leaving';
} else {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else {
self.state = 'leaving';
}
} else if (self.state === 'leaving') {
// Move towards exit door
var dx = 1800 - self.x;
var dy = 600 - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 20) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else {
// Customer reached exit, remove them
self.destroy();
customers.splice(customers.indexOf(self), 1);
}
}
};
return self;
});
var CustomizePanel = Container.expand(function () {
var self = Container.call(this);
// Create panel background
var panelBg = self.attachAsset('customizePanel', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.4
});
// Panel title
var titleText = new Text2('BAM Market Customization', {
size: 70,
fill: 0xffffff
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 0;
titleText.y = -420;
self.addChild(titleText);
// Floor materials section
var floorMaterialLabel = new Text2('Floor Materials', {
size: 50,
fill: 0xffffff
});
floorMaterialLabel.anchor.set(0.5, 0.5);
floorMaterialLabel.x = 0;
floorMaterialLabel.y = -350;
self.addChild(floorMaterialLabel);
// Floor material options with different prices
var floorMaterials = [{
color: 0xf0f0f0,
name: 'Basic Tile',
price: 50,
pattern: 'solid'
}, {
color: 0x8b4513,
name: 'Wood Floor',
price: 100,
pattern: 'wood'
}, {
color: 0x696969,
name: 'Marble',
price: 200,
pattern: 'marble'
}, {
color: 0x228b22,
name: 'Carpet',
price: 75,
pattern: 'carpet'
}, {
color: 0x4169e1,
name: 'Premium Tile',
price: 150,
pattern: 'premium'
}, {
color: 0xff69b4,
name: 'Designer Floor',
price: 300,
pattern: 'designer'
}];
for (var i = 0; i < floorMaterials.length; i++) {
var materialOption = self.addChild(LK.getAsset('colorOption', {
anchorX: 0.5,
anchorY: 0.5
}));
materialOption.tint = floorMaterials[i].color;
materialOption.x = (i - 2.5) * 130;
materialOption.y = -250;
materialOption.scaleX = 1.2;
materialOption.scaleY = 1.2;
materialOption.colorValue = floorMaterials[i].color;
materialOption.materialPrice = floorMaterials[i].price;
materialOption.materialName = floorMaterials[i].name;
materialOption.optionType = 'floor';
// Add price text to material option
var priceText = new Text2('$' + floorMaterials[i].price, {
size: 30,
fill: 0xffffff
});
priceText.anchor.set(0.5, 0.5);
priceText.y = 60;
materialOption.addChild(priceText);
// Add material name text
var nameText = new Text2(floorMaterials[i].name, {
size: 28,
fill: 0xffffff
});
nameText.anchor.set(0.5, 0.5);
nameText.y = -60;
materialOption.addChild(nameText);
materialOption.down = function (x, y, obj) {
if (money >= obj.materialPrice) {
money -= obj.materialPrice;
storeFloor.tint = obj.colorValue;
// Add visual effect based on material type
if (obj.materialName === 'Marble') {
storeFloor.alpha = 0.9;
} else if (obj.materialName === 'Wood Floor') {
storeFloor.alpha = 0.95;
} else {
storeFloor.alpha = 1.0;
}
updateUI();
LK.getSound('purchase').play();
LK.effects.flashObject(obj, 0x00ff00, 300);
} else {
LK.effects.flashObject(obj, 0xff0000, 300);
}
};
}
// Shelf styles section
var shelfStyleLabel = new Text2('Shelf Styles', {
size: 50,
fill: 0xffffff
});
shelfStyleLabel.anchor.set(0.5, 0.5);
shelfStyleLabel.x = 0;
shelfStyleLabel.y = -80;
self.addChild(shelfStyleLabel);
var shelfStyles = [{
color: 0x8b4513,
name: 'Classic Wood',
price: 75,
style: 'classic'
}, {
color: 0x2f4f4f,
name: 'Modern Metal',
price: 125,
style: 'modern'
}, {
color: 0xffffff,
name: 'Premium White',
price: 150,
style: 'premium'
}, {
color: 0x000000,
name: 'Luxury Black',
price: 200,
style: 'luxury'
}, {
color: 0xffd700,
name: 'Gold Edition',
price: 350,
style: 'gold'
}, {
color: 0xc0c0c0,
name: 'Silver Style',
price: 250,
style: 'silver'
}];
for (var i = 0; i < shelfStyles.length; i++) {
var styleOption = self.addChild(LK.getAsset('colorOption', {
anchorX: 0.5,
anchorY: 0.5
}));
styleOption.tint = shelfStyles[i].color;
styleOption.x = (i - 2.5) * 130;
styleOption.y = 0;
styleOption.scaleX = 1.2;
styleOption.scaleY = 1.2;
styleOption.colorValue = shelfStyles[i].color;
styleOption.stylePrice = shelfStyles[i].price;
styleOption.styleName = shelfStyles[i].name;
styleOption.optionType = 'shelf';
// Add price text to style option
var priceText = new Text2('$' + shelfStyles[i].price, {
size: 30,
fill: 0xffffff
});
priceText.anchor.set(0.5, 0.5);
priceText.y = 60;
styleOption.addChild(priceText);
// Add style name text
var nameText = new Text2(shelfStyles[i].name, {
size: 28,
fill: 0xffffff
});
nameText.anchor.set(0.5, 0.5);
nameText.y = -60;
styleOption.addChild(nameText);
styleOption.down = function (x, y, obj) {
if (money >= obj.stylePrice) {
money -= obj.stylePrice;
shelves.forEach(function (shelf) {
shelf.children[0].tint = obj.colorValue;
// Add special effects for premium styles
if (obj.styleName === 'Gold Edition') {
shelf.children[0].alpha = 0.9;
// Add golden glow effect
tween(shelf.children[0], {
alpha: 1.0
}, {
duration: 1000,
yoyo: true,
repeat: -1
});
} else if (obj.styleName === 'Luxury Black') {
shelf.children[0].alpha = 0.95;
}
});
updateUI();
LK.getSound('purchase').play();
LK.effects.flashObject(obj, 0x00ff00, 300);
} else {
LK.effects.flashObject(obj, 0xff0000, 300);
}
};
}
// Lighting section
var lightingLabel = new Text2('Store Lighting', {
size: 50,
fill: 0xffffff
});
lightingLabel.anchor.set(0.5, 0.5);
lightingLabel.x = 0;
lightingLabel.y = 140;
self.addChild(lightingLabel);
var lightingOptions = [{
color: 0xffffff,
name: 'Bright White',
price: 100,
effect: 'bright'
}, {
color: 0xfff8dc,
name: 'Warm Light',
price: 125,
effect: 'warm'
}, {
color: 0xe6e6fa,
name: 'Cool Light',
price: 125,
effect: 'cool'
}, {
color: 0xffd700,
name: 'Luxury Gold',
price: 250,
effect: 'luxury'
}];
for (var i = 0; i < lightingOptions.length; i++) {
var lightOption = self.addChild(LK.getAsset('colorOption', {
anchorX: 0.5,
anchorY: 0.5
}));
lightOption.tint = lightingOptions[i].color;
lightOption.x = (i - 1.5) * 160;
lightOption.y = 220;
lightOption.scaleX = 1.2;
lightOption.scaleY = 1.2;
lightOption.colorValue = lightingOptions[i].color;
lightOption.lightPrice = lightingOptions[i].price;
lightOption.lightName = lightingOptions[i].name;
lightOption.optionType = 'lighting';
// Add price text
var priceText = new Text2('$' + lightingOptions[i].price, {
size: 30,
fill: 0x000000
});
priceText.anchor.set(0.5, 0.5);
priceText.y = 60;
lightOption.addChild(priceText);
// Add lighting name
var nameText = new Text2(lightingOptions[i].name, {
size: 28,
fill: 0x000000
});
nameText.anchor.set(0.5, 0.5);
nameText.y = -60;
lightOption.addChild(nameText);
lightOption.down = function (x, y, obj) {
if (money >= obj.lightPrice) {
money -= obj.lightPrice;
// Apply lighting effect to entire game background
game.setBackgroundColor(obj.colorValue);
// Add lighting effects to shelves and other elements
shelves.forEach(function (shelf) {
if (obj.lightName === 'Luxury Gold') {
// Add golden shimmer to shelves
tween(shelf, {
alpha: 0.9
}, {
duration: 2000,
yoyo: true,
repeat: -1
});
}
});
updateUI();
LK.getSound('purchase').play();
LK.effects.flashObject(obj, 0x00ff00, 300);
} else {
LK.effects.flashObject(obj, 0xff0000, 300);
}
};
}
// Close button
var closeBtn = self.addChild(LK.getAsset('closeButton', {
anchorX: 0.5,
anchorY: 0.5
}));
closeBtn.x = 0;
// Store decorations section
var decorLabel = new Text2('Store Decorations (One-time purchase)', {
size: 44,
fill: 0xffffff
});
decorLabel.anchor.set(0.5, 0.5);
decorLabel.x = 0;
decorLabel.y = 370;
self.addChild(decorLabel);
var decorations = [{
name: 'Golden Statue',
price: 500,
asset: 'decorativeItem',
color: 0xffd700
}, {
name: 'Store Plants',
price: 150,
asset: 'plantDecor',
color: 0x228b22
}, {
name: 'Neon Sign',
price: 300,
asset: 'signDecor',
color: 0x00ffff
}];
for (var i = 0; i < decorations.length; i++) {
var decorOption = self.addChild(LK.getAsset('colorOption', {
anchorX: 0.5,
anchorY: 0.5
}));
decorOption.tint = decorations[i].color;
decorOption.x = (i - 1) * 200;
decorOption.y = 450;
decorOption.scaleX = 1.2;
decorOption.scaleY = 1.2;
decorOption.decorName = decorations[i].name;
decorOption.decorPrice = decorations[i].price;
decorOption.decorAsset = decorations[i].asset;
decorOption.decorColor = decorations[i].color;
// Add price text
var priceText = new Text2('$' + decorations[i].price, {
size: 30,
fill: 0x000000
});
priceText.anchor.set(0.5, 0.5);
priceText.y = 60;
decorOption.addChild(priceText);
// Add decoration name
var nameText = new Text2(decorations[i].name, {
size: 28,
fill: 0x000000
});
nameText.anchor.set(0.5, 0.5);
nameText.y = -60;
decorOption.addChild(nameText);
decorOption.down = function (x, y, obj) {
if (money >= obj.decorPrice) {
money -= obj.decorPrice;
// Add decoration to store
var decoration = game.addChild(LK.getAsset(obj.decorAsset, {
anchorX: 0.5,
anchorY: 0.5
}));
decoration.tint = obj.decorColor;
decoration.x = 1200 + Math.random() * 400; // Random position in store
decoration.y = 600 + Math.random() * 200;
// Add decorative animation
tween(decoration, {
rotation: Math.PI * 2
}, {
duration: 5000,
repeat: -1
});
updateUI();
LK.getSound('purchase').play();
LK.effects.flashObject(obj, 0x00ff00, 300);
// Disable button after purchase
obj.alpha = 0.5;
obj.down = null;
} else {
LK.effects.flashObject(obj, 0xff0000, 300);
}
};
}
closeBtn.y = 570;
closeBtn.scaleX = 1.2;
closeBtn.scaleY = 1.2;
var closeText = new Text2('X', {
size: 50,
fill: 0xffffff
});
closeText.anchor.set(0.5, 0.5);
closeBtn.addChild(closeText);
closeBtn.down = function (x, y, obj) {
self.destroy();
customizePanel = null;
};
// Center panel on screen
self.x = 1024;
self.y = 1366;
return self;
});
var Door = Container.expand(function () {
var self = Container.call(this);
// Create door frame
var frame = self.addChild(LK.getAsset('doorFrame', {
anchorX: 0.5,
anchorY: 0.5
}));
// Create door
var door = self.addChild(LK.getAsset('entranceDoor', {
anchorX: 0.5,
anchorY: 0.5
}));
self.doorType = 'entrance'; // 'entrance' or 'exit'
self.isOpen = false;
self.openTimer = 0;
self.setDoorType = function (type) {
self.doorType = type;
if (type === 'exit') {
door.destroy();
door = self.addChild(LK.getAsset('exitDoor', {
anchorX: 0.5,
anchorY: 0.5
}));
}
};
self.openDoor = function () {
if (!self.isOpen) {
self.isOpen = true;
self.openTimer = 60; // Keep door open for 1 second
// Animate door opening
tween(door, {
scaleX: 0.3,
alpha: 0.7
}, {
duration: 300
});
}
};
self.closeDoor = function () {
if (self.isOpen) {
self.isOpen = false;
// Animate door closing
tween(door, {
scaleX: 1,
alpha: 1
}, {
duration: 300
});
}
};
self.update = function () {
if (self.isOpen) {
self.openTimer--;
if (self.openTimer <= 0) {
self.closeDoor();
}
}
// Check for nearby customers to open door
var nearbyCustomer = false;
customers.forEach(function (customer) {
var distance = Math.sqrt(Math.pow(customer.x - self.x, 2) + Math.pow(customer.y - self.y, 2));
if (distance < 100) {
nearbyCustomer = true;
}
});
if (nearbyCustomer && !self.isOpen) {
self.openDoor();
}
};
return self;
});
var Mascot = Container.expand(function () {
var self = Container.call(this);
// Create mascot body
var mascotBody = self.attachAsset('mascot', {
anchorX: 0.5,
anchorY: 0.5
});
// Mascot animation
self.animationTimer = 0;
self.update = function () {
self.animationTimer += 0.1;
// Bouncing animation
mascotBody.y = Math.sin(self.animationTimer) * 10;
mascotBody.rotation = Math.sin(self.animationTimer * 0.5) * 0.2;
};
return self;
});
var MoneyEffect = Container.expand(function () {
var self = Container.call(this);
var moneyIcon = self.attachAsset('money', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocity = {
x: (Math.random() - 0.5) * 4,
y: -2 - Math.random() * 2
};
self.lifetime = 120; // 2 seconds at 60fps
self.age = 0;
self.update = function () {
self.age++;
// Move upward and slightly sideways
self.x += self.velocity.x;
self.y += self.velocity.y;
// Fade out over time
self.alpha = 1 - self.age / self.lifetime;
// Scale effect
var scale = 1 + self.age / self.lifetime * 0.5;
self.scaleX = scale;
self.scaleY = scale;
// Remove when lifetime expires
if (self.age >= self.lifetime) {
self.destroy();
var index = moneyEffects.indexOf(self);
if (index > -1) {
moneyEffects.splice(index, 1);
}
}
};
return self;
});
var Security = Container.expand(function () {
var self = Container.call(this);
// Create security guard body
var body = self.addChild(LK.getAsset('securityGuard', {
anchorX: 0.5,
anchorY: 0.5
}));
// Create security guard head
var head = self.addChild(LK.getAsset('securityHead', {
anchorX: 0.5,
anchorY: 0.5
}));
head.y = -35;
// Create security guard arms
var leftArm = self.addChild(LK.getAsset('securityArm', {
anchorX: 0.5,
anchorY: 0
}));
leftArm.x = -18;
leftArm.y = -15;
var rightArm = self.addChild(LK.getAsset('securityArm', {
anchorX: 0.5,
anchorY: 0
}));
rightArm.x = 18;
rightArm.y = -15;
// Create security guard legs
var leftLeg = self.addChild(LK.getAsset('securityLeg', {
anchorX: 0.5,
anchorY: 0
}));
leftLeg.x = -8;
leftLeg.y = 15;
var rightLeg = self.addChild(LK.getAsset('securityLeg', {
anchorX: 0.5,
anchorY: 0
}));
rightLeg.x = 8;
rightLeg.y = 15;
// Store body parts for animation
self.bodyParts = {
head: head,
body: body,
leftArm: leftArm,
rightArm: rightArm,
leftLeg: leftLeg,
rightLeg: rightLeg
};
self.isActive = true;
self.animationTimer = 0;
// Security guard patrol animation
self.update = function () {
self.animationTimer += 0.1;
// Subtle walking animation while patrolling
if (self.isActive) {
self.bodyParts.leftArm.rotation = Math.sin(self.animationTimer) * 0.2;
self.bodyParts.rightArm.rotation = Math.sin(self.animationTimer + Math.PI) * 0.2;
self.bodyParts.head.rotation = Math.sin(self.animationTimer * 0.5) * 0.1;
self.bodyParts.body.y = Math.sin(self.animationTimer * 2) * 1;
}
// Check for customers trying to leave without paying
customers.forEach(function (customer) {
if (customer.state === 'leaving' && customer.shoppingCart.length > 0) {
var distance = Math.sqrt(Math.pow(customer.x - self.x, 2) + Math.pow(customer.y - self.y, 2));
if (distance < 100) {
// Stop the customer
customer.state = 'checkout';
customer.targetShelf = null;
// Security guard alert animation
tween(self.bodyParts.rightArm, {
rotation: -0.8
}, {
duration: 200,
onComplete: function onComplete() {
tween(self.bodyParts.rightArm, {
rotation: 0
}, {
duration: 200
});
}
});
// Flash red to indicate security alert
LK.effects.flashObject(self, 0xff0000, 500);
}
}
});
};
return self;
});
var Shelf = Container.expand(function () {
var self = Container.call(this);
var shelfGraphics = self.attachAsset('shelf', {
anchorX: 0.5,
anchorY: 0.5
});
self.products = [];
self.maxProducts = 5;
self.productType = 'basic';
self.price = 10;
self.addProduct = function () {
if (self.products.length < self.maxProducts) {
var product = self.addChild(LK.getAsset('product', {
anchorX: 0.5,
anchorY: 0.5
}));
product.x = (self.products.length - 2) * 20;
product.y = -25;
self.products.push(product);
}
};
self.sellProduct = function () {
if (self.products.length > 0) {
var product = self.products.pop();
product.destroy();
return self.price;
}
return 0;
};
self.down = function (x, y, obj) {
// Shelves no longer sell products when clicked
// Products can only be sold through customer interactions
};
return self;
});
var StoreManager = Container.expand(function () {
var self = Container.call(this);
self.customerSpawnTimer = 0;
self.customerSpawnRate = 120; // spawn every 2 seconds at 60fps
self.spawnCustomer = function () {
if (customers.length < 8) {
var customer = new Customer();
customer.x = 250; // Near entrance door
customer.y = 600 + (Math.random() - 0.5) * 100;
customers.push(customer);
game.addChild(customer);
}
};
self.update = function () {
self.customerSpawnTimer++;
// Check if store has products available
var hasProducts = shelves.some(function (shelf) {
return shelf.products.length > 0;
});
// Adjust spawn rate based on product availability
var currentSpawnRate = self.customerSpawnRate;
if (!hasProducts) {
// Much fewer customers when no products (5x slower spawn rate)
currentSpawnRate = self.customerSpawnRate * 5;
}
// Apply advertisement board bonus - 4% more customers per board
var adBoardMultiplier = 1 + advertisementBoards.length * 0.04;
currentSpawnRate = currentSpawnRate / adBoardMultiplier;
if (self.customerSpawnTimer >= currentSpawnRate) {
self.customerSpawnTimer = 0;
self.spawnCustomer();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game variables
var money = 45;
var level = 1;
var shelves = [];
var customers = [];
var cashiers = [];
var moneyEffects = [];
var storeSize = storage.storeSize || 1;
var emptyShelfPenaltyTimer = 0;
var warningText = null;
var taxTimer = 0;
var taxInterval = 72000; // 20 minutes at 60fps (20 * 60 * 60)
var mascot = null;
var mascotButton = null;
var mascotMoneyMultiplier = 1.5; // 1.5x money when mascot is active
var customizePanel = null;
var securityGuard = null;
var adBoardCounter = 0;
var adTexts = ['BAM MARKET\nBest Deals!', 'FRESH PRODUCTS\nDaily!', 'SAVE MORE\nSpend Less!', 'QUALITY ITEMS\nLow Prices!', 'NEW ARRIVALS\nEvery Week!', 'PREMIUM GOODS\nAffordable!', 'SHOP SMART\nSave Big!', 'EXCLUSIVE\nOffers Here!'];
var advertisementBoards = [];
// Helper function to find nearest cashier
function findNearestCashier() {
if (cashiers.length === 0) return null;
var nearestCashier = cashiers[0];
var minDistance = Infinity;
cashiers.forEach(function (cashier) {
var distance = Math.sqrt(Math.pow(cashier.x, 2) + Math.pow(cashier.y, 2));
if (distance < minDistance && !cashier.isProcessing) {
minDistance = distance;
nearestCashier = cashier;
}
});
return nearestCashier;
}
// Helper function to check if all shelves are empty
function areAllShelvesEmpty() {
return shelves.every(function (shelf) {
return shelf.products.length === 0;
});
}
// Function to show warning message
function showWarningMessage() {
if (warningText) {
warningText.destroy();
}
warningText = new Text2('Please buy products!', {
size: 80,
fill: 0xff0000
});
warningText.anchor.set(0.5, 0.5);
warningText.x = 1024;
warningText.y = 1366;
game.addChild(warningText);
// Flash the warning text
LK.effects.flashObject(warningText, 0xffff00, 1000);
}
// Function to show penalty message
function showPenaltyMessage() {
if (warningText) {
warningText.destroy();
}
warningText = new Text2('Buy products -$2', {
size: 80,
fill: 0xff0000
});
warningText.anchor.set(0.5, 0.5);
warningText.x = 1024;
warningText.y = 1366;
game.addChild(warningText);
// Flash the penalty text
LK.effects.flashObject(warningText, 0xffff00, 1000);
// Create penalty indicator next to money display
var penaltyIndicator = new Text2('-$2', {
size: 60,
fill: 0xff0000
});
penaltyIndicator.anchor.set(0, 0);
penaltyIndicator.x = moneyText.x + 100;
penaltyIndicator.y = moneyText.y;
LK.gui.top.addChild(penaltyIndicator);
// Animate penalty indicator
tween(penaltyIndicator, {
y: penaltyIndicator.y - 30,
alpha: 0
}, {
duration: 2000,
onComplete: function onComplete() {
penaltyIndicator.destroy();
}
});
}
// Function to hide warning message
function hideWarningMessage() {
if (warningText) {
warningText.destroy();
warningText = null;
}
}
// Function to collect tax
function collectTax() {
// Show tax warning message
if (warningText) {
warningText.destroy();
}
warningText = new Text2('Tax Time! -$110', {
size: 80,
fill: 0xff0000
});
warningText.anchor.set(0.5, 0.5);
warningText.x = 1024;
warningText.y = 1366;
game.addChild(warningText);
// Flash the tax warning
LK.effects.flashObject(warningText, 0xffff00, 2000);
// Deduct tax amount
money -= 110;
updateUI();
// Flash screen red for tax collection
LK.effects.flashScreen(0xff0000, 1000);
// Create tax penalty indicator
var taxIndicator = new Text2('-$110 TAX', {
size: 60,
fill: 0xff0000
});
taxIndicator.anchor.set(0, 0);
taxIndicator.x = moneyText.x + 100;
taxIndicator.y = moneyText.y;
LK.gui.top.addChild(taxIndicator);
// Animate tax indicator
tween(taxIndicator, {
y: taxIndicator.y - 50,
alpha: 0
}, {
duration: 3000,
onComplete: function onComplete() {
taxIndicator.destroy();
}
});
}
// Function to create money effect at position
function createMoneyEffect(x, y, amount) {
// Create multiple money icons based on amount
var numEffects = Math.min(Math.floor(amount / 10) + 1, 5);
for (var i = 0; i < numEffects; i++) {
var effect = new MoneyEffect();
effect.x = x + (Math.random() - 0.5) * 40;
effect.y = y + (Math.random() - 0.5) * 20;
// Add slight delay between effects
var delay = i * 100;
if (delay > 0) {
effect.alpha = 0;
tween(effect, {
alpha: 1
}, {
duration: 200,
delay: delay
});
}
moneyEffects.push(effect);
game.addChild(effect);
}
}
// UI Elements
var gameTitle = new Text2('BAM Market', {
size: 80,
fill: 0x000000
});
gameTitle.anchor.set(0.5, 0);
gameTitle.x = 0;
gameTitle.y = 20;
LK.gui.top.addChild(gameTitle);
var moneyText = new Text2('$' + money, {
size: 60,
fill: 0x000000
});
moneyText.anchor.set(0.5, 0);
moneyText.y = 120;
LK.gui.top.addChild(moneyText);
var levelText = new Text2('Level ' + level, {
size: 40,
fill: 0x000000
});
levelText.anchor.set(0, 0);
levelText.x = 50;
levelText.y = 50;
LK.gui.topLeft.addChild(levelText);
// Store floor
var storeFloor = game.addChild(LK.getAsset('storeFloor', {
anchorX: 0.5,
anchorY: 0.5
}));
storeFloor.x = 1024;
storeFloor.y = 866;
// Initial shelves
function createShelf(x, y) {
var shelf = new Shelf();
shelf.x = x;
shelf.y = y;
// Set price based on current level
shelf.price = Math.floor(10 * Math.pow(1.5, level - 1));
// Stock with initial products
for (var i = 0; i < 3; i++) {
shelf.addProduct();
}
shelves.push(shelf);
game.addChild(shelf);
return shelf;
}
// Create entrance and exit doors
var entranceDoor = new Door();
entranceDoor.x = 200; // Far left edge of store
entranceDoor.y = 600; // Middle height
entranceDoor.setDoorType('entrance');
game.addChild(entranceDoor);
var exitDoor = new Door();
exitDoor.x = 1800; // Far right edge of store
exitDoor.y = 600; // Middle height
exitDoor.setDoorType('exit');
game.addChild(exitDoor);
// Create security guard at exit door
securityGuard = new Security();
securityGuard.x = 1750; // Position right next to exit door
securityGuard.y = 600; // Same height as exit door
game.addChild(securityGuard);
// Add "SECURITY" text above the security guard
var securityText = new Text2('SECURITY', {
size: 24,
fill: 0x000000
});
securityText.anchor.set(0.5, 0.5);
securityText.x = securityGuard.x;
securityText.y = securityGuard.y - 80;
game.addChild(securityText);
// Create and position advertisement board
var adBoard = new Advertisement(adBoardCounter);
// Position in organized grid pattern
var boardsPerRow = 4;
var gridSpacingX = 250;
var gridSpacingY = 200;
var startX = 1200;
var startY = 250;
var row = Math.floor(adBoardCounter / boardsPerRow);
var col = adBoardCounter % boardsPerRow;
adBoard.x = startX + col * gridSpacingX;
adBoard.y = startY + row * gridSpacingY;
game.addChild(adBoard);
advertisementBoards.push(adBoard);
adBoardCounter++;
// Create initial store layout
createShelf(600, 500);
createShelf(800, 500);
createShelf(1000, 500);
createShelf(600, 700);
createShelf(800, 700);
// Create initial cashiers - positioned at front of store for easy customer access
for (var i = 0; i < 1; i++) {
var cashier = new Cashier();
cashier.x = 600 + i * 200; // Space cashiers 200 pixels apart
cashier.y = 400; // Front of store for easy access
cashiers.push(cashier);
game.addChild(cashier);
}
// Expand store button
var expandButton = game.addChild(LK.getAsset('expandButton', {
anchorX: 0.5,
anchorY: 0.5
}));
expandButton.x = 1024;
expandButton.y = 1700;
expandButton.scaleX = 1.3;
expandButton.scaleY = 1.3;
var expandText = new Text2('Expand\n$150', {
size: 30,
fill: 0xFFFFFF
});
expandText.anchor.set(0.5, 0.5);
expandButton.addChild(expandText);
expandButton.down = function (x, y, obj) {
var expandCost = Math.floor(150 * Math.pow(1.5, level - 1));
if (shelves.length >= 15) {
// Maximum 15 shelves reached (5 initial + 10 additional = 15 total, but we want max 5 additional)
LK.effects.flashObject(expandButton, 0xFF0000, 500);
return;
}
if (money >= expandCost) {
money -= expandCost;
storeSize++;
// Find the rightmost shelf position
var rightmostX = 0;
shelves.forEach(function (shelf) {
if (shelf.x > rightmostX) {
rightmostX = shelf.x;
}
});
// Check if we can fit horizontally (within store bounds)
var newShelfX = rightmostX + 200; // 200 pixels spacing between shelves
var maxStoreWidth = 1800; // Store width limit
if (newShelfX <= maxStoreWidth) {
// Add new shelves next to existing ones horizontally
createShelf(newShelfX, 500);
createShelf(newShelfX, 700);
} else {
// Find bottom-most shelf position to stack vertically
var bottommostY = 0;
shelves.forEach(function (shelf) {
if (shelf.y > bottommostY) {
bottommostY = shelf.y;
}
});
// Add new shelves below existing ones
var newShelfY = bottommostY + 200; // 200 pixels spacing between shelf rows
createShelf(600, newShelfY); // Start new row at initial X position
createShelf(800, newShelfY);
}
// Hide button if maximum reached
if (shelves.length >= 15) {
expandButton.visible = false;
}
// Level up when expanding store (buying shelves)
level++;
levelText.setText('Level ' + level);
LK.effects.flashScreen(0x00FF00, 1000);
updateUI();
LK.getSound('expand').play();
LK.effects.flashObject(expandButton, 0x00FF00, 500);
} else {
LK.effects.flashObject(expandButton, 0xFF0000, 500);
}
};
// Restock button
var stockButton = game.addChild(LK.getAsset('stockButton', {
anchorX: 0.5,
anchorY: 0.5
}));
stockButton.x = 1024;
stockButton.y = 1820;
stockButton.scaleX = 1.3;
stockButton.scaleY = 1.3;
var stockText = new Text2('Restock\n$50', {
size: 30,
fill: 0xFFFFFF
});
stockText.anchor.set(0.5, 0.5);
stockButton.addChild(stockText);
stockButton.down = function (x, y, obj) {
var stockCost = Math.floor(50 * Math.pow(1.5, level - 1));
if (money >= stockCost) {
money -= stockCost;
// Restock all shelves
shelves.forEach(function (shelf) {
while (shelf.products.length < shelf.maxProducts) {
shelf.addProduct();
}
});
updateUI();
LK.getSound('purchase').play();
LK.effects.flashObject(stockButton, 0x00FF00, 500);
} else {
LK.effects.flashObject(stockButton, 0xFF0000, 500);
}
};
// Hire cashier button
var hireCashierButton = game.addChild(LK.getAsset('hireCashierButton', {
anchorX: 0.5,
anchorY: 0.5
}));
hireCashierButton.x = 1024;
hireCashierButton.y = 1940;
hireCashierButton.scaleX = 1.3;
hireCashierButton.scaleY = 1.3;
var hireCashierText = new Text2('Hire\nCashier\n$175', {
size: 26,
fill: 0xFFFFFF
});
hireCashierText.anchor.set(0.5, 0.5);
hireCashierButton.addChild(hireCashierText);
hireCashierButton.down = function (x, y, obj) {
var hireCost = Math.floor(175 * Math.pow(1.5, level - 1));
if (cashiers.length >= 4) {
// Maximum 4 cashiers reached
LK.effects.flashObject(hireCashierButton, 0xFF0000, 500);
return;
}
if (money >= hireCost) {
money -= hireCost;
// Create new cashier
var newCashier = new Cashier();
// Position new cashier next to existing cashiers
var cashierX = 600 + cashiers.length * 200;
var cashierY = 400;
var maxStoreWidth = 1800; // Store width limit
// If cashier would go beyond store width, stack vertically
if (cashierX > maxStoreWidth) {
// Find how many cashiers fit horizontally
var cashiersPerRow = Math.floor((maxStoreWidth - 600) / 200) + 1;
var row = Math.floor(cashiers.length / cashiersPerRow);
var col = cashiers.length % cashiersPerRow;
cashierX = 600 + col * 200;
cashierY = 400 + row * 150; // Stack with 150 pixel spacing vertically
}
newCashier.x = cashierX;
newCashier.y = cashierY;
cashiers.push(newCashier);
game.addChild(newCashier);
// Hide button if maximum reached
if (cashiers.length >= 4) {
hireCashierButton.visible = false;
}
// Level up when hiring cashier
level++;
levelText.setText('Level ' + level);
LK.effects.flashScreen(0x00FF00, 1000);
updateUI();
LK.getSound('cashRegister').play();
LK.effects.flashObject(hireCashierButton, 0x00FF00, 500);
} else {
LK.effects.flashObject(hireCashierButton, 0xFF0000, 500);
}
};
// Create mascot button (initially hidden)
mascotButton = game.addChild(LK.getAsset('mascotButton', {
anchorX: 0.5,
anchorY: 0.5
}));
mascotButton.x = 1024;
mascotButton.y = 2060;
mascotButton.scaleX = 1.3;
mascotButton.scaleY = 1.3;
mascotButton.visible = false; // Hide initially
var mascotButtonText = new Text2('Buy\nMascot\n$670', {
size: 26,
fill: 0xFFFFFF
});
mascotButtonText.anchor.set(0.5, 0.5);
mascotButton.addChild(mascotButtonText);
mascotButton.down = function (x, y, obj) {
var mascotCost = 670;
if (money >= mascotCost && level >= 10 && !mascot) {
money -= mascotCost;
// Create mascot
mascot = new Mascot();
mascot.x = 400; // Position near entrance
mascot.y = 500;
game.addChild(mascot);
// Hide mascot button after purchase
mascotButton.visible = false;
// Double customer spawn rate (2x more customers)
storeManager.customerSpawnRate = Math.max(30, storeManager.customerSpawnRate * 0.5);
updateUI();
LK.getSound('purchase').play();
LK.effects.flashObject(mascotButton, 0x00FF00, 500);
LK.effects.flashScreen(0x00FF00, 1000);
} else {
LK.effects.flashObject(mascotButton, 0xFF0000, 500);
}
};
// Add advertisement board button
var adBoardButton = game.addChild(LK.getAsset('stockButton', {
anchorX: 0.5,
anchorY: 0.5
}));
adBoardButton.x = 1024;
adBoardButton.y = 2180;
adBoardButton.scaleX = 1.3;
adBoardButton.scaleY = 1.3;
var adBoardText = new Text2('Add\nAd Board\n$75', {
size: 26,
fill: 0xFFFFFF
});
adBoardText.anchor.set(0.5, 0.5);
adBoardButton.addChild(adBoardText);
adBoardButton.down = function (x, y, obj) {
var adBoardCost = 75;
if (advertisementBoards.length >= 3) {
// Maximum 3 advertisement boards reached
LK.effects.flashObject(adBoardButton, 0xFF0000, 500);
return;
}
if (money >= adBoardCost) {
money -= adBoardCost;
// Create new advertisement board with unique text
var newAdBoard = new Advertisement(adBoardCounter);
// Position in organized grid pattern
var boardsPerRow = 4;
var gridSpacingX = 250;
var gridSpacingY = 200;
var startX = 1200;
var startY = 250;
var row = Math.floor(adBoardCounter / boardsPerRow);
var col = adBoardCounter % boardsPerRow;
newAdBoard.x = startX + col * gridSpacingX;
newAdBoard.y = startY + row * gridSpacingY;
game.addChild(newAdBoard);
advertisementBoards.push(newAdBoard);
adBoardCounter++;
// Hide button if maximum reached
if (advertisementBoards.length >= 3) {
adBoardButton.visible = false;
}
updateUI();
LK.getSound('purchase').play();
LK.effects.flashObject(adBoardButton, 0x00FF00, 500);
} else {
LK.effects.flashObject(adBoardButton, 0xFF0000, 500);
}
};
// Customize store button
var customizeButton = game.addChild(LK.getAsset('customizeButton', {
anchorX: 0.5,
anchorY: 0.5
}));
customizeButton.x = 1024;
customizeButton.y = 2300;
customizeButton.scaleX = 1.3;
customizeButton.scaleY = 1.3;
var customizeText = new Text2('Customize\nStore', {
size: 30,
fill: 0xFFFFFF
});
customizeText.anchor.set(0.5, 0.5);
customizeButton.addChild(customizeText);
customizeButton.down = function (x, y, obj) {
if (!customizePanel) {
customizePanel = new CustomizePanel();
game.addChild(customizePanel);
LK.getSound('purchase').play();
}
};
// Store manager
var storeManager = new StoreManager();
game.addChild(storeManager);
function updateUI() {
moneyText.setText('$' + money);
// Level up system
if (money >= level * 1000) {
level++;
levelText.setText('Level ' + level);
LK.effects.flashScreen(0x00FF00, 1000);
}
// Show mascot button at level 10
if (level >= 10 && !mascot && mascotButton) {
mascotButton.visible = true;
}
// Save progress
storage.money = money;
storage.level = level;
storage.storeSize = storeSize;
}
// Game loop
game.update = function () {
// Update customers
for (var i = customers.length - 1; i >= 0; i--) {
var customer = customers[i];
if (customer.update) {
customer.update();
}
}
// Update cashiers
for (var i = 0; i < cashiers.length; i++) {
var cashier = cashiers[i];
if (cashier.update) {
cashier.update();
}
}
// Update store manager
if (storeManager.update) {
storeManager.update();
}
// Update doors
if (entranceDoor.update) {
entranceDoor.update();
}
if (exitDoor.update) {
exitDoor.update();
}
// Update money effects
for (var i = moneyEffects.length - 1; i >= 0; i--) {
var effect = moneyEffects[i];
if (effect.update) {
effect.update();
}
}
// Update mascot
if (mascot && mascot.update) {
mascot.update();
}
// Update security guard
if (securityGuard && securityGuard.update) {
securityGuard.update();
}
// Update advertisement board
if (adBoard && adBoard.update) {
adBoard.update();
}
// Check for empty shelves penalty
if (areAllShelvesEmpty()) {
emptyShelfPenaltyTimer++;
// Show warning message
showWarningMessage();
// Apply penalty every 10 seconds (600 ticks at 60fps)
if (emptyShelfPenaltyTimer >= 600) {
money -= 2;
emptyShelfPenaltyTimer = 0;
updateUI();
// Show penalty message
showPenaltyMessage();
// Flash screen red for penalty
LK.effects.flashScreen(0xff0000, 500);
}
} else {
emptyShelfPenaltyTimer = 0;
hideWarningMessage();
}
// Check win condition
if (money >= 10000) {
LK.showYouWin();
}
// Tax collection every 20 minutes
taxTimer++;
if (taxTimer >= taxInterval) {
collectTax();
taxTimer = 0; // Reset timer
}
// Check lose condition (bankruptcy)
if (money < 0 && shelves.every(function (shelf) {
return shelf.products.length === 0;
})) {
LK.showGameOver();
}
};
// Handle pause menu with reset option
LK.on('pauseMenuShow', function () {
// Add reset button to pause menu
var resetButton = LK.gui.center.addChild(LK.getAsset('stockButton', {
anchorX: 0.5,
anchorY: 0.5
}));
resetButton.x = 0;
resetButton.y = 100;
resetButton.scaleX = 1.5;
resetButton.scaleY = 1.5;
var resetText = new Text2('Reset Game', {
size: 32,
fill: 0xFFFFFF
});
resetText.anchor.set(0.5, 0.5);
resetButton.addChild(resetText);
resetButton.down = function () {
// Clear storage
storage.money = undefined;
storage.level = undefined;
storage.storeSize = undefined;
// Reset game by showing game over (which resets the game)
LK.showGameOver();
};
// Store reference to clean up later
resetButton.pauseMenuButton = true;
});
LK.on('pauseMenuHide', function () {
// Clean up reset button when pause menu is hidden
var children = LK.gui.center.children.slice();
for (var i = 0; i < children.length; i++) {
if (children[i].pauseMenuButton) {
children[i].destroy();
}
}
});
// Initialize UI
updateUI();