/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
resources: 0,
plants: 0,
creatures: 0,
structures: 0,
lastTimestamp: undefined,
upgrades: {},
biomes: {
forest: {
unlocked: true
}
},
stats: {
totalResources: 0
}
});
/****
* Classes
****/
var Biome = Container.expand(function (name, color) {
var self = Container.call(this);
var biomeGraphic = self.attachAsset('biome', {
anchorX: 0.5,
anchorY: 0.5,
tint: color || 0x81C784
});
var nameText = new Text2(name, {
size: 50,
fill: 0xFFFFFF
});
nameText.anchor.set(0.5, 0.5);
self.addChild(nameText);
self.unlock = function () {
LK.getSound('unlock').play();
tween(self, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 300
});
}
});
};
self.down = function (x, y, obj) {
// Set current biome
if (storage.biomes[name] && storage.biomes[name].unlocked) {
LK.getSound('click').play();
currentBiome = name;
updateBiomeSelection();
}
};
return self;
});
var Button = Container.expand(function (text, cost, callback) {
var self = Container.call(this);
var buttonGraphic = self.attachAsset('button', {
anchorX: 0.5,
anchorY: 0.5
});
var buttonText = new Text2(text, {
size: 40,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
buttonText.y = -15;
self.addChild(buttonText);
var costText = new Text2("Cost: " + cost, {
size: 30,
fill: 0xFFFFFF
});
costText.anchor.set(0.5, 0.5);
costText.y = 20;
self.addChild(costText);
self.cost = cost;
self.enabled = true;
self.updateCost = function (newCost) {
self.cost = newCost;
costText.setText("Cost: " + newCost);
};
self.setEnabled = function (enabled) {
self.enabled = enabled;
buttonGraphic.alpha = enabled ? 1.0 : 0.5;
};
self.down = function (x, y, obj) {
if (self.enabled) {
LK.getSound('click').play();
tween(self, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
callback();
}
};
return self;
});
var Plot = Container.expand(function () {
var self = Container.call(this);
var plotGraphic = self.attachAsset('plot', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
self.type = null;
self.level = 1;
self.progress = 0;
self.maxProgress = 100;
self.productive = false;
self.resourceRate = 1;
// Create progress bar (initially hidden)
var progressBarBg = self.attachAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
y: plotGraphic.height / 2 + 30
});
progressBarBg.alpha = 0;
var progressBar = self.attachAsset('progressBar', {
anchorX: 0,
anchorY: 0.5,
x: -progressBarBg.width / 2 + 10,
y: progressBarBg.y,
width: 0
});
progressBar.alpha = 0;
var entityGraphic = null;
// Text for level display
var levelText = new Text2('', {
size: 40,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0.5);
levelText.y = -plotGraphic.height / 2 - 30;
self.addChild(levelText);
levelText.alpha = 0;
self.setType = function (type) {
self.type = type;
// Clear previous entity graphic if it exists
if (entityGraphic) {
self.removeChild(entityGraphic);
}
// Set new entity graphic based on type
switch (type) {
case 'plant':
entityGraphic = self.attachAsset('plant', {
anchorX: 0.5,
anchorY: 1.0,
y: 30
});
self.resourceRate = 1 * self.level;
break;
case 'creature':
entityGraphic = self.attachAsset('creature', {
anchorX: 0.5,
anchorY: 0.5,
y: 0
});
self.resourceRate = 2 * self.level;
break;
case 'structure':
entityGraphic = self.attachAsset('structure', {
anchorX: 0.5,
anchorY: 0.5,
y: 0
});
self.resourceRate = 3 * self.level;
break;
default:
// Empty plot
entityGraphic = null;
self.resourceRate = 0;
}
// Show progress elements if we have a type
if (type) {
progressBarBg.alpha = 1;
progressBar.alpha = 1;
levelText.alpha = 1;
levelText.setText("Lvl " + self.level);
} else {
progressBarBg.alpha = 0;
progressBar.alpha = 0;
levelText.alpha = 0;
}
self.updateProgressBar();
};
self.updateProgressBar = function () {
var percentage = self.progress / self.maxProgress;
progressBar.width = (progressBarBg.width - 20) * percentage;
};
self.upgrade = function () {
if (self.type) {
self.level++;
self.resourceRate = self.level * (self.type === 'plant' ? 1 : self.type === 'creature' ? 2 : 3);
levelText.setText("Lvl " + self.level);
// Visual effect for upgrade
tween(entityGraphic, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
onFinish: function onFinish() {
tween(entityGraphic, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
LK.getSound('unlock').play();
}
};
self.update = function (deltaTime) {
if (self.type && !self.productive) {
self.progress += deltaTime * 0.05 * self.level;
if (self.progress >= self.maxProgress) {
self.progress = self.maxProgress;
self.productive = true;
// Pulse the entity to indicate it's ready
self.pulse();
}
self.updateProgressBar();
}
};
self.pulse = function () {
if (entityGraphic) {
tween(entityGraphic, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(entityGraphic, {
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: self.pulse
});
}
});
}
};
self.collect = function () {
if (self.productive) {
var gainedResources = self.resourceRate;
resources += gainedResources;
totalResourcesGained += gainedResources;
// Reset progress
self.progress = 0;
self.productive = false;
self.updateProgressBar();
// Stop pulsing
if (entityGraphic) {
tween.stop(entityGraphic, {
scaleX: true,
scaleY: true
});
entityGraphic.scaleX = 1;
entityGraphic.scaleY = 1;
}
// Spawn resource particle
spawnResourceParticle(self.x, self.y);
return gainedResources;
}
return 0;
};
self.down = function (x, y, obj) {
if (self.type && self.productive) {
LK.getSound('click').play();
self.collect();
}
};
return self;
});
var ResourceParticle = Container.expand(function () {
var self = Container.call(this);
var resourceGraphic = self.attachAsset('resource', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
self.setup = function (startX, startY, targetX, targetY) {
self.x = startX;
self.y = startY;
// Animate to target
tween(self, {
x: targetX,
y: targetY,
alpha: 0.5
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.destroy();
var index = resourceParticles.indexOf(self);
if (index !== -1) {
resourceParticles.splice(index, 1);
}
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1B5E20
});
/****
* Game Code
****/
// Constants
var PLOT_ROWS = 3;
var PLOT_COLS = 3;
var PLOT_PADDING = 50;
var PLOT_SIZE = 300;
// Game state variables
var resources = storage.resources || 0;
var totalResourcesGained = storage.stats.totalResources || 0;
var plots = [];
var resourceParticles = [];
var currentBiome = "forest";
var biomes = {};
// Biome data
var biomeData = {
"forest": {
color: 0x81C784,
unlockCost: 0,
plantMultiplier: 1,
creatureMultiplier: 1,
structureMultiplier: 1
},
"desert": {
color: 0xFFD54F,
unlockCost: 1000,
plantMultiplier: 0.8,
creatureMultiplier: 1.2,
structureMultiplier: 1.3
},
"ocean": {
color: 0x4FC3F7,
unlockCost: 5000,
plantMultiplier: 1.3,
creatureMultiplier: 1.5,
structureMultiplier: 0.9
},
"mountain": {
color: 0x90A4AE,
unlockCost: 20000,
plantMultiplier: 0.7,
creatureMultiplier: 0.8,
structureMultiplier: 2.0
}
};
// UI Elements
var resourcesText;
var plantsCountText;
var creaturesCountText;
var structuresCountText;
var rateText;
var plantButton;
var creatureButton;
var structureButton;
var biomePanel;
// Setup game
function setupGame() {
// Play background music
LK.playMusic('gameMusic');
createUI();
createPlots();
createBiomePanel();
// Initialize from storage if needed
if (storage.plants > 0 || storage.creatures > 0 || storage.structures > 0) {
// Re-create entities based on stored data
var plotIndex = 0;
for (var i = 0; i < storage.plants; i++) {
if (plotIndex < plots.length) {
plots[plotIndex].setType('plant');
plotIndex++;
}
}
for (var i = 0; i < storage.creatures; i++) {
if (plotIndex < plots.length) {
plots[plotIndex].setType('creature');
plotIndex++;
}
}
for (var i = 0; i < storage.structures; i++) {
if (plotIndex < plots.length) {
plots[plotIndex].setType('structure');
plotIndex++;
}
}
}
// Process offline progress
var now = Date.now();
var lastTime = storage.lastTimestamp || now;
var offlineSeconds = Math.floor((now - lastTime) / 1000);
if (offlineSeconds > 10) {
processOfflineProgress(offlineSeconds);
}
updateUI();
}
function createUI() {
// Resources counter at top
resourcesText = new Text2("Resources: 0", {
size: 70,
fill: 0xFFFFFF
});
resourcesText.anchor.set(0.5, 0);
LK.gui.top.addChild(resourcesText);
resourcesText.y = 50;
// Entity counters
var countersContainer = new Container();
LK.gui.left.addChild(countersContainer);
countersContainer.x = 150;
countersContainer.y = 300;
plantsCountText = new Text2("Plants: 0", {
size: 40,
fill: 0xFFFFFF
});
plantsCountText.anchor.set(0, 0.5);
countersContainer.addChild(plantsCountText);
creaturesCountText = new Text2("Creatures: 0", {
size: 40,
fill: 0xFFFFFF
});
creaturesCountText.anchor.set(0, 0.5);
creaturesCountText.y = 60;
countersContainer.addChild(creaturesCountText);
structuresCountText = new Text2("Structures: 0", {
size: 40,
fill: 0xFFFFFF
});
structuresCountText.anchor.set(0, 0.5);
structuresCountText.y = 120;
countersContainer.addChild(structuresCountText);
rateText = new Text2("Production: 0/sec", {
size: 40,
fill: 0xFFFFFF
});
rateText.anchor.set(0, 0.5);
rateText.y = 180;
countersContainer.addChild(rateText);
// Action buttons
var buttonsContainer = new Container();
LK.gui.right.addChild(buttonsContainer);
buttonsContainer.x = -150;
buttonsContainer.y = 300;
plantButton = new Button("Add Plant", 10, function () {
if (resources >= plantButton.cost) {
resources -= plantButton.cost;
addEntity('plant');
storage.plants++;
// Increase cost for next plant
plantButton.updateCost(Math.floor(10 * Math.pow(1.2, storage.plants)));
updateUI();
}
});
buttonsContainer.addChild(plantButton);
creatureButton = new Button("Add Creature", 50, function () {
if (resources >= creatureButton.cost) {
resources -= creatureButton.cost;
addEntity('creature');
storage.creatures++;
// Increase cost for next creature
creatureButton.updateCost(Math.floor(50 * Math.pow(1.3, storage.creatures)));
updateUI();
}
});
creatureButton.y = 120;
buttonsContainer.addChild(creatureButton);
structureButton = new Button("Add Structure", 200, function () {
if (resources >= structureButton.cost) {
resources -= structureButton.cost;
addEntity('structure');
storage.structures++;
// Increase cost for next structure
structureButton.updateCost(Math.floor(200 * Math.pow(1.4, storage.structures)));
updateUI();
}
});
structureButton.y = 240;
buttonsContainer.addChild(structureButton);
// Set initial costs based on storage
plantButton.updateCost(Math.floor(10 * Math.pow(1.2, storage.plants)));
creatureButton.updateCost(Math.floor(50 * Math.pow(1.3, storage.creatures)));
structureButton.updateCost(Math.floor(200 * Math.pow(1.4, storage.structures)));
}
function createPlots() {
var totalWidth = PLOT_COLS * PLOT_SIZE + (PLOT_COLS - 1) * PLOT_PADDING;
var totalHeight = PLOT_ROWS * PLOT_SIZE + (PLOT_ROWS - 1) * PLOT_PADDING;
var startX = (2048 - totalWidth) / 2 + PLOT_SIZE / 2;
var startY = (2732 - totalHeight) / 2 + PLOT_SIZE / 2;
for (var row = 0; row < PLOT_ROWS; row++) {
for (var col = 0; col < PLOT_COLS; col++) {
var plot = new Plot();
plot.x = startX + col * (PLOT_SIZE + PLOT_PADDING);
plot.y = startY + row * (PLOT_SIZE + PLOT_PADDING);
game.addChild(plot);
plots.push(plot);
}
}
}
function createBiomePanel() {
biomePanel = new Container();
game.addChild(biomePanel);
biomePanel.y = 2732 - 150;
var biomeX = 2048 / 2 - Object.keys(biomeData).length * 150;
// Create biome buttons
Object.keys(biomeData).forEach(function (biomeName, index) {
var biomeObj = new Biome(biomeName, biomeData[biomeName].color);
biomeObj.x = biomeX + index * 300;
// Initialize biome in storage if needed
if (!storage.biomes[biomeName]) {
storage.biomes[biomeName] = {
unlocked: biomeName === "forest"
};
}
biomes[biomeName] = biomeObj;
biomePanel.addChild(biomeObj);
// If not unlocked, show lock indicator
if (!storage.biomes[biomeName].unlocked) {
var lockText = new Text2("🔒", {
size: 60,
fill: 0xFFFFFF
});
lockText.anchor.set(0.5, 0.5);
lockText.y = -40;
biomeObj.addChild(lockText);
var costText = new Text2(biomeData[biomeName].unlockCost, {
size: 30,
fill: 0xFFFFFF
});
costText.anchor.set(0.5, 0.5);
costText.y = 40;
biomeObj.addChild(costText);
}
});
updateBiomeSelection();
}
function updateBiomeSelection() {
Object.keys(biomes).forEach(function (biomeName) {
var biome = biomes[biomeName];
biome.alpha = biomeName === currentBiome ? 1.0 : 0.6;
biome.scale.set(biomeName === currentBiome ? 1.1 : 1.0);
});
}
function addEntity(type) {
// Find first empty plot
for (var i = 0; i < plots.length; i++) {
if (!plots[i].type) {
plots[i].setType(type);
LK.getSound('unlock').play();
return true;
}
}
return false;
}
function spawnResourceParticle(startX, startY) {
var particle = new ResourceParticle();
particle.setup(startX, startY, resourcesText.parent.toGlobal(resourcesText.position).x, resourcesText.parent.toGlobal(resourcesText.position).y);
game.addChild(particle);
resourceParticles.push(particle);
}
function updateUI() {
resourcesText.setText("Resources: " + Math.floor(resources));
plantsCountText.setText("Plants: " + storage.plants);
creaturesCountText.setText("Creatures: " + storage.creatures);
structuresCountText.setText("Structures: " + storage.structures);
// Calculate production rate
var rate = 0;
plots.forEach(function (plot) {
if (plot.type && plot.productive) {
rate += plot.resourceRate;
}
});
rateText.setText("Production: " + rate + "/sec");
// Enable/disable buttons based on resources
plantButton.setEnabled(resources >= plantButton.cost);
creatureButton.setEnabled(resources >= creatureButton.cost);
structureButton.setEnabled(resources >= structureButton.cost);
// Check for unlockable biomes
Object.keys(biomeData).forEach(function (biomeName) {
if (!storage.biomes[biomeName].unlocked && resources >= biomeData[biomeName].unlockCost) {
storage.biomes[biomeName].unlocked = true;
biomes[biomeName].unlock();
// Remove lock indicator
biomes[biomeName].children.forEach(function (child) {
if (child instanceof Text2) {
biomes[biomeName].removeChild(child);
}
});
}
});
}
function processOfflineProgress(seconds) {
// Calculate offline earnings
var offlineRate = 0;
var plantCount = storage.plants;
var creatureCount = storage.creatures;
var structureCount = storage.structures;
if (plantCount + creatureCount + structureCount > 0) {
// Simple calculation: each entity produces its base rate per second
offlineRate = (plantCount * 1 + creatureCount * 2 + structureCount * 3) * 0.5; // Reduce offline earnings to 50%
var offlineEarnings = Math.floor(offlineRate * seconds);
resources += offlineEarnings;
totalResourcesGained += offlineEarnings;
// Show offline earnings message
var offlineText = new Text2("You earned " + offlineEarnings + " resources while away!", {
size: 60,
fill: 0xFFFFFF
});
offlineText.anchor.set(0.5, 0.5);
offlineText.x = 2048 / 2;
offlineText.y = 2732 / 2;
game.addChild(offlineText);
// Fade out the message
LK.setTimeout(function () {
tween(offlineText, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
game.removeChild(offlineText);
}
});
}, 3000);
}
}
// Setup game when loaded
setupGame();
// Game update function
var lastUpdateTime = Date.now();
game.update = function () {
// Calculate delta time
var now = Date.now();
var deltaTime = now - lastUpdateTime;
lastUpdateTime = now;
// Update all plots
plots.forEach(function (plot) {
plot.update(deltaTime);
});
// Auto-collect from productive plots every 3 seconds
if (LK.ticks % 180 === 0) {
var collected = 0;
plots.forEach(function (plot) {
if (plot.productive) {
collected += plot.collect();
}
});
if (collected > 0) {
totalResourcesGained += collected;
}
}
// Update storage periodically
if (LK.ticks % 60 === 0) {
storage.resources = resources;
storage.lastTimestamp = Date.now();
storage.stats.totalResources = totalResourcesGained;
}
// Update UI every 10 ticks
if (LK.ticks % 10 === 0) {
updateUI();
}
// Check for milestone achievements
if (LK.ticks % 300 === 0) {
checkMilestones();
}
};
function checkMilestones() {
var milestones = [{
resources: 1000,
message: "Your empire is growing!"
}, {
resources: 10000,
message: "Your ecosystem is thriving!"
}, {
resources: 100000,
message: "Your empire is becoming legendary!"
}];
milestones.forEach(function (milestone) {
if (totalResourcesGained >= milestone.resources && (!storage.milestones || !storage.milestones[milestone.resources])) {
// Store milestone as achieved
if (!storage.milestones) {
storage.milestones = {};
}
storage.milestones[milestone.resources] = true;
// Show milestone message
var milestoneText = new Text2(milestone.message, {
size: 60,
fill: 0xFFEB3B
});
milestoneText.anchor.set(0.5, 0.5);
milestoneText.x = 2048 / 2;
milestoneText.y = 2732 / 3;
game.addChild(milestoneText);
// Fade out the message
LK.setTimeout(function () {
tween(milestoneText, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
game.removeChild(milestoneText);
}
});
}, 3000);
}
});
} /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
resources: 0,
plants: 0,
creatures: 0,
structures: 0,
lastTimestamp: undefined,
upgrades: {},
biomes: {
forest: {
unlocked: true
}
},
stats: {
totalResources: 0
}
});
/****
* Classes
****/
var Biome = Container.expand(function (name, color) {
var self = Container.call(this);
var biomeGraphic = self.attachAsset('biome', {
anchorX: 0.5,
anchorY: 0.5,
tint: color || 0x81C784
});
var nameText = new Text2(name, {
size: 50,
fill: 0xFFFFFF
});
nameText.anchor.set(0.5, 0.5);
self.addChild(nameText);
self.unlock = function () {
LK.getSound('unlock').play();
tween(self, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 300
});
}
});
};
self.down = function (x, y, obj) {
// Set current biome
if (storage.biomes[name] && storage.biomes[name].unlocked) {
LK.getSound('click').play();
currentBiome = name;
updateBiomeSelection();
}
};
return self;
});
var Button = Container.expand(function (text, cost, callback) {
var self = Container.call(this);
var buttonGraphic = self.attachAsset('button', {
anchorX: 0.5,
anchorY: 0.5
});
var buttonText = new Text2(text, {
size: 40,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
buttonText.y = -15;
self.addChild(buttonText);
var costText = new Text2("Cost: " + cost, {
size: 30,
fill: 0xFFFFFF
});
costText.anchor.set(0.5, 0.5);
costText.y = 20;
self.addChild(costText);
self.cost = cost;
self.enabled = true;
self.updateCost = function (newCost) {
self.cost = newCost;
costText.setText("Cost: " + newCost);
};
self.setEnabled = function (enabled) {
self.enabled = enabled;
buttonGraphic.alpha = enabled ? 1.0 : 0.5;
};
self.down = function (x, y, obj) {
if (self.enabled) {
LK.getSound('click').play();
tween(self, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
callback();
}
};
return self;
});
var Plot = Container.expand(function () {
var self = Container.call(this);
var plotGraphic = self.attachAsset('plot', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
self.type = null;
self.level = 1;
self.progress = 0;
self.maxProgress = 100;
self.productive = false;
self.resourceRate = 1;
// Create progress bar (initially hidden)
var progressBarBg = self.attachAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
y: plotGraphic.height / 2 + 30
});
progressBarBg.alpha = 0;
var progressBar = self.attachAsset('progressBar', {
anchorX: 0,
anchorY: 0.5,
x: -progressBarBg.width / 2 + 10,
y: progressBarBg.y,
width: 0
});
progressBar.alpha = 0;
var entityGraphic = null;
// Text for level display
var levelText = new Text2('', {
size: 40,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0.5);
levelText.y = -plotGraphic.height / 2 - 30;
self.addChild(levelText);
levelText.alpha = 0;
self.setType = function (type) {
self.type = type;
// Clear previous entity graphic if it exists
if (entityGraphic) {
self.removeChild(entityGraphic);
}
// Set new entity graphic based on type
switch (type) {
case 'plant':
entityGraphic = self.attachAsset('plant', {
anchorX: 0.5,
anchorY: 1.0,
y: 30
});
self.resourceRate = 1 * self.level;
break;
case 'creature':
entityGraphic = self.attachAsset('creature', {
anchorX: 0.5,
anchorY: 0.5,
y: 0
});
self.resourceRate = 2 * self.level;
break;
case 'structure':
entityGraphic = self.attachAsset('structure', {
anchorX: 0.5,
anchorY: 0.5,
y: 0
});
self.resourceRate = 3 * self.level;
break;
default:
// Empty plot
entityGraphic = null;
self.resourceRate = 0;
}
// Show progress elements if we have a type
if (type) {
progressBarBg.alpha = 1;
progressBar.alpha = 1;
levelText.alpha = 1;
levelText.setText("Lvl " + self.level);
} else {
progressBarBg.alpha = 0;
progressBar.alpha = 0;
levelText.alpha = 0;
}
self.updateProgressBar();
};
self.updateProgressBar = function () {
var percentage = self.progress / self.maxProgress;
progressBar.width = (progressBarBg.width - 20) * percentage;
};
self.upgrade = function () {
if (self.type) {
self.level++;
self.resourceRate = self.level * (self.type === 'plant' ? 1 : self.type === 'creature' ? 2 : 3);
levelText.setText("Lvl " + self.level);
// Visual effect for upgrade
tween(entityGraphic, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
onFinish: function onFinish() {
tween(entityGraphic, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
LK.getSound('unlock').play();
}
};
self.update = function (deltaTime) {
if (self.type && !self.productive) {
self.progress += deltaTime * 0.05 * self.level;
if (self.progress >= self.maxProgress) {
self.progress = self.maxProgress;
self.productive = true;
// Pulse the entity to indicate it's ready
self.pulse();
}
self.updateProgressBar();
}
};
self.pulse = function () {
if (entityGraphic) {
tween(entityGraphic, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(entityGraphic, {
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: self.pulse
});
}
});
}
};
self.collect = function () {
if (self.productive) {
var gainedResources = self.resourceRate;
resources += gainedResources;
totalResourcesGained += gainedResources;
// Reset progress
self.progress = 0;
self.productive = false;
self.updateProgressBar();
// Stop pulsing
if (entityGraphic) {
tween.stop(entityGraphic, {
scaleX: true,
scaleY: true
});
entityGraphic.scaleX = 1;
entityGraphic.scaleY = 1;
}
// Spawn resource particle
spawnResourceParticle(self.x, self.y);
return gainedResources;
}
return 0;
};
self.down = function (x, y, obj) {
if (self.type && self.productive) {
LK.getSound('click').play();
self.collect();
}
};
return self;
});
var ResourceParticle = Container.expand(function () {
var self = Container.call(this);
var resourceGraphic = self.attachAsset('resource', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
self.setup = function (startX, startY, targetX, targetY) {
self.x = startX;
self.y = startY;
// Animate to target
tween(self, {
x: targetX,
y: targetY,
alpha: 0.5
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.destroy();
var index = resourceParticles.indexOf(self);
if (index !== -1) {
resourceParticles.splice(index, 1);
}
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1B5E20
});
/****
* Game Code
****/
// Constants
var PLOT_ROWS = 3;
var PLOT_COLS = 3;
var PLOT_PADDING = 50;
var PLOT_SIZE = 300;
// Game state variables
var resources = storage.resources || 0;
var totalResourcesGained = storage.stats.totalResources || 0;
var plots = [];
var resourceParticles = [];
var currentBiome = "forest";
var biomes = {};
// Biome data
var biomeData = {
"forest": {
color: 0x81C784,
unlockCost: 0,
plantMultiplier: 1,
creatureMultiplier: 1,
structureMultiplier: 1
},
"desert": {
color: 0xFFD54F,
unlockCost: 1000,
plantMultiplier: 0.8,
creatureMultiplier: 1.2,
structureMultiplier: 1.3
},
"ocean": {
color: 0x4FC3F7,
unlockCost: 5000,
plantMultiplier: 1.3,
creatureMultiplier: 1.5,
structureMultiplier: 0.9
},
"mountain": {
color: 0x90A4AE,
unlockCost: 20000,
plantMultiplier: 0.7,
creatureMultiplier: 0.8,
structureMultiplier: 2.0
}
};
// UI Elements
var resourcesText;
var plantsCountText;
var creaturesCountText;
var structuresCountText;
var rateText;
var plantButton;
var creatureButton;
var structureButton;
var biomePanel;
// Setup game
function setupGame() {
// Play background music
LK.playMusic('gameMusic');
createUI();
createPlots();
createBiomePanel();
// Initialize from storage if needed
if (storage.plants > 0 || storage.creatures > 0 || storage.structures > 0) {
// Re-create entities based on stored data
var plotIndex = 0;
for (var i = 0; i < storage.plants; i++) {
if (plotIndex < plots.length) {
plots[plotIndex].setType('plant');
plotIndex++;
}
}
for (var i = 0; i < storage.creatures; i++) {
if (plotIndex < plots.length) {
plots[plotIndex].setType('creature');
plotIndex++;
}
}
for (var i = 0; i < storage.structures; i++) {
if (plotIndex < plots.length) {
plots[plotIndex].setType('structure');
plotIndex++;
}
}
}
// Process offline progress
var now = Date.now();
var lastTime = storage.lastTimestamp || now;
var offlineSeconds = Math.floor((now - lastTime) / 1000);
if (offlineSeconds > 10) {
processOfflineProgress(offlineSeconds);
}
updateUI();
}
function createUI() {
// Resources counter at top
resourcesText = new Text2("Resources: 0", {
size: 70,
fill: 0xFFFFFF
});
resourcesText.anchor.set(0.5, 0);
LK.gui.top.addChild(resourcesText);
resourcesText.y = 50;
// Entity counters
var countersContainer = new Container();
LK.gui.left.addChild(countersContainer);
countersContainer.x = 150;
countersContainer.y = 300;
plantsCountText = new Text2("Plants: 0", {
size: 40,
fill: 0xFFFFFF
});
plantsCountText.anchor.set(0, 0.5);
countersContainer.addChild(plantsCountText);
creaturesCountText = new Text2("Creatures: 0", {
size: 40,
fill: 0xFFFFFF
});
creaturesCountText.anchor.set(0, 0.5);
creaturesCountText.y = 60;
countersContainer.addChild(creaturesCountText);
structuresCountText = new Text2("Structures: 0", {
size: 40,
fill: 0xFFFFFF
});
structuresCountText.anchor.set(0, 0.5);
structuresCountText.y = 120;
countersContainer.addChild(structuresCountText);
rateText = new Text2("Production: 0/sec", {
size: 40,
fill: 0xFFFFFF
});
rateText.anchor.set(0, 0.5);
rateText.y = 180;
countersContainer.addChild(rateText);
// Action buttons
var buttonsContainer = new Container();
LK.gui.right.addChild(buttonsContainer);
buttonsContainer.x = -150;
buttonsContainer.y = 300;
plantButton = new Button("Add Plant", 10, function () {
if (resources >= plantButton.cost) {
resources -= plantButton.cost;
addEntity('plant');
storage.plants++;
// Increase cost for next plant
plantButton.updateCost(Math.floor(10 * Math.pow(1.2, storage.plants)));
updateUI();
}
});
buttonsContainer.addChild(plantButton);
creatureButton = new Button("Add Creature", 50, function () {
if (resources >= creatureButton.cost) {
resources -= creatureButton.cost;
addEntity('creature');
storage.creatures++;
// Increase cost for next creature
creatureButton.updateCost(Math.floor(50 * Math.pow(1.3, storage.creatures)));
updateUI();
}
});
creatureButton.y = 120;
buttonsContainer.addChild(creatureButton);
structureButton = new Button("Add Structure", 200, function () {
if (resources >= structureButton.cost) {
resources -= structureButton.cost;
addEntity('structure');
storage.structures++;
// Increase cost for next structure
structureButton.updateCost(Math.floor(200 * Math.pow(1.4, storage.structures)));
updateUI();
}
});
structureButton.y = 240;
buttonsContainer.addChild(structureButton);
// Set initial costs based on storage
plantButton.updateCost(Math.floor(10 * Math.pow(1.2, storage.plants)));
creatureButton.updateCost(Math.floor(50 * Math.pow(1.3, storage.creatures)));
structureButton.updateCost(Math.floor(200 * Math.pow(1.4, storage.structures)));
}
function createPlots() {
var totalWidth = PLOT_COLS * PLOT_SIZE + (PLOT_COLS - 1) * PLOT_PADDING;
var totalHeight = PLOT_ROWS * PLOT_SIZE + (PLOT_ROWS - 1) * PLOT_PADDING;
var startX = (2048 - totalWidth) / 2 + PLOT_SIZE / 2;
var startY = (2732 - totalHeight) / 2 + PLOT_SIZE / 2;
for (var row = 0; row < PLOT_ROWS; row++) {
for (var col = 0; col < PLOT_COLS; col++) {
var plot = new Plot();
plot.x = startX + col * (PLOT_SIZE + PLOT_PADDING);
plot.y = startY + row * (PLOT_SIZE + PLOT_PADDING);
game.addChild(plot);
plots.push(plot);
}
}
}
function createBiomePanel() {
biomePanel = new Container();
game.addChild(biomePanel);
biomePanel.y = 2732 - 150;
var biomeX = 2048 / 2 - Object.keys(biomeData).length * 150;
// Create biome buttons
Object.keys(biomeData).forEach(function (biomeName, index) {
var biomeObj = new Biome(biomeName, biomeData[biomeName].color);
biomeObj.x = biomeX + index * 300;
// Initialize biome in storage if needed
if (!storage.biomes[biomeName]) {
storage.biomes[biomeName] = {
unlocked: biomeName === "forest"
};
}
biomes[biomeName] = biomeObj;
biomePanel.addChild(biomeObj);
// If not unlocked, show lock indicator
if (!storage.biomes[biomeName].unlocked) {
var lockText = new Text2("🔒", {
size: 60,
fill: 0xFFFFFF
});
lockText.anchor.set(0.5, 0.5);
lockText.y = -40;
biomeObj.addChild(lockText);
var costText = new Text2(biomeData[biomeName].unlockCost, {
size: 30,
fill: 0xFFFFFF
});
costText.anchor.set(0.5, 0.5);
costText.y = 40;
biomeObj.addChild(costText);
}
});
updateBiomeSelection();
}
function updateBiomeSelection() {
Object.keys(biomes).forEach(function (biomeName) {
var biome = biomes[biomeName];
biome.alpha = biomeName === currentBiome ? 1.0 : 0.6;
biome.scale.set(biomeName === currentBiome ? 1.1 : 1.0);
});
}
function addEntity(type) {
// Find first empty plot
for (var i = 0; i < plots.length; i++) {
if (!plots[i].type) {
plots[i].setType(type);
LK.getSound('unlock').play();
return true;
}
}
return false;
}
function spawnResourceParticle(startX, startY) {
var particle = new ResourceParticle();
particle.setup(startX, startY, resourcesText.parent.toGlobal(resourcesText.position).x, resourcesText.parent.toGlobal(resourcesText.position).y);
game.addChild(particle);
resourceParticles.push(particle);
}
function updateUI() {
resourcesText.setText("Resources: " + Math.floor(resources));
plantsCountText.setText("Plants: " + storage.plants);
creaturesCountText.setText("Creatures: " + storage.creatures);
structuresCountText.setText("Structures: " + storage.structures);
// Calculate production rate
var rate = 0;
plots.forEach(function (plot) {
if (plot.type && plot.productive) {
rate += plot.resourceRate;
}
});
rateText.setText("Production: " + rate + "/sec");
// Enable/disable buttons based on resources
plantButton.setEnabled(resources >= plantButton.cost);
creatureButton.setEnabled(resources >= creatureButton.cost);
structureButton.setEnabled(resources >= structureButton.cost);
// Check for unlockable biomes
Object.keys(biomeData).forEach(function (biomeName) {
if (!storage.biomes[biomeName].unlocked && resources >= biomeData[biomeName].unlockCost) {
storage.biomes[biomeName].unlocked = true;
biomes[biomeName].unlock();
// Remove lock indicator
biomes[biomeName].children.forEach(function (child) {
if (child instanceof Text2) {
biomes[biomeName].removeChild(child);
}
});
}
});
}
function processOfflineProgress(seconds) {
// Calculate offline earnings
var offlineRate = 0;
var plantCount = storage.plants;
var creatureCount = storage.creatures;
var structureCount = storage.structures;
if (plantCount + creatureCount + structureCount > 0) {
// Simple calculation: each entity produces its base rate per second
offlineRate = (plantCount * 1 + creatureCount * 2 + structureCount * 3) * 0.5; // Reduce offline earnings to 50%
var offlineEarnings = Math.floor(offlineRate * seconds);
resources += offlineEarnings;
totalResourcesGained += offlineEarnings;
// Show offline earnings message
var offlineText = new Text2("You earned " + offlineEarnings + " resources while away!", {
size: 60,
fill: 0xFFFFFF
});
offlineText.anchor.set(0.5, 0.5);
offlineText.x = 2048 / 2;
offlineText.y = 2732 / 2;
game.addChild(offlineText);
// Fade out the message
LK.setTimeout(function () {
tween(offlineText, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
game.removeChild(offlineText);
}
});
}, 3000);
}
}
// Setup game when loaded
setupGame();
// Game update function
var lastUpdateTime = Date.now();
game.update = function () {
// Calculate delta time
var now = Date.now();
var deltaTime = now - lastUpdateTime;
lastUpdateTime = now;
// Update all plots
plots.forEach(function (plot) {
plot.update(deltaTime);
});
// Auto-collect from productive plots every 3 seconds
if (LK.ticks % 180 === 0) {
var collected = 0;
plots.forEach(function (plot) {
if (plot.productive) {
collected += plot.collect();
}
});
if (collected > 0) {
totalResourcesGained += collected;
}
}
// Update storage periodically
if (LK.ticks % 60 === 0) {
storage.resources = resources;
storage.lastTimestamp = Date.now();
storage.stats.totalResources = totalResourcesGained;
}
// Update UI every 10 ticks
if (LK.ticks % 10 === 0) {
updateUI();
}
// Check for milestone achievements
if (LK.ticks % 300 === 0) {
checkMilestones();
}
};
function checkMilestones() {
var milestones = [{
resources: 1000,
message: "Your empire is growing!"
}, {
resources: 10000,
message: "Your ecosystem is thriving!"
}, {
resources: 100000,
message: "Your empire is becoming legendary!"
}];
milestones.forEach(function (milestone) {
if (totalResourcesGained >= milestone.resources && (!storage.milestones || !storage.milestones[milestone.resources])) {
// Store milestone as achieved
if (!storage.milestones) {
storage.milestones = {};
}
storage.milestones[milestone.resources] = true;
// Show milestone message
var milestoneText = new Text2(milestone.message, {
size: 60,
fill: 0xFFEB3B
});
milestoneText.anchor.set(0.5, 0.5);
milestoneText.x = 2048 / 2;
milestoneText.y = 2732 / 3;
game.addChild(milestoneText);
// Fade out the message
LK.setTimeout(function () {
tween(milestoneText, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
game.removeChild(milestoneText);
}
});
}, 3000);
}
});
}