/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Car class
var Car = Container.expand(function () {
var self = Container.call(this);
var carGfx = self.attachAsset('car', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = carGfx.width;
self.height = carGfx.height;
self.speed = 6 + Math.random() * 2; // px per tick
self.state = 'arriving'; // arriving, refueling, leaving
self.refuelTicks = 0;
self.refuelTime = 60 + Math.floor(Math.random() * 60); // 1-2 seconds
self.pumpX = 0;
self.pumpY = 0;
self.update = function () {
if (self.state === 'arriving') {
// Move car towards pump
var dx = self.pumpX - self.x;
var dy = self.pumpY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 10) {
self.x = self.pumpX;
self.y = self.pumpY;
// Stop at pump, but do not start refueling until clicked
self.state = 'waitingForRefuel';
self.refuelTicks = 0;
} else {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
} else if (self.state === 'refueling') {
self.refuelTicks++;
if (self.refuelTicks >= self.refuelTime) {
self.state = 'leaving';
self.leaveTargetX = 2200; // off screen right
self.leaveTargetY = self.y;
}
} else if (self.state === 'leaving') {
self.x += self.speed * 1.2;
if (self.x > 2200) {
self.destroyed = true;
}
}
};
return self;
});
// Pump class
var Pump = Container.expand(function () {
var self = Container.call(this);
var pumpGfx = self.attachAsset('pump', {
anchorX: 0.5,
anchorY: 1
});
self.width = pumpGfx.width;
self.height = pumpGfx.height;
self.car = null; // Car currently at this pump
self.isBusy = function () {
return !!self.car;
};
return self;
});
// Gas Station Floor class
var StationFloor = Container.expand(function () {
var self = Container.call(this);
self.floorNum = 1; // 1 = base, 2,3,4 = upgrades
self.pumps = [];
// Floor graphics
var floorAsset = self.attachAsset(self.floorNum === 1 ? 'stationBase' : 'stationFloor', {
anchorX: 0.5,
anchorY: 1
});
self.width = floorAsset.width;
self.height = floorAsset.height;
// Place pumps
self.initPumps = function () {
// 2 pumps per floor, increased spacing for more separation
var pumpSpacing = 400; // increased spacing for more distance between pumps
var pumpOffset = pumpSpacing * (2 - 1) / 2; // center pumps
for (var i = 0; i < 2; i++) {
var pump = new Pump();
pump.x = -pumpOffset + i * pumpSpacing;
pump.y = -10;
self.addChild(pump);
self.pumps.push(pump);
}
};
self.initPumps();
return self;
});
// Upgrade Button class
var UpgradeButton = Container.expand(function () {
var self = Container.call(this);
var btnGfx = self.attachAsset('upgradeBtn', {
anchorX: 0.5,
anchorY: 0.5
});
// Move the icon to the front (after btnGfx, so it is above the button background)
var icon = self.attachAsset('upgradeIcon', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0
});
// Do NOT add the label, so only the icon is visible
self.setEnabled = function (enabled) {
btnGfx.alpha = enabled ? 1 : 0.5;
self.interactive = enabled;
self.buttonMode = enabled;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a2a3a
});
/****
* Game Code
****/
// new car model
// Upgrade icon
// Upgrade button
// Car
// Pump
// Gas station floor (for floors 2-4)
// Gas station base (floor 1)
// Game state variables
var money = 0;
var floors = [];
var cars = [];
var maxFloors = 4;
var floorCount = 2; // Start with 2 floors
var carSpawnTimer = 0;
var carSpawnInterval = 90; // ticks between car spawns
var upgradeCost = 100;
var upgradeBtn;
var moneyTxt;
var floorYStart = 2200; // y position of base floor
var floorSpacing = 400; // increased vertical space between floors for stacking
// Money display
moneyTxt = new Text2('$0', {
size: 100,
fill: 0xFFFFFF
});
moneyTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(moneyTxt);
// Place floors
function placeFloors() {
// Remove all floors
for (var i = 0; i < floors.length; i++) {
floors[i].destroy();
}
floors = [];
// Define the starting X position for the first station
var startX = 2048 / 2;
// Define the spacing between stations when placing new ones
var stationSpacing = 900; // Adjust as needed for visual separation
for (var f = 0; f < floorCount; f++) {
var floor = new StationFloor();
floor.floorNum = f + 1;
// Set correct asset for base or upper floors
var assetId = f === 0 ? 'stationBase' : 'stationFloor';
floor.children[0].setAsset(assetId);
// Position floors horizontally based on floor number
// The first two floors are stacked, subsequent floors go to the left
if (f < 2) {
floor.x = startX;
// Stack floors vertically with space between them
floor.y = floorYStart - f * floorSpacing;
} else {
// New floors go to the left of the initial two floors
floor.x = startX - stationSpacing * (Math.ceil((f + 1) / 2) - 1); // Position new stations to the left
// Alternate y position for stacked floors in new stations
floor.y = floorYStart - f % 2 * floorSpacing;
}
game.addChild(floor);
floors.push(floor);
}
// --- Place a clickable button right above the first gas station ---
if (typeof aboveFirstStationBtn !== "undefined" && aboveFirstStationBtn) {
aboveFirstStationBtn.destroy();
aboveFirstStationBtn = null;
}
aboveFirstStationBtn = new UpgradeButton();
aboveFirstStationBtn.setEnabled(true);
aboveFirstStationBtn.interactive = true;
aboveFirstStationBtn.buttonMode = true;
// Enlarge the button
aboveFirstStationBtn.scaleX = 1.4;
aboveFirstStationBtn.scaleY = 1.4;
aboveFirstStationBtn.x = 2048 / 2;
if (floors.length > 0) {
// Move button even higher above the first floor (base station)
aboveFirstStationBtn.y = floors[0].y - floors[0].height - 1200;
} else {
aboveFirstStationBtn.y = floorYStart - 200 - 1200;
}
aboveFirstStationBtn.down = function (x, y, obj) {
// Open a window (modal) on mouse/touch click
if (!game.specialWindow) {
var winW = 900;
var winH = 700;
var win = new Container();
// Background
var bg = LK.getAsset('stationBase', {
width: winW,
height: winH,
color: 0x224444,
anchorX: 0.5,
anchorY: 0.5
});
win.addChild(bg);
// Title
var title = new Text2("Special Window", {
size: 90,
fill: 0xFFFFFF,
align: "center"
});
title.anchor.set(0.5, 0);
title.x = 0;
title.y = -winH / 2 + 60;
win.addChild(title);
// Close button
var closeBtn = new Text2("X", {
size: 80,
fill: 0xFF4444,
align: "center"
});
closeBtn.anchor.set(0.5, 0.5);
closeBtn.x = winW / 2 - 60 - 20;
closeBtn.y = -winH / 2 + 60;
win.addChild(closeBtn);
closeBtn.interactive = true;
closeBtn.buttonMode = true;
closeBtn.down = function (x, y, obj) {
if (game.specialWindow) {
game.specialWindow.destroy();
game.specialWindow = null;
}
};
// Placeholder for content
var info = new Text2("Special window content!", {
size: 60,
fill: 0xcccccc,
align: "center"
});
info.anchor.set(0.5, 0.5);
info.x = 0;
info.y = 60;
win.addChild(info);
win.x = 2048 / 2;
win.y = 2732 / 2;
LK.gui.center.addChild(win);
game.specialWindow = win;
}
// Animate the button as before
tween(aboveFirstStationBtn, {
scaleX: 1.2 * 1.4,
scaleY: 1.2 * 1.4
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(aboveFirstStationBtn, {
scaleX: 1.4,
scaleY: 1.4
}, {
duration: 100,
easing: tween.easeIn
});
}
});
};
game.addChild(aboveFirstStationBtn);
}
placeFloors();
// Upgrade button
upgradeBtn = new UpgradeButton();
// Restore upgrade button color to original (dark)
if (upgradeBtn.children && upgradeBtn.children.length > 0) {
// The first child is the button graphic
upgradeBtn.children[0].setAsset('upgradeBtn', {
color: 0x050410
}); // original dark color
}
// Restore upgrade icon position to previous (centered)
if (upgradeBtn.children && upgradeBtn.children.length > 1) {
// The second child is the icon
upgradeBtn.children[1].x = 0;
upgradeBtn.children[1].y = 0;
}
upgradeBtn.x = 2048 / 2;
upgradeBtn.y = moneyTxt.y + moneyTxt.height + 60; // 60px below the money display
upgradeBtn.setEnabled(true);
upgradeBtn.interactive = true;
upgradeBtn.buttonMode = true;
upgradeBtn.down = function (x, y, obj) {
// Open upgrade window (modal) on mouse/touch click
if (!game.upgradeWindow) {
var winW = 900;
var winH = 700;
var win = new Container();
// Background
var bg = LK.getAsset('stationBase', {
width: winW,
height: winH,
color: 0x222244,
anchorX: 0.5,
anchorY: 0.5
});
win.addChild(bg);
// Title
var title = new Text2("Upgrade Station", {
size: 90,
fill: 0xFFFFFF,
align: "center"
});
title.anchor.set(0.5, 0);
title.x = 0;
title.y = -winH / 2 + 60;
win.addChild(title);
// Close button
var closeBtn = new Text2("X", {
size: 80,
fill: 0xFF4444,
align: "center"
});
closeBtn.anchor.set(0.5, 0.5);
closeBtn.x = winW / 2 - 60 - 20;
closeBtn.y = -winH / 2 + 60;
win.addChild(closeBtn);
closeBtn.interactive = true;
closeBtn.buttonMode = true;
closeBtn.down = function (x, y, obj) {
if (game.upgradeWindow) {
game.upgradeWindow.destroy();
game.upgradeWindow = null;
}
};
// Placeholder for upgrade options
var info = new Text2("Upgrade options coming soon!", {
size: 60,
fill: 0xcccccc,
align: "center"
});
info.anchor.set(0.5, 0.5);
info.x = 0;
info.y = 60;
win.addChild(info);
win.x = 2048 / 2;
win.y = 2732 / 2;
LK.gui.center.addChild(win);
game.upgradeWindow = win;
}
};
// Place upgrade button below money display in gui.top
LK.gui.top.addChild(upgradeBtn);
upgradeBtn.x = 2048 / 2;
upgradeBtn.y = moneyTxt.y + moneyTxt.height + 60; // 60px below the money display
// Automatic Fuel Dispenser Button
var autoDispenserBtnCost = 250;
var autoDispenserEnabled = false;
var autoDispenserBtn = new UpgradeButton();
autoDispenserBtn.x = 2048 / 2;
autoDispenserBtn.y = 2732 - 320;
autoDispenserBtn.setEnabled(money >= autoDispenserBtnCost && !autoDispenserEnabled);
LK.gui.bottom.addChild(autoDispenserBtn);
// Update auto dispenser button state
function updateAutoDispenserBtn() {
if (!autoDispenserEnabled) {
autoDispenserBtn.setEnabled(money >= autoDispenserBtnCost);
} else {
autoDispenserBtn.setEnabled(false);
}
}
updateAutoDispenserBtn();
// Handle auto dispenser button press
autoDispenserBtn.down = function (x, y, obj) {
if (!autoDispenserEnabled && money >= autoDispenserBtnCost) {
money -= autoDispenserBtnCost;
autoDispenserEnabled = true;
updateMoneyTxt();
updateAutoDispenserBtn();
// Animate button
tween(autoDispenserBtn, {
scaleX: 1.15,
scaleY: 1.15
}, {
duration: 120,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(autoDispenserBtn, {
scaleX: 1,
scaleY: 1
}, {
duration: 120,
easing: tween.easeIn
});
}
});
}
};
// Update upgrade button label
function updateUpgradeBtn() {
if (floorCount < maxFloors) {
upgradeBtn.setEnabled(money >= upgradeCost);
} else {
upgradeBtn.setEnabled(false);
}
}
updateUpgradeBtn();
// Handle upgrade button press
upgradeBtn.down = function (x, y, obj) {
// Check if the player has enough money for *any* upgrade
if (money < upgradeCost) {
// Show a red message below the upgrade button for 4 seconds, and reset timer if pressed again
if (!game.notEnoughMoneyLabel) {
game.notEnoughMoneyLabel = new Text2("Not enough money", {
size: 60,
fill: 0xFF4444,
align: "center"
});
game.notEnoughMoneyLabel.anchor.set(0.5, 0);
// Place below the upgrade button (add 40px for spacing)
game.notEnoughMoneyLabel.x = upgradeBtn.x;
game.notEnoughMoneyLabel.y = upgradeBtn.y + upgradeBtn.height / 2 + 40;
LK.gui.top.addChild(game.notEnoughMoneyLabel);
}
// Always reset the timer if pressed again
if (game.notEnoughMoneyTimeout) {
LK.clearTimeout(game.notEnoughMoneyTimeout);
game.notEnoughMoneyTimeout = null;
}
game.notEnoughMoneyLabel.visible = true;
// Hide after 4 seconds
game.notEnoughMoneyTimeout = LK.setTimeout(function () {
if (game.notEnoughMoneyLabel) {
game.notEnoughMoneyLabel.visible = false;
}
game.notEnoughMoneyTimeout = null;
}, 4000);
return;
}
// If money is sufficient, first check for the special upgrade condition (money exactly 100)
if (money === 100) {
// Deduct the upgrade cost (set to 100 for this special case)
money -= 100; // Assuming 100 is the cost for the first special upgrade
updateMoneyTxt();
// Show a green message below the upgrade button for 4 seconds, and reset timer if pressed again
if (!game.upgradeSuccessLabel) {
game.upgradeSuccessLabel = new Text2("Upgrade successful!", {
size: 60,
fill: 0x44FF44,
align: "center"
});
game.upgradeSuccessLabel.anchor.set(0.5, 0);
// Place below the upgrade button (add 40px for spacing)
game.upgradeSuccessLabel.x = upgradeBtn.x;
game.upgradeSuccessLabel.y = upgradeBtn.y + upgradeBtn.height / 2 + 40;
LK.gui.top.addChild(game.upgradeSuccessLabel);
}
// Always reset the timer if pressed again
if (game.upgradeSuccessTimeout) {
LK.clearTimeout(game.upgradeSuccessTimeout);
game.upgradeSuccessTimeout = null;
}
game.upgradeSuccessLabel.visible = true;
// Hide after 4 seconds
game.upgradeSuccessTimeout = LK.setTimeout(function () {
if (game.upgradeSuccessLabel) {
game.upgradeSuccessLabel.visible = false;
}
game.upgradeSuccessTimeout = null;
}, 4000);
// Add new floors and pumps for the special upgrade
// Check if we are at the initial state and money is 100 for the special upgrade
// We should only add floors up to 4 total
if (floorCount < maxFloors) {
floorCount = Math.min(floorCount + 2, maxFloors); // Add 2 floors, but not exceeding maxFloors
placeFloors(); // Re-place all floors including the new ones
updateUpgradeBtn();
}
// Enable new car model
if (typeof extraCarModelEnabled === "undefined") {
extraCarModelEnabled = true;
}
// Optionally, show a message for the new car model
if (!game.newCarModelWindow) {
var winW = 700;
var winH = 350;
var win = new Container();
var bg = LK.getAsset('stationBase', {
width: winW,
height: winH,
color: 0x224444,
anchorX: 0.5,
anchorY: 0.5
});
win.addChild(bg);
var title = new Text2("New car model unlocked!", {
size: 70,
fill: 0x44FF44,
align: "center"
});
title.anchor.set(0.5, 0.5);
title.x = 0;
title.y = 0;
win.addChild(title);
var closeBtn = new Text2("OK", {
size: 60,
fill: 0xFFFFFF,
align: "center"
});
closeBtn.anchor.set(0.5, 0.5);
closeBtn.x = 0;
closeBtn.y = winH / 2 - 60;
win.addChild(closeBtn);
closeBtn.interactive = true;
closeBtn.buttonMode = true;
closeBtn.down = function (x, y, obj) {
if (game.newCarModelWindow) {
game.newCarModelWindow.destroy();
game.newCarModelWindow = null;
}
};
win.x = 2048 / 2;
win.y = 2732 / 2;
LK.gui.center.addChild(win);
game.newCarModelWindow = win;
}
return; // Exit the function after the special upgrade
}
// If not the special case and money is sufficient for a normal upgrade:
// Deduct the upgrade cost for normal upgrades
money -= upgradeCost;
updateMoneyTxt();
// Open upgrade window (modal) on mouse/touch click
if (!game.upgradeWindow) {
var winW = 900;
var winH = 700;
var win = new Container();
// Background
var bg = LK.getAsset('stationBase', {
width: winW,
height: winH,
color: 0x222244,
anchorX: 0.5,
anchorY: 0.5
});
win.addChild(bg);
// Title
var title = new Text2("Upgrade Station", {
size: 90,
fill: 0xFFFFFF,
align: "center"
});
title.anchor.set(0.5, 0);
title.x = 0;
title.y = -winH / 2 + 60;
win.addChild(title);
// Close button
var closeBtn = new Text2("X", {
size: 80,
fill: 0xFF4444,
align: "center"
});
closeBtn.anchor.set(0.5, 0.5);
closeBtn.x = winW / 2 - 60 - 20;
closeBtn.y = -winH / 2 + 60;
win.addChild(closeBtn);
closeBtn.interactive = true;
closeBtn.buttonMode = true;
closeBtn.down = function (x, y, obj) {
if (game.upgradeWindow) {
game.upgradeWindow.destroy();
game.upgradeWindow = null;
}
};
// Placeholder for upgrade options
var info = new Text2("Upgrade options coming soon!", {
size: 60,
fill: 0xcccccc,
align: "center"
});
info.anchor.set(0.5, 0.5);
info.x = 0;
info.y = 60;
win.addChild(info);
win.x = 2048 / 2;
win.y = 2732 / 2;
LK.gui.center.addChild(win);
game.upgradeWindow = win;
}
};
// Update money text
function updateMoneyTxt() {
moneyTxt.setText('$' + money);
updateUpgradeBtn();
if (typeof updateAutoDispenserBtn === "function") updateAutoDispenserBtn();
}
// Find a free pump, returns {floor, pump} or null
function findFreePump() {
for (var f = 0; f < floors.length; f++) {
var floor = floors[f];
for (var p = 0; p < floor.pumps.length; p++) {
if (!floor.pumps[p].isBusy()) {
return {
floor: floor,
pump: floor.pumps[p],
floorIndex: f,
pumpIndex: p
};
}
}
}
return null;
}
// Spawn a car at a free pump
function spawnCar() {
var spot = findFreePump();
if (!spot) return;
// Choose car model based on unlock
var carModel = typeof extraCarModelEnabled !== "undefined" && extraCarModelEnabled && Math.random() < 0.5 ? 'car2' : 'car';
var car = new Car();
if (carModel === 'car2') {
// Replace car's graphic with car2
if (car.children && car.children.length > 0) {
car.children[0].setAsset('car2', {
anchorX: 0.5,
anchorY: 0.5
});
car.width = car.children[0].width;
car.height = car.children[0].height;
}
}
// Start off screen left
car.x = -200;
car.y = spot.floor.y - 60;
// Match pumpSpacing and pumpOffset from StationFloor (increased spacing)
var pumpSpacing = 400;
var pumpOffset = pumpSpacing * (2 - 1) / 2;
car.pumpX = spot.floor.x - pumpOffset + spot.pumpIndex * pumpSpacing;
car.pumpY = spot.floor.y - 60;
spot.pump.car = car;
game.addChild(car);
cars.push({
car: car,
pump: spot.pump
});
}
// Game update loop
game.update = function () {
// Spawn cars
carSpawnTimer++;
if (carSpawnTimer >= carSpawnInterval) {
carSpawnTimer = 0;
spawnCar();
}
// Update cars
for (var i = cars.length - 1; i >= 0; i--) {
var carObj = cars[i];
var car = carObj.car;
// Manual refuel: if car is waiting at pump, allow click to start refuel
if (car.state === 'waitingForRefuel' && !carObj.manualRefuelListenerAdded && !carObj.autoRefuel) {
car.interactive = true;
car.buttonMode = true;
car.down = function (carObj) {
return function (x, y, obj) {
// Only allow if still waiting for refuel
if (carObj.car.state === 'waitingForRefuel') {
carObj.car.state = 'refueling';
carObj.car.refuelTicks = 0;
carObj.car.interactive = false;
carObj.car.buttonMode = false;
}
};
}(carObj);
carObj.manualRefuelListenerAdded = true;
}
// If auto dispenser is purchased, auto-refuel cars
if (typeof autoDispenserEnabled !== "undefined" && autoDispenserEnabled && (car.state === 'waitingForRefuel' || car.state === 'refueling') && !carObj.autoRefuel) {
if (car.state === 'waitingForRefuel') {
car.state = 'refueling';
car.refuelTicks = 0;
car.interactive = false;
car.buttonMode = false;
}
car.refuelTicks = car.refuelTime;
carObj.autoRefuel = true;
}
// If auto dispenser is purchased, auto-refuel cars
if (typeof autoDispenserEnabled !== "undefined" && autoDispenserEnabled && car.state === 'refueling' && !carObj.autoRefuel) {
car.refuelTicks = car.refuelTime;
carObj.autoRefuel = true;
}
car.update();
// If car finished refueling, give money and set pump free
if (car.state === 'leaving' && !carObj.paid) {
var earned = 10 + 5 * (carObj.pump.parent.floorNum - 1);
if (carObj.pump.parent.floorNum === 1) {
if (earned > 5) {
earned = 5;
}
}
money += earned;
updateMoneyTxt();
carObj.paid = true;
carObj.pump.car = null;
updateUpgradeBtn();
}
// Remove car if destroyed
if (car.destroyed) {
car.destroy();
cars.splice(i, 1);
}
}
};
// Initial money
money = 50;
updateMoneyTxt();
updateUpgradeBtn(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Car class
var Car = Container.expand(function () {
var self = Container.call(this);
var carGfx = self.attachAsset('car', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = carGfx.width;
self.height = carGfx.height;
self.speed = 6 + Math.random() * 2; // px per tick
self.state = 'arriving'; // arriving, refueling, leaving
self.refuelTicks = 0;
self.refuelTime = 60 + Math.floor(Math.random() * 60); // 1-2 seconds
self.pumpX = 0;
self.pumpY = 0;
self.update = function () {
if (self.state === 'arriving') {
// Move car towards pump
var dx = self.pumpX - self.x;
var dy = self.pumpY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 10) {
self.x = self.pumpX;
self.y = self.pumpY;
// Stop at pump, but do not start refueling until clicked
self.state = 'waitingForRefuel';
self.refuelTicks = 0;
} else {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
} else if (self.state === 'refueling') {
self.refuelTicks++;
if (self.refuelTicks >= self.refuelTime) {
self.state = 'leaving';
self.leaveTargetX = 2200; // off screen right
self.leaveTargetY = self.y;
}
} else if (self.state === 'leaving') {
self.x += self.speed * 1.2;
if (self.x > 2200) {
self.destroyed = true;
}
}
};
return self;
});
// Pump class
var Pump = Container.expand(function () {
var self = Container.call(this);
var pumpGfx = self.attachAsset('pump', {
anchorX: 0.5,
anchorY: 1
});
self.width = pumpGfx.width;
self.height = pumpGfx.height;
self.car = null; // Car currently at this pump
self.isBusy = function () {
return !!self.car;
};
return self;
});
// Gas Station Floor class
var StationFloor = Container.expand(function () {
var self = Container.call(this);
self.floorNum = 1; // 1 = base, 2,3,4 = upgrades
self.pumps = [];
// Floor graphics
var floorAsset = self.attachAsset(self.floorNum === 1 ? 'stationBase' : 'stationFloor', {
anchorX: 0.5,
anchorY: 1
});
self.width = floorAsset.width;
self.height = floorAsset.height;
// Place pumps
self.initPumps = function () {
// 2 pumps per floor, increased spacing for more separation
var pumpSpacing = 400; // increased spacing for more distance between pumps
var pumpOffset = pumpSpacing * (2 - 1) / 2; // center pumps
for (var i = 0; i < 2; i++) {
var pump = new Pump();
pump.x = -pumpOffset + i * pumpSpacing;
pump.y = -10;
self.addChild(pump);
self.pumps.push(pump);
}
};
self.initPumps();
return self;
});
// Upgrade Button class
var UpgradeButton = Container.expand(function () {
var self = Container.call(this);
var btnGfx = self.attachAsset('upgradeBtn', {
anchorX: 0.5,
anchorY: 0.5
});
// Move the icon to the front (after btnGfx, so it is above the button background)
var icon = self.attachAsset('upgradeIcon', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0
});
// Do NOT add the label, so only the icon is visible
self.setEnabled = function (enabled) {
btnGfx.alpha = enabled ? 1 : 0.5;
self.interactive = enabled;
self.buttonMode = enabled;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a2a3a
});
/****
* Game Code
****/
// new car model
// Upgrade icon
// Upgrade button
// Car
// Pump
// Gas station floor (for floors 2-4)
// Gas station base (floor 1)
// Game state variables
var money = 0;
var floors = [];
var cars = [];
var maxFloors = 4;
var floorCount = 2; // Start with 2 floors
var carSpawnTimer = 0;
var carSpawnInterval = 90; // ticks between car spawns
var upgradeCost = 100;
var upgradeBtn;
var moneyTxt;
var floorYStart = 2200; // y position of base floor
var floorSpacing = 400; // increased vertical space between floors for stacking
// Money display
moneyTxt = new Text2('$0', {
size: 100,
fill: 0xFFFFFF
});
moneyTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(moneyTxt);
// Place floors
function placeFloors() {
// Remove all floors
for (var i = 0; i < floors.length; i++) {
floors[i].destroy();
}
floors = [];
// Define the starting X position for the first station
var startX = 2048 / 2;
// Define the spacing between stations when placing new ones
var stationSpacing = 900; // Adjust as needed for visual separation
for (var f = 0; f < floorCount; f++) {
var floor = new StationFloor();
floor.floorNum = f + 1;
// Set correct asset for base or upper floors
var assetId = f === 0 ? 'stationBase' : 'stationFloor';
floor.children[0].setAsset(assetId);
// Position floors horizontally based on floor number
// The first two floors are stacked, subsequent floors go to the left
if (f < 2) {
floor.x = startX;
// Stack floors vertically with space between them
floor.y = floorYStart - f * floorSpacing;
} else {
// New floors go to the left of the initial two floors
floor.x = startX - stationSpacing * (Math.ceil((f + 1) / 2) - 1); // Position new stations to the left
// Alternate y position for stacked floors in new stations
floor.y = floorYStart - f % 2 * floorSpacing;
}
game.addChild(floor);
floors.push(floor);
}
// --- Place a clickable button right above the first gas station ---
if (typeof aboveFirstStationBtn !== "undefined" && aboveFirstStationBtn) {
aboveFirstStationBtn.destroy();
aboveFirstStationBtn = null;
}
aboveFirstStationBtn = new UpgradeButton();
aboveFirstStationBtn.setEnabled(true);
aboveFirstStationBtn.interactive = true;
aboveFirstStationBtn.buttonMode = true;
// Enlarge the button
aboveFirstStationBtn.scaleX = 1.4;
aboveFirstStationBtn.scaleY = 1.4;
aboveFirstStationBtn.x = 2048 / 2;
if (floors.length > 0) {
// Move button even higher above the first floor (base station)
aboveFirstStationBtn.y = floors[0].y - floors[0].height - 1200;
} else {
aboveFirstStationBtn.y = floorYStart - 200 - 1200;
}
aboveFirstStationBtn.down = function (x, y, obj) {
// Open a window (modal) on mouse/touch click
if (!game.specialWindow) {
var winW = 900;
var winH = 700;
var win = new Container();
// Background
var bg = LK.getAsset('stationBase', {
width: winW,
height: winH,
color: 0x224444,
anchorX: 0.5,
anchorY: 0.5
});
win.addChild(bg);
// Title
var title = new Text2("Special Window", {
size: 90,
fill: 0xFFFFFF,
align: "center"
});
title.anchor.set(0.5, 0);
title.x = 0;
title.y = -winH / 2 + 60;
win.addChild(title);
// Close button
var closeBtn = new Text2("X", {
size: 80,
fill: 0xFF4444,
align: "center"
});
closeBtn.anchor.set(0.5, 0.5);
closeBtn.x = winW / 2 - 60 - 20;
closeBtn.y = -winH / 2 + 60;
win.addChild(closeBtn);
closeBtn.interactive = true;
closeBtn.buttonMode = true;
closeBtn.down = function (x, y, obj) {
if (game.specialWindow) {
game.specialWindow.destroy();
game.specialWindow = null;
}
};
// Placeholder for content
var info = new Text2("Special window content!", {
size: 60,
fill: 0xcccccc,
align: "center"
});
info.anchor.set(0.5, 0.5);
info.x = 0;
info.y = 60;
win.addChild(info);
win.x = 2048 / 2;
win.y = 2732 / 2;
LK.gui.center.addChild(win);
game.specialWindow = win;
}
// Animate the button as before
tween(aboveFirstStationBtn, {
scaleX: 1.2 * 1.4,
scaleY: 1.2 * 1.4
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(aboveFirstStationBtn, {
scaleX: 1.4,
scaleY: 1.4
}, {
duration: 100,
easing: tween.easeIn
});
}
});
};
game.addChild(aboveFirstStationBtn);
}
placeFloors();
// Upgrade button
upgradeBtn = new UpgradeButton();
// Restore upgrade button color to original (dark)
if (upgradeBtn.children && upgradeBtn.children.length > 0) {
// The first child is the button graphic
upgradeBtn.children[0].setAsset('upgradeBtn', {
color: 0x050410
}); // original dark color
}
// Restore upgrade icon position to previous (centered)
if (upgradeBtn.children && upgradeBtn.children.length > 1) {
// The second child is the icon
upgradeBtn.children[1].x = 0;
upgradeBtn.children[1].y = 0;
}
upgradeBtn.x = 2048 / 2;
upgradeBtn.y = moneyTxt.y + moneyTxt.height + 60; // 60px below the money display
upgradeBtn.setEnabled(true);
upgradeBtn.interactive = true;
upgradeBtn.buttonMode = true;
upgradeBtn.down = function (x, y, obj) {
// Open upgrade window (modal) on mouse/touch click
if (!game.upgradeWindow) {
var winW = 900;
var winH = 700;
var win = new Container();
// Background
var bg = LK.getAsset('stationBase', {
width: winW,
height: winH,
color: 0x222244,
anchorX: 0.5,
anchorY: 0.5
});
win.addChild(bg);
// Title
var title = new Text2("Upgrade Station", {
size: 90,
fill: 0xFFFFFF,
align: "center"
});
title.anchor.set(0.5, 0);
title.x = 0;
title.y = -winH / 2 + 60;
win.addChild(title);
// Close button
var closeBtn = new Text2("X", {
size: 80,
fill: 0xFF4444,
align: "center"
});
closeBtn.anchor.set(0.5, 0.5);
closeBtn.x = winW / 2 - 60 - 20;
closeBtn.y = -winH / 2 + 60;
win.addChild(closeBtn);
closeBtn.interactive = true;
closeBtn.buttonMode = true;
closeBtn.down = function (x, y, obj) {
if (game.upgradeWindow) {
game.upgradeWindow.destroy();
game.upgradeWindow = null;
}
};
// Placeholder for upgrade options
var info = new Text2("Upgrade options coming soon!", {
size: 60,
fill: 0xcccccc,
align: "center"
});
info.anchor.set(0.5, 0.5);
info.x = 0;
info.y = 60;
win.addChild(info);
win.x = 2048 / 2;
win.y = 2732 / 2;
LK.gui.center.addChild(win);
game.upgradeWindow = win;
}
};
// Place upgrade button below money display in gui.top
LK.gui.top.addChild(upgradeBtn);
upgradeBtn.x = 2048 / 2;
upgradeBtn.y = moneyTxt.y + moneyTxt.height + 60; // 60px below the money display
// Automatic Fuel Dispenser Button
var autoDispenserBtnCost = 250;
var autoDispenserEnabled = false;
var autoDispenserBtn = new UpgradeButton();
autoDispenserBtn.x = 2048 / 2;
autoDispenserBtn.y = 2732 - 320;
autoDispenserBtn.setEnabled(money >= autoDispenserBtnCost && !autoDispenserEnabled);
LK.gui.bottom.addChild(autoDispenserBtn);
// Update auto dispenser button state
function updateAutoDispenserBtn() {
if (!autoDispenserEnabled) {
autoDispenserBtn.setEnabled(money >= autoDispenserBtnCost);
} else {
autoDispenserBtn.setEnabled(false);
}
}
updateAutoDispenserBtn();
// Handle auto dispenser button press
autoDispenserBtn.down = function (x, y, obj) {
if (!autoDispenserEnabled && money >= autoDispenserBtnCost) {
money -= autoDispenserBtnCost;
autoDispenserEnabled = true;
updateMoneyTxt();
updateAutoDispenserBtn();
// Animate button
tween(autoDispenserBtn, {
scaleX: 1.15,
scaleY: 1.15
}, {
duration: 120,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(autoDispenserBtn, {
scaleX: 1,
scaleY: 1
}, {
duration: 120,
easing: tween.easeIn
});
}
});
}
};
// Update upgrade button label
function updateUpgradeBtn() {
if (floorCount < maxFloors) {
upgradeBtn.setEnabled(money >= upgradeCost);
} else {
upgradeBtn.setEnabled(false);
}
}
updateUpgradeBtn();
// Handle upgrade button press
upgradeBtn.down = function (x, y, obj) {
// Check if the player has enough money for *any* upgrade
if (money < upgradeCost) {
// Show a red message below the upgrade button for 4 seconds, and reset timer if pressed again
if (!game.notEnoughMoneyLabel) {
game.notEnoughMoneyLabel = new Text2("Not enough money", {
size: 60,
fill: 0xFF4444,
align: "center"
});
game.notEnoughMoneyLabel.anchor.set(0.5, 0);
// Place below the upgrade button (add 40px for spacing)
game.notEnoughMoneyLabel.x = upgradeBtn.x;
game.notEnoughMoneyLabel.y = upgradeBtn.y + upgradeBtn.height / 2 + 40;
LK.gui.top.addChild(game.notEnoughMoneyLabel);
}
// Always reset the timer if pressed again
if (game.notEnoughMoneyTimeout) {
LK.clearTimeout(game.notEnoughMoneyTimeout);
game.notEnoughMoneyTimeout = null;
}
game.notEnoughMoneyLabel.visible = true;
// Hide after 4 seconds
game.notEnoughMoneyTimeout = LK.setTimeout(function () {
if (game.notEnoughMoneyLabel) {
game.notEnoughMoneyLabel.visible = false;
}
game.notEnoughMoneyTimeout = null;
}, 4000);
return;
}
// If money is sufficient, first check for the special upgrade condition (money exactly 100)
if (money === 100) {
// Deduct the upgrade cost (set to 100 for this special case)
money -= 100; // Assuming 100 is the cost for the first special upgrade
updateMoneyTxt();
// Show a green message below the upgrade button for 4 seconds, and reset timer if pressed again
if (!game.upgradeSuccessLabel) {
game.upgradeSuccessLabel = new Text2("Upgrade successful!", {
size: 60,
fill: 0x44FF44,
align: "center"
});
game.upgradeSuccessLabel.anchor.set(0.5, 0);
// Place below the upgrade button (add 40px for spacing)
game.upgradeSuccessLabel.x = upgradeBtn.x;
game.upgradeSuccessLabel.y = upgradeBtn.y + upgradeBtn.height / 2 + 40;
LK.gui.top.addChild(game.upgradeSuccessLabel);
}
// Always reset the timer if pressed again
if (game.upgradeSuccessTimeout) {
LK.clearTimeout(game.upgradeSuccessTimeout);
game.upgradeSuccessTimeout = null;
}
game.upgradeSuccessLabel.visible = true;
// Hide after 4 seconds
game.upgradeSuccessTimeout = LK.setTimeout(function () {
if (game.upgradeSuccessLabel) {
game.upgradeSuccessLabel.visible = false;
}
game.upgradeSuccessTimeout = null;
}, 4000);
// Add new floors and pumps for the special upgrade
// Check if we are at the initial state and money is 100 for the special upgrade
// We should only add floors up to 4 total
if (floorCount < maxFloors) {
floorCount = Math.min(floorCount + 2, maxFloors); // Add 2 floors, but not exceeding maxFloors
placeFloors(); // Re-place all floors including the new ones
updateUpgradeBtn();
}
// Enable new car model
if (typeof extraCarModelEnabled === "undefined") {
extraCarModelEnabled = true;
}
// Optionally, show a message for the new car model
if (!game.newCarModelWindow) {
var winW = 700;
var winH = 350;
var win = new Container();
var bg = LK.getAsset('stationBase', {
width: winW,
height: winH,
color: 0x224444,
anchorX: 0.5,
anchorY: 0.5
});
win.addChild(bg);
var title = new Text2("New car model unlocked!", {
size: 70,
fill: 0x44FF44,
align: "center"
});
title.anchor.set(0.5, 0.5);
title.x = 0;
title.y = 0;
win.addChild(title);
var closeBtn = new Text2("OK", {
size: 60,
fill: 0xFFFFFF,
align: "center"
});
closeBtn.anchor.set(0.5, 0.5);
closeBtn.x = 0;
closeBtn.y = winH / 2 - 60;
win.addChild(closeBtn);
closeBtn.interactive = true;
closeBtn.buttonMode = true;
closeBtn.down = function (x, y, obj) {
if (game.newCarModelWindow) {
game.newCarModelWindow.destroy();
game.newCarModelWindow = null;
}
};
win.x = 2048 / 2;
win.y = 2732 / 2;
LK.gui.center.addChild(win);
game.newCarModelWindow = win;
}
return; // Exit the function after the special upgrade
}
// If not the special case and money is sufficient for a normal upgrade:
// Deduct the upgrade cost for normal upgrades
money -= upgradeCost;
updateMoneyTxt();
// Open upgrade window (modal) on mouse/touch click
if (!game.upgradeWindow) {
var winW = 900;
var winH = 700;
var win = new Container();
// Background
var bg = LK.getAsset('stationBase', {
width: winW,
height: winH,
color: 0x222244,
anchorX: 0.5,
anchorY: 0.5
});
win.addChild(bg);
// Title
var title = new Text2("Upgrade Station", {
size: 90,
fill: 0xFFFFFF,
align: "center"
});
title.anchor.set(0.5, 0);
title.x = 0;
title.y = -winH / 2 + 60;
win.addChild(title);
// Close button
var closeBtn = new Text2("X", {
size: 80,
fill: 0xFF4444,
align: "center"
});
closeBtn.anchor.set(0.5, 0.5);
closeBtn.x = winW / 2 - 60 - 20;
closeBtn.y = -winH / 2 + 60;
win.addChild(closeBtn);
closeBtn.interactive = true;
closeBtn.buttonMode = true;
closeBtn.down = function (x, y, obj) {
if (game.upgradeWindow) {
game.upgradeWindow.destroy();
game.upgradeWindow = null;
}
};
// Placeholder for upgrade options
var info = new Text2("Upgrade options coming soon!", {
size: 60,
fill: 0xcccccc,
align: "center"
});
info.anchor.set(0.5, 0.5);
info.x = 0;
info.y = 60;
win.addChild(info);
win.x = 2048 / 2;
win.y = 2732 / 2;
LK.gui.center.addChild(win);
game.upgradeWindow = win;
}
};
// Update money text
function updateMoneyTxt() {
moneyTxt.setText('$' + money);
updateUpgradeBtn();
if (typeof updateAutoDispenserBtn === "function") updateAutoDispenserBtn();
}
// Find a free pump, returns {floor, pump} or null
function findFreePump() {
for (var f = 0; f < floors.length; f++) {
var floor = floors[f];
for (var p = 0; p < floor.pumps.length; p++) {
if (!floor.pumps[p].isBusy()) {
return {
floor: floor,
pump: floor.pumps[p],
floorIndex: f,
pumpIndex: p
};
}
}
}
return null;
}
// Spawn a car at a free pump
function spawnCar() {
var spot = findFreePump();
if (!spot) return;
// Choose car model based on unlock
var carModel = typeof extraCarModelEnabled !== "undefined" && extraCarModelEnabled && Math.random() < 0.5 ? 'car2' : 'car';
var car = new Car();
if (carModel === 'car2') {
// Replace car's graphic with car2
if (car.children && car.children.length > 0) {
car.children[0].setAsset('car2', {
anchorX: 0.5,
anchorY: 0.5
});
car.width = car.children[0].width;
car.height = car.children[0].height;
}
}
// Start off screen left
car.x = -200;
car.y = spot.floor.y - 60;
// Match pumpSpacing and pumpOffset from StationFloor (increased spacing)
var pumpSpacing = 400;
var pumpOffset = pumpSpacing * (2 - 1) / 2;
car.pumpX = spot.floor.x - pumpOffset + spot.pumpIndex * pumpSpacing;
car.pumpY = spot.floor.y - 60;
spot.pump.car = car;
game.addChild(car);
cars.push({
car: car,
pump: spot.pump
});
}
// Game update loop
game.update = function () {
// Spawn cars
carSpawnTimer++;
if (carSpawnTimer >= carSpawnInterval) {
carSpawnTimer = 0;
spawnCar();
}
// Update cars
for (var i = cars.length - 1; i >= 0; i--) {
var carObj = cars[i];
var car = carObj.car;
// Manual refuel: if car is waiting at pump, allow click to start refuel
if (car.state === 'waitingForRefuel' && !carObj.manualRefuelListenerAdded && !carObj.autoRefuel) {
car.interactive = true;
car.buttonMode = true;
car.down = function (carObj) {
return function (x, y, obj) {
// Only allow if still waiting for refuel
if (carObj.car.state === 'waitingForRefuel') {
carObj.car.state = 'refueling';
carObj.car.refuelTicks = 0;
carObj.car.interactive = false;
carObj.car.buttonMode = false;
}
};
}(carObj);
carObj.manualRefuelListenerAdded = true;
}
// If auto dispenser is purchased, auto-refuel cars
if (typeof autoDispenserEnabled !== "undefined" && autoDispenserEnabled && (car.state === 'waitingForRefuel' || car.state === 'refueling') && !carObj.autoRefuel) {
if (car.state === 'waitingForRefuel') {
car.state = 'refueling';
car.refuelTicks = 0;
car.interactive = false;
car.buttonMode = false;
}
car.refuelTicks = car.refuelTime;
carObj.autoRefuel = true;
}
// If auto dispenser is purchased, auto-refuel cars
if (typeof autoDispenserEnabled !== "undefined" && autoDispenserEnabled && car.state === 'refueling' && !carObj.autoRefuel) {
car.refuelTicks = car.refuelTime;
carObj.autoRefuel = true;
}
car.update();
// If car finished refueling, give money and set pump free
if (car.state === 'leaving' && !carObj.paid) {
var earned = 10 + 5 * (carObj.pump.parent.floorNum - 1);
if (carObj.pump.parent.floorNum === 1) {
if (earned > 5) {
earned = 5;
}
}
money += earned;
updateMoneyTxt();
carObj.paid = true;
carObj.pump.car = null;
updateUpgradeBtn();
}
// Remove car if destroyed
if (car.destroyed) {
car.destroy();
cars.splice(i, 1);
}
}
};
// Initial money
money = 50;
updateMoneyTxt();
updateUpgradeBtn();