User prompt
Place a clickable button right above the first gas station
User prompt
Place the Upgrade button below the area where the money is displayed.
User prompt
Increase the spacing between the gas stations that are side by side so they’re not too close to each other.
User prompt
Increase the vertical space between the top and bottom gas stations. They should be stacked, not side by side, with some space between them.
User prompt
The fuel filling spots should be placed closer together, with minimal spacing between them.
User prompt
Leave some space between the gas stations; they shouldn’t be placed right next to each other.
User prompt
upgrad icon fix to same before
User prompt
Just gather what I told you, correct any mistakes, and fix everything right now.
User prompt
I cant se can you change anothe color button for me i can see
User prompt
why i cant click to upgrad button
User prompt
I want to open the upgrade window by clicking the upgrade button with the mouse.
User prompt
Do upgrad button red
User prompt
Place the upgrade button below the money display. When I click the button, a window should open. We will add the upgrade options inside this window later.
User prompt
At the beginning of the game, the level 1 gas station should earn a maximum of 5 money per car.
User prompt
At the beginning of the game, the level 1 gas station should earn at least 5 money from each car.
User prompt
Move to uppgrade button to under money
User prompt
I want the upgrad button under the money
User prompt
There should be a blue button below the gas station, and it should say "Upgrade" on it.
User prompt
When cars arrive at the gas station, they need to stop, and I have to click with the mouse to fill them up with fuel.
User prompt
When cars arrive, I click with the mouse to fill them up with fuel. The cars line up one after another. Later, through the upgrade system, players can place an automatic fuel dispenser. Once it's purchased, the fuel will be automatically filled into the cars.
Code edit (1 edits merged)
Please save this source code
User prompt
Gas Station Tycoon: Stack & Serve
Initial prompt
My game will be a 2D tycoon game. There will be a gas station where cars come to refuel. I will earn money this way. At the bottom of the game screen, there will be a button. When my money reaches a certain amount, I will be able to upgrade the gas station by pressing the button. At first, the gas station will have two floors, and it will keep growing like this until it reaches four floors.
/**** * 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();