/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
coins: 100,
unlockedPlots: 2,
unlockedSeeds: ["wheat", "corn", "tomato", "carrot", "potato", "strawberry"],
unlockedTools: {}
});
/****
* Classes
****/
var CoinDisplay = Container.expand(function () {
var self = Container.call(this);
var coinIcon = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
x: -60
});
var coinText = new Text2("0", {
size: 80,
fill: 0xFFFFFF
});
coinText.anchor.set(0, 0.5);
coinText.x = -30;
self.addChild(coinText);
self.updateCoins = function (amount) {
coinText.setText(amount.toString());
};
return self;
});
var FarmPlot = Container.expand(function () {
var self = Container.call(this);
self.state = PlotState.EMPTY;
self.growthTimer = 0;
self.seedType = null;
self.locked = true; // Plot starts locked by default
var soilGraphic = self.attachAsset('soil', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x555555 // Darker tint for locked plots
});
// Lock overlay
var lockOverlay = null;
// Update the visual state based on locked status
self.updateLockVisual = function () {
// Update soil tint
if (soilGraphic) {
soilGraphic.tint = self.locked ? 0x555555 : 0xFFFFFF;
}
// Update lock overlay
if (self.locked) {
if (!lockOverlay) {
lockOverlay = new Text2("🔒", {
size: 90,
fill: 0xFFFFFF
});
lockOverlay.anchor.set(0.5, 0.5);
lockOverlay.y = -20;
self.addChild(lockOverlay);
}
} else if (lockOverlay) {
lockOverlay.destroy();
lockOverlay = null;
}
};
var cropGraphic = null;
self.till = function () {
if (self.state === PlotState.EMPTY) {
self.state = PlotState.TILLED;
soilGraphic.destroy();
soilGraphic = self.attachAsset('tilled_soil', {
anchorX: 0.5,
anchorY: 0.5
});
// Play shovel sound effect when tilling
LK.getSound('till').play({
pitch: 0.85 + Math.random() * 0.3
});
return true;
}
return false;
};
self.plant = function (seedType) {
if (self.state === PlotState.TILLED) {
self.state = PlotState.SEEDED;
self.seedType = seedType;
if (cropGraphic) {
cropGraphic.destroy();
}
// Use the specific seed asset for each seed type
var seedAssetId = 'seed';
switch (seedType) {
case SeedType.WHEAT:
seedAssetId = 'wheat_seed';
break;
case SeedType.CORN:
seedAssetId = 'corn_seed';
break;
case SeedType.TOMATO:
seedAssetId = 'tomato_seed';
break;
case SeedType.CARROT:
seedAssetId = 'carrot_seed';
break;
case SeedType.POTATO:
seedAssetId = 'potato_seed';
break;
case SeedType.STRAWBERRY:
seedAssetId = 'strawberry_seed';
break;
}
cropGraphic = self.attachAsset(seedAssetId, {
anchorX: 0.5,
anchorY: 0.5,
y: -20
});
// Play rustling sound effect when planting seeds
LK.getSound('plant').play({
pitch: 0.9 + Math.random() * 0.2,
volume: 0.6
});
return true;
}
return false;
};
self.water = function () {
if (self.state === PlotState.SEEDED) {
self.state = PlotState.WATERED;
self.growthTimer = 0;
var waterDroplet = self.attachAsset('water_drop', {
anchorX: 0.5,
anchorY: 0.5,
y: -50,
alpha: 0.8
});
tween(waterDroplet, {
alpha: 0
}, {
duration: 1500,
onFinish: function onFinish() {
waterDroplet.destroy();
}
});
// Play splash sound effect when watering
LK.getSound('water').play({
pitch: 0.9 + Math.random() * 0.2,
volume: 0.7
});
return true;
}
return false;
};
self.grow = function () {
// Get crop configuration based on seed type
var cropConfig = CropConfig[self.seedType] || CropConfig.carrot;
var growthTime = cropConfig.growthTime;
// Calculate growth stage thresholds
var stage1Time = growthTime * 0.25; // 25% of total growth time
var stage2Time = growthTime * 0.5; // 50% of total growth time
var stage3Time = growthTime * 0.75; // 75% of total growth time
var harvestTime = growthTime; // 100% of total growth time
// Helper function to get appropriate asset for crop type and stage
function getCropAsset(seedType, stage) {
var assetId = 'crop_stage' + stage; // Default fallback
if (stage === 'growing') {
// Growing stage
switch (seedType) {
case SeedType.WHEAT:
return 'wheat_growing';
case SeedType.CORN:
return 'corn_growing';
case SeedType.TOMATO:
return 'tomato_growing';
case SeedType.CARROT:
return 'carrot_growing';
case SeedType.POTATO:
return 'potato_growing';
case SeedType.STRAWBERRY:
return 'strawberry_growing';
default:
return 'crop_stage2';
}
} else if (stage === 'mature') {
// Mature stage
switch (seedType) {
case SeedType.WHEAT:
return 'wheat_mature';
case SeedType.CORN:
return 'corn_mature';
case SeedType.TOMATO:
return 'tomato_mature';
case SeedType.CARROT:
return 'carrot_mature';
case SeedType.POTATO:
return 'potato_mature';
case SeedType.STRAWBERRY:
return 'strawberry_mature';
default:
return 'harvest_ready';
}
}
return assetId;
}
if (self.state === PlotState.WATERED) {
self.growthTimer++;
if (self.growthTimer >= stage1Time) {
self.state = PlotState.GROWING1;
if (cropGraphic) {
cropGraphic.destroy();
}
cropGraphic = self.attachAsset(getCropAsset(self.seedType, 'growing'), {
anchorX: 0.5,
anchorY: 1.0,
y: 0
});
}
} else if (self.state === PlotState.GROWING1) {
self.growthTimer++;
if (self.growthTimer >= stage2Time) {
self.state = PlotState.GROWING2;
if (cropGraphic) {
cropGraphic.destroy();
}
cropGraphic = self.attachAsset(getCropAsset(self.seedType, 'growing'), {
anchorX: 0.5,
anchorY: 1.0,
y: 0
});
cropGraphic.scaleX = 1.2;
cropGraphic.scaleY = 1.2;
}
} else if (self.state === PlotState.GROWING2) {
self.growthTimer++;
if (self.growthTimer >= stage3Time) {
self.state = PlotState.GROWING3;
if (cropGraphic) {
cropGraphic.destroy();
}
cropGraphic = self.attachAsset(getCropAsset(self.seedType, 'growing'), {
anchorX: 0.5,
anchorY: 1.0,
y: 0
});
cropGraphic.scaleX = 1.4;
cropGraphic.scaleY = 1.4;
}
} else if (self.state === PlotState.GROWING3) {
self.growthTimer++;
if (self.growthTimer >= harvestTime) {
self.state = PlotState.READY;
if (cropGraphic) {
cropGraphic.destroy();
}
cropGraphic = self.attachAsset(getCropAsset(self.seedType, 'mature'), {
anchorX: 0.5,
anchorY: 1.0,
y: 0
});
// Add bouncing animation for ready crops
tween(cropGraphic, {
y: -10
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(cropGraphic, {
y: 0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (cropGraphic && cropGraphic.parent) {
self.bounceAnimation();
}
}
});
}
});
}
}
};
self.bounceAnimation = function () {
if (self.state === PlotState.READY && cropGraphic && cropGraphic.parent) {
tween.stop(cropGraphic); // Stop any running tweens first
tween(cropGraphic, {
y: -10
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (cropGraphic && cropGraphic.parent) {
// Check if cropGraphic still exists
tween(cropGraphic, {
y: 0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (cropGraphic && cropGraphic.parent) {
self.bounceAnimation();
}
}
});
}
}
});
}
};
self.harvest = function () {
if (self.state === PlotState.READY) {
var harvestValue = 0;
if (self.seedType && CropConfig[self.seedType]) {
harvestValue = CropConfig[self.seedType].value;
} else {
harvestValue = 3; // Default value if seedType is invalid
}
self.reset();
// Play plucking sound effect when harvesting
LK.getSound('harvest').play({
pitch: 0.8 + Math.random() * 0.4,
volume: 0.8
});
return harvestValue;
}
return 0;
};
self.reset = function () {
self.state = PlotState.EMPTY;
self.growthTimer = 0;
self.seedType = null;
if (cropGraphic) {
cropGraphic.destroy();
cropGraphic = null;
}
if (soilGraphic) {
soilGraphic.destroy();
}
soilGraphic = self.attachAsset('soil', {
anchorX: 0.5,
anchorY: 0.5,
tint: self.locked ? 0x555555 : 0xFFFFFF // Maintain lock tint
});
self.updateLockVisual(); // Update lock visual after reset
};
self.down = function (x, y, obj) {
// If plot is locked, show purchase dialog
if (self.locked) {
if (coins >= 200) {
// Create confirmation dialog
var confirmDialog = new Container();
// Background
var dialogBg = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4,
scaleY: 2,
tint: 0x333333,
alpha: 0.9
});
confirmDialog.addChild(dialogBg);
// Message
var message = new Text2("Unlock this plot for 200 coins?", {
size: 50,
fill: 0xFFFFFF
});
message.anchor.set(0.5, 0);
message.y = -50;
confirmDialog.addChild(message);
// Yes button
var yesButton = new Container();
var yesBg = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1,
tint: 0x00AA00
});
yesButton.addChild(yesBg);
var yesText = new Text2("Yes", {
size: 50,
fill: 0xFFFFFF
});
yesText.anchor.set(0.5, 0.5);
yesButton.addChild(yesText);
yesButton.x = -100;
yesButton.y = 50;
yesButton.interactive = true;
confirmDialog.addChild(yesButton);
// No button
var noButton = new Container();
var noBg = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1,
tint: 0xAA0000
});
noButton.addChild(noBg);
var noText = new Text2("No", {
size: 50,
fill: 0xFFFFFF
});
noText.anchor.set(0.5, 0.5);
noButton.addChild(noText);
noButton.x = 100;
noButton.y = 50;
noButton.interactive = true;
confirmDialog.addChild(noButton);
// Position dialog
confirmDialog.x = gameWidth / 2;
confirmDialog.y = gameHeight / 2;
game.addChild(confirmDialog);
// Button handlers
yesButton.down = function () {
// Purchase plot
coins -= 200;
storage.coins = coins;
coinDisplay.updateCoins(coins);
// Unlock plot
self.locked = false;
self.updateLockVisual();
// Increment unlocked plots count
storage.unlockedPlots = (storage.unlockedPlots || 0) + 1;
// Update plot counter display
if (plotCounter) {
plotCounter.updateCount(storage.unlockedPlots);
}
// Visual feedback
LK.effects.flashObject(self, 0x00FF00, 500);
// Remove dialog
confirmDialog.destroy();
};
noButton.down = function () {
// Just remove dialog
confirmDialog.destroy();
};
} else {
// Not enough coins
LK.effects.flashObject(self, 0xFF0000, 500);
}
return;
}
var toolAction = false;
// Handle both basic and advanced tools
switch (currentTool) {
case ToolType.HOE:
case "Auto-Tilling Tool":
toolAction = self.till();
// If using auto-tiller and action succeeded, till adjacent plots
if (toolAction && currentTool === "Auto-Tilling Tool") {
// Find nearby plots
var nearbyPlots = findNearbyPlots(self, 1);
nearbyPlots.forEach(function (plot) {
if (!plot.locked) {
plot.till();
// Visual feedback for each plot
LK.effects.flashObject(plot, 0xAA7722, 300);
}
});
}
break;
case ToolType.SEEDS:
// If the plot is tilled, show seed selector
if (self.state === PlotState.TILLED) {
// Position seed selector over this plot
seedSelector.x = self.x;
seedSelector.y = self.y - 200;
seedSelector.show();
// Set the target plot for planting
seedSelector.targetPlot = self;
} else {
// If not tilled, try to plant with current seed
toolAction = self.plant(selectedSeedType);
}
break;
case ToolType.WATER:
case "Irrigation System":
toolAction = self.water();
// If using irrigation system and action succeeded, water adjacent plots
if (toolAction && currentTool === "Irrigation System") {
// Find nearby plots
var nearbyPlots = findNearbyPlots(self, 1);
nearbyPlots.forEach(function (plot) {
if (!plot.locked) {
var waterSuccess = plot.water();
if (waterSuccess) {
// Visual feedback for each watered plot
LK.effects.flashObject(plot, 0x1E90FF, 300);
}
}
});
}
break;
case ToolType.HARVEST:
case "Better Harvesting Tools":
var harvestValue = self.harvest();
if (harvestValue > 0) {
toolAction = true;
// Give bonus yield if using better harvesting tools
if (currentTool === "Better Harvesting Tools") {
harvestValue = Math.floor(harvestValue * 1.5); // 50% bonus
}
addCoins(harvestValue);
}
break;
case ToolType.SHOVEL:
// Shovel resets the plot to empty state
if (self.state !== PlotState.EMPTY) {
self.reset();
toolAction = true;
}
break;
}
if (toolAction) {
// Visual feedback
LK.effects.flashObject(self, 0xFFFFFF, 300);
}
};
self.update = function () {
if (self.state >= PlotState.WATERED && self.state < PlotState.READY) {
self.grow();
}
// Check for hover over planted crops
if (self.state >= PlotState.SEEDED && Math.abs(lastTouchPosition.x - self.x) < plotSize / 2 && Math.abs(lastTouchPosition.y - self.y) < plotSize / 2) {
// Mouse is over this plot
if (!self.isHovered) {
self.isHovered = true;
tooltip.updateInfo(self);
tooltip.show(lastTouchPosition.x, lastTouchPosition.y);
}
} else if (self.isHovered) {
self.isHovered = false;
// Don't hide tooltip here as another plot might be hovered
}
};
return self;
});
var PlotCounter = Container.expand(function () {
var self = Container.call(this);
// Create background
var background = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.5,
scaleY: 1,
tint: 0x4b0082,
alpha: 0.7
});
self.addChild(background);
// Plot counter text
var counterText = new Text2("Plots: 0/0", {
size: 50,
fill: 0xFFFFFF
});
counterText.anchor.set(0.5, 0.5);
self.addChild(counterText);
// Update counter display
self.updateCount = function (unlocked) {
counterText.setText("Plots: " + unlocked + "/" + farmPlots.length);
};
return self;
});
var SeedSelector = Container.expand(function () {
var self = Container.call(this);
// Target plot to plant on after selection
self.targetPlot = null;
// Create background
var background = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4,
scaleY: 1.5,
tint: 0x8b5a2b,
alpha: 0.8
});
self.addChild(background);
// Title
var titleText = new Text2("Select Seed", {
size: 70,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0);
titleText.y = -70;
self.addChild(titleText);
// Create seed buttons
var seedButtons = [];
var seedTypes = [{
type: SeedType.WHEAT,
name: "Wheat",
color: 0xF5DEB3
}, {
type: SeedType.CORN,
name: "Corn",
color: 0xFFF44F
}, {
type: SeedType.TOMATO,
name: "Tomato",
color: 0xFF6347
}, {
type: SeedType.CARROT,
name: "Carrot",
color: 0xFFA500
}, {
type: SeedType.POTATO,
name: "Potato",
color: 0xA0522D
}, {
type: SeedType.STRAWBERRY,
name: "Strawberry",
color: 0xFF3366
}];
var buttonSize = 60;
var spacing = 80;
var startX = -(spacing * (seedTypes.length - 1)) / 2;
seedTypes.forEach(function (seedInfo, index) {
var button = new Container();
// Seed visual
var seedVisual = LK.getAsset('seed', {
anchorX: 0.5,
anchorY: 0.5,
tint: seedInfo.color
});
button.addChild(seedVisual);
// Seed name
var nameText = new Text2(seedInfo.name, {
size: 40,
fill: 0xFFFFFF
});
nameText.anchor.set(0.5, 0);
nameText.y = 40;
button.addChild(nameText);
// Growth time text
var growthDays = CropConfig[seedInfo.type].growthTime / (60 * 60);
var growthText = new Text2(growthDays + " days", {
size: 30,
fill: 0xCCCCCC
});
growthText.anchor.set(0.5, 0);
growthText.y = 70;
button.addChild(growthText);
// Position button
button.x = startX + index * spacing;
button.y = 0;
button.interactive = true;
// Selection highlight
var highlight = LK.getAsset('seed', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFFFF00,
alpha: 0
});
button.addChildAt(highlight, 0);
// Set button data
button.seedType = seedInfo.type;
button.highlight = highlight;
// Add to container and array
self.addChild(button);
seedButtons.push(button);
// Button event
button.down = function (x, y, obj) {
// Set the selected seed type
selectedSeedType = button.seedType;
updateSelectedSeed();
// If we have a target plot, plant the seed and hide the selector
if (self.targetPlot) {
// Try to plant the selected seed
var success = self.targetPlot.plant(selectedSeedType);
if (success) {
// Visual feedback
LK.effects.flashObject(self.targetPlot, 0xFFFFFF, 300);
}
// Hide selector regardless of success
self.visible = false;
self.targetPlot = null;
}
};
});
// Update visual selection
function updateSelectedSeed() {
seedButtons.forEach(function (button) {
if (button.seedType === selectedSeedType) {
button.highlight.alpha = 0.3;
} else {
button.highlight.alpha = 0;
}
});
}
// Close button
var closeButton = new Container();
var closeVisual = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
tint: 0xFF5555
});
closeButton.addChild(closeVisual);
var closeText = new Text2("X", {
size: 60,
fill: 0xFFFFFF
});
closeText.anchor.set(0.5, 0.5);
closeButton.addChild(closeText);
closeButton.x = background.width / 2 - 30;
closeButton.y = -background.height / 2 + 30;
self.addChild(closeButton);
// Close event
closeButton.down = function (x, y, obj) {
self.visible = false;
self.targetPlot = null; // Clear target plot when closing
};
self.show = function () {
self.visible = true;
updateSelectedSeed();
};
// Initialize with default selection
updateSelectedSeed();
return self;
});
var Tool = Container.expand(function (toolType, isAdvanced, toolData) {
var self = Container.call(this);
self.toolType = toolType;
self.isAdvanced = isAdvanced || false;
self.toolData = toolData || null;
// Determine which asset to use
var assetId;
if (self.isAdvanced && self.toolData) {
// Use advanced tool specific sprites
if (self.toolData.name === "Irrigation System") {
assetId = 'tool_irrigation';
} else if (self.toolData.name === "Better Harvesting Tools") {
assetId = 'tool_better_harvest';
} else if (self.toolData.name === "Auto-Tilling Tool") {
assetId = 'tool_auto_tiller';
} else {
assetId = self.toolData.icon;
}
} else {
// Use basic tool sprites
if (toolType === ToolType.HOE) {
assetId = 'tool_hoe';
} else if (toolType === ToolType.SEEDS) {
assetId = 'tool_seeds';
} else if (toolType === ToolType.WATER) {
assetId = 'tool_water';
} else if (toolType === ToolType.HARVEST) {
assetId = 'tool_harvest';
} else if (toolType === ToolType.SHOVEL) {
assetId = 'tool_shovel';
} else {
assetId = 'tool_hoe'; // Default
}
}
var toolGraphic = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Apply tint if it's an advanced tool with tint
if (self.isAdvanced && self.toolData && self.toolData.tint) {
toolGraphic.tint = self.toolData.tint;
}
// Create tool name label
var toolName = new Text2(self.isAdvanced && self.toolData ? self.toolData.name : ToolType.HOE === toolType ? "Hoe" : ToolType.SEEDS === toolType ? "Seeds" : ToolType.WATER === toolType ? "Water" : ToolType.HARVEST === toolType ? "Harvest" : "Tool", {
size: 36,
fill: 0xFFFFFF
});
toolName.anchor.set(0.5, 0);
toolName.y = 80;
self.addChild(toolName);
// Add lock icon or price for locked tools
self.lockIcon = null;
self.priceText = null;
self.updateLockStatus = function () {
// Remove existing lock/price if any
if (self.lockIcon) {
self.lockIcon.destroy();
self.lockIcon = null;
}
if (self.priceText) {
self.priceText.destroy();
self.priceText = null;
}
// If it's an advanced tool and not unlocked, show lock or price
if (self.isAdvanced && self.toolData && !self.toolData.unlocked) {
// Show price
self.priceText = new Text2(self.toolData.price.toString(), {
size: 40,
fill: 0xFFDD00
});
self.priceText.anchor.set(0.5, 0);
self.priceText.y = -70;
self.addChild(self.priceText);
// Dim the tool
toolGraphic.alpha = 0.5;
} else {
toolGraphic.alpha = 1;
}
};
// Highlight border when selected
var selectedBorder = null;
self.setSelected = function (selected) {
if (selected) {
if (!selectedBorder) {
selectedBorder = new Container();
var borderSize = 10;
var borderAsset = LK.getAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2,
tint: 0xFFFF00,
alpha: 0.5
});
selectedBorder.addChild(borderAsset);
self.addChildAt(selectedBorder, 0);
}
} else {
if (selectedBorder) {
selectedBorder.destroy();
selectedBorder = null;
}
}
};
self.down = function (x, y, obj) {
// If it's a locked advanced tool, try to purchase
if (self.isAdvanced && self.toolData && !self.toolData.unlocked) {
if (coins >= self.toolData.price) {
// Purchase the tool
coins -= self.toolData.price;
storage.coins = coins;
coinDisplay.updateCoins(coins);
self.toolData.unlocked = true;
// Save unlocked status
var unlockedTools = storage.unlockedTools || {};
unlockedTools[self.toolData.name] = true;
storage.unlockedTools = unlockedTools;
// Update visuals
self.updateLockStatus();
// Show success animation
LK.effects.flashObject(self, 0x00FF00, 500);
} else {
// Not enough coins
LK.effects.flashObject(self, 0xFF0000, 500);
}
} else {
// Normal tool selection
selectTool(self.isAdvanced ? self.toolData.name : self.toolType);
}
};
// Initialize lock/price display
if (self.isAdvanced) {
self.updateLockStatus();
}
return self;
});
var Tooltip = Container.expand(function () {
var self = Container.call(this);
// Create background
var background = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.5,
scaleY: 1.4,
tint: 0x333333,
alpha: 0.8
});
self.addChild(background);
// Water level text
var waterLevelText = new Text2("Water Level: Unknown", {
size: 40,
fill: 0x1E90FF
});
waterLevelText.anchor.set(0.5, 0);
waterLevelText.y = -30;
self.addChild(waterLevelText);
// Growth time text
var growthTimeText = new Text2("Time Till Grown: Unknown", {
size: 40,
fill: 0xFFFFFF
});
growthTimeText.anchor.set(0.5, 0);
growthTimeText.y = 10;
self.addChild(growthTimeText);
// Update tooltip information
self.updateInfo = function (plot) {
if (!plot || plot.state === PlotState.EMPTY || plot.state === PlotState.TILLED) {
self.visible = false;
return;
}
// Calculate water level text
var waterLevel = "None";
if (plot.state >= PlotState.WATERED) {
if (plot.state === PlotState.WATERED) {
waterLevel = "High";
} else if (plot.state === PlotState.GROWING1) {
waterLevel = "High";
} else if (plot.state === PlotState.GROWING2) {
waterLevel = "Medium";
} else if (plot.state === PlotState.GROWING3) {
waterLevel = "Low";
} else if (plot.state === PlotState.READY) {
waterLevel = "Low";
}
}
waterLevelText.setText("Water Level: " + waterLevel);
// Calculate growth time remaining
var timeText = "Ready to Harvest!";
if (plot.state < PlotState.READY && plot.state >= PlotState.WATERED) {
var cropConfig = CropConfig[plot.seedType] || CropConfig.carrot;
var totalGrowthTime = cropConfig.growthTime;
var timeRemaining = totalGrowthTime - plot.growthTimer;
// Convert ticks to days (60 ticks per second, 60 seconds per minute, 60 minutes per hour)
var daysRemaining = Math.ceil(timeRemaining / (60 * 60));
timeText = "Time Till Grown: " + daysRemaining + " days";
}
growthTimeText.setText(timeText);
self.visible = true;
};
// Hide tooltip
self.hide = function () {
self.visible = false;
};
// Initialize as hidden
self.visible = false;
// Add show animation
self.show = function (x, y) {
// Position tooltip near cursor but ensure it stays on screen
self.x = Math.min(Math.max(x, 250), gameWidth - 250);
self.y = Math.min(Math.max(y - 80, 100), gameHeight - 100);
// Animation effect
self.alpha = 0;
self.scale.x = 0.8;
self.scale.y = 0.8;
tween.stop(self);
tween(self, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOutQuad
});
self.visible = true;
};
return self;
});
var Town = Container.expand(function () {
var self = Container.call(this);
// Create town background
var background = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 8,
scaleY: 10,
tint: 0x8B4513,
alpha: 0.9
});
self.addChild(background);
// Town title
var titleText = new Text2("Town", {
size: 90,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0);
titleText.y = -450;
self.addChild(titleText);
// Create shops
var shops = [{
name: "Tool Shop",
description: "Upgrade your farming tools",
y: -300
}, {
name: "Seed Shop",
description: "Buy new seed varieties",
y: -100
}, {
name: "Market",
description: "Sell your crops for coins",
y: 100
}];
var shopButtons = [];
shops.forEach(function (shop) {
var shopButton = new Container();
// Shop button background
var buttonBg = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 6,
scaleY: 1.5,
tint: 0x6B4226
});
shopButton.addChild(buttonBg);
// Shop name
var nameText = new Text2(shop.name, {
size: 60,
fill: 0xFFFFFF
});
nameText.anchor.set(0.5, 0.5);
nameText.y = -25;
shopButton.addChild(nameText);
// Shop description
var descText = new Text2(shop.description, {
size: 40,
fill: 0xCCCCCC
});
descText.anchor.set(0.5, 0.5);
descText.y = 25;
shopButton.addChild(descText);
// Position and add
shopButton.y = shop.y;
shopButton.shopType = shop.name;
shopButton.interactive = true;
self.addChild(shopButton);
shopButtons.push(shopButton);
// Click handler
shopButton.down = function (x, y, obj) {
self.openShop(shop.name);
};
});
// Close button
var closeButton = new Container();
var closeVisual = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8,
tint: 0xFF5555
});
closeButton.addChild(closeVisual);
var closeText = new Text2("X", {
size: 60,
fill: 0xFFFFFF
});
closeText.anchor.set(0.5, 0.5);
closeButton.addChild(closeText);
closeButton.x = background.width / 2 - 30;
closeButton.y = -background.height / 2 + 30;
closeButton.interactive = true;
self.addChild(closeButton);
// Close event
closeButton.down = function (x, y, obj) {
self.hide();
};
// Currently open shop content
var currentShopContent = null;
// Shop handlers
self.openShop = function (shopType) {
// Clear current shop content if any
if (currentShopContent) {
currentShopContent.destroy();
currentShopContent = null;
}
// Create new shop content based on type
currentShopContent = new Container();
self.addChild(currentShopContent);
// Shop title
var shopTitle = new Text2(shopType, {
size: 80,
fill: 0xFFD700
});
shopTitle.anchor.set(0.5, 0.5);
shopTitle.y = -350;
currentShopContent.addChild(shopTitle);
// Shop specific content
if (shopType === "Tool Shop") {
createToolShop(currentShopContent);
} else if (shopType === "Seed Shop") {
createSeedShop(currentShopContent);
} else if (shopType === "Market") {
createMarket(currentShopContent);
}
// Update shop buttons visibility
shops.forEach(function (shop, index) {
shopButtons[index].visible = false;
});
// Add back button
var backButton = new Container();
var backVisual = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 1,
tint: 0x4B0082
});
backButton.addChild(backVisual);
var backText = new Text2("Back", {
size: 50,
fill: 0xFFFFFF
});
backText.anchor.set(0.5, 0.5);
backButton.addChild(backText);
backButton.y = 400;
backButton.interactive = true;
currentShopContent.addChild(backButton);
backButton.down = function (x, y, obj) {
if (currentShopContent) {
currentShopContent.destroy();
currentShopContent = null;
}
// Show shop buttons again
shops.forEach(function (shop, index) {
shopButtons[index].visible = true;
});
};
};
// Create Tool Shop content
function createToolShop(container) {
var toolsPerRow = 3;
var spacing = 200;
var startX = -(spacing * (toolsPerRow - 1)) / 2;
var startY = -200;
var advancedTools = [];
Object.keys(ToolConfig.advanced).forEach(function (key) {
advancedTools.push(ToolConfig.advanced[key]);
});
advancedTools.forEach(function (toolData, index) {
var row = Math.floor(index / toolsPerRow);
var col = index % toolsPerRow;
var toolButton = new Container();
// Tool icon
var toolIcon = LK.getAsset(toolData.icon, {
anchorX: 0.5,
anchorY: 0.5,
tint: toolData.tint || 0xFFFFFF
});
toolButton.addChild(toolIcon);
// Tool name
var nameText = new Text2(toolData.name, {
size: 40,
fill: 0xFFFFFF
});
nameText.anchor.set(0.5, 0);
nameText.y = 70;
toolButton.addChild(nameText);
// Tool description
var descText = new Text2(toolData.description, {
size: 30,
fill: 0xCCCCCC
});
descText.anchor.set(0.5, 0);
descText.y = 100;
toolButton.addChild(descText);
// Price or status
var statusText = new Text2(toolData.unlocked ? "Owned" : toolData.price + " coins", {
size: 40,
fill: toolData.unlocked ? 0x00FF00 : 0xFFD700,
style: {} // Add style object for later modification
});
statusText.anchor.set(0.5, 0.5);
statusText.y = -60;
toolButton.addChild(statusText);
// Position and add
toolButton.x = startX + col * spacing;
toolButton.y = startY + row * 220;
toolButton.toolData = toolData;
toolButton.interactive = !toolData.unlocked;
container.addChild(toolButton);
// Click handler only for locked tools
if (!toolData.unlocked) {
toolButton.down = function (x, y, obj) {
if (coins >= toolData.price) {
// Purchase the tool
coins -= toolData.price;
storage.coins = coins;
coinDisplay.updateCoins(coins);
toolData.unlocked = true;
// Save unlocked status
var unlockedTools = storage.unlockedTools || {};
unlockedTools[toolData.name] = true;
storage.unlockedTools = unlockedTools;
// Update tool panel
for (var i = 0; i < tools.length; i++) {
if (tools[i].isAdvanced && tools[i].toolData && tools[i].toolData.name === toolData.name) {
tools[i].updateLockStatus();
break;
}
}
// Update button
statusText.setText("Owned");
statusText.style.fill = 0x00FF00;
toolButton.interactive = false;
// Show success animation
LK.effects.flashObject(toolButton, 0x00FF00, 500);
} else {
// Not enough coins
LK.effects.flashObject(toolButton, 0xFF0000, 500);
}
};
}
});
}
// Create Seed Shop content
function createSeedShop(container) {
var seedsPerRow = 3;
var spacing = 200;
var startX = -(spacing * (seedsPerRow - 1)) / 2;
var startY = -200;
var seedTypes = [{
type: SeedType.WHEAT,
name: "Wheat",
color: 0xF5DEB3,
growthDays: 2,
price: 2
}, {
type: SeedType.CORN,
name: "Corn",
color: 0xFFF44F,
growthDays: 3,
price: 3
}, {
type: SeedType.TOMATO,
name: "Tomato",
color: 0xFF6347,
growthDays: 4,
price: 5
}, {
type: SeedType.CARROT,
name: "Carrot",
color: 0xFFA500,
growthDays: 3,
price: 3
}, {
type: SeedType.POTATO,
name: "Potato",
color: 0xA0522D,
growthDays: 5,
price: 6
}, {
type: SeedType.STRAWBERRY,
name: "Strawberry",
color: 0xFF3366,
growthDays: 6,
price: 8
}];
seedTypes.forEach(function (seedInfo, index) {
var row = Math.floor(index / seedsPerRow);
var col = index % seedsPerRow;
var seedButton = new Container();
// Seed visual
var seedVisual = LK.getAsset('seed', {
anchorX: 0.5,
anchorY: 0.5,
tint: seedInfo.color,
scaleX: 1.5,
scaleY: 1.5
});
seedButton.addChild(seedVisual);
// Seed name
var nameText = new Text2(seedInfo.name, {
size: 40,
fill: 0xFFFFFF
});
nameText.anchor.set(0.5, 0);
nameText.y = 50;
seedButton.addChild(nameText);
// Growth time
var timeText = new Text2(seedInfo.growthDays + " days", {
size: 30,
fill: 0xCCCCCC
});
timeText.anchor.set(0.5, 0);
timeText.y = 80;
seedButton.addChild(timeText);
// Price
var priceText = new Text2(seedInfo.price + " coins", {
size: 40,
fill: 0xFFD700
});
priceText.anchor.set(0.5, 0.5);
priceText.y = -60;
seedButton.addChild(priceText);
// Value text
var valueText = new Text2("Value: " + CropConfig[seedInfo.type].value + " coins", {
size: 30,
fill: 0x00FF00
});
valueText.anchor.set(0.5, 0);
valueText.y = 110;
seedButton.addChild(valueText);
// Position and add
seedButton.x = startX + col * spacing;
seedButton.y = startY + row * 220;
seedButton.seedType = seedInfo.type;
seedButton.price = seedInfo.price;
seedButton.interactive = true;
container.addChild(seedButton);
// Click handler
seedButton.down = function (x, y, obj) {
if (coins >= seedButton.price) {
// Purchase the seed
coins -= seedButton.price;
storage.coins = coins;
coinDisplay.updateCoins(coins);
// Show success animation
LK.effects.flashObject(seedButton, 0x00FF00, 500);
// Select this seed type
selectedSeedType = seedButton.seedType;
selectTool(ToolType.SEEDS);
} else {
// Not enough coins
LK.effects.flashObject(seedButton, 0xFF0000, 500);
}
};
});
}
// Create Market content
function createMarket(container) {
var marketTitle = new Text2("Sell your harvested crops at the Market", {
size: 50,
fill: 0xFFFFFF
});
marketTitle.anchor.set(0.5, 0.5);
marketTitle.y = -250;
container.addChild(marketTitle);
var marketDesc = new Text2("Current market prices:", {
size: 40,
fill: 0xCCCCCC
});
marketDesc.anchor.set(0.5, 0.5);
marketDesc.y = -180;
container.addChild(marketDesc);
// Show prices for each crop
var cropsPerRow = 3;
var spacing = 200;
var startX = -(spacing * (cropsPerRow - 1)) / 2;
var startY = -100;
var cropTypes = [{
type: SeedType.WHEAT,
name: "Wheat",
color: 0xF5DEB3
}, {
type: SeedType.CORN,
name: "Corn",
color: 0xFFF44F
}, {
type: SeedType.TOMATO,
name: "Tomato",
color: 0xFF6347
}, {
type: SeedType.CARROT,
name: "Carrot",
color: 0xFFA500
}, {
type: SeedType.POTATO,
name: "Potato",
color: 0xA0522D
}, {
type: SeedType.STRAWBERRY,
name: "Strawberry",
color: 0xFF3366
}];
cropTypes.forEach(function (cropInfo, index) {
var row = Math.floor(index / cropsPerRow);
var col = index % cropsPerRow;
var cropDisplay = new Container();
// Crop visual
var cropVisual = LK.getAsset('harvest_ready', {
anchorX: 0.5,
anchorY: 0.5,
tint: cropInfo.color,
scaleX: 0.8,
scaleY: 0.8
});
cropDisplay.addChild(cropVisual);
// Crop name
var nameText = new Text2(cropInfo.name, {
size: 40,
fill: 0xFFFFFF
});
nameText.anchor.set(0.5, 0);
nameText.y = 80;
cropDisplay.addChild(nameText);
// Crop value
var valueText = new Text2(CropConfig[cropInfo.type].value + " coins", {
size: 50,
fill: 0xFFD700
});
valueText.anchor.set(0.5, 0.5);
valueText.y = 30;
cropDisplay.addChild(valueText);
// Position
cropDisplay.x = startX + col * spacing;
cropDisplay.y = startY + row * 200;
container.addChild(cropDisplay);
});
var marketNotice = new Text2("Harvest crops with the Harvest Tool to earn coins!", {
size: 40,
fill: 0xFFFFFF
});
marketNotice.anchor.set(0.5, 0.5);
marketNotice.y = 300;
container.addChild(marketNotice);
}
// Show/hide methods
self.show = function () {
self.visible = true;
// Reset to main town view
if (currentShopContent) {
currentShopContent.destroy();
currentShopContent = null;
}
// Show shop buttons
shops.forEach(function (shop, index) {
shopButtons[index].visible = true;
});
};
self.hide = function () {
self.visible = false;
};
// Initialize as hidden
self.visible = false;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB // Sky blue background
});
/****
* Game Code
****/
// Game variables
var PlotState = {
EMPTY: 0,
TILLED: 1,
SEEDED: 2,
WATERED: 3,
GROWING1: 4,
GROWING2: 5,
GROWING3: 6,
READY: 7
};
// Tool configurations
var ToolConfig = {
// Basic tools (available from start)
basic: {
HOE: {
name: "Hoe",
description: "Tills soil for planting",
icon: 'tool_hoe',
unlocked: true
},
SHOVEL: {
name: "Shovel",
description: "Digs holes in the soil",
icon: 'tool_shovel',
unlocked: true
},
WATER: {
name: "Water Bucket",
description: "Waters your plants",
icon: 'tool_water',
unlocked: true
},
SEEDS: {
name: "Seed Bag",
description: "Plants seeds in tilled soil",
icon: 'tool_seeds',
unlocked: true
},
HARVEST: {
name: "Harvest Tool",
description: "Harvests mature crops",
icon: 'tool_harvest',
unlocked: true
}
},
// Advanced tools (unlocked through purchases)
advanced: {
IRRIGATION: {
name: "Irrigation System",
description: "Waters multiple plots at once",
icon: 'tool_irrigation',
price: 100,
unlocked: false
},
BETTER_HARVEST: {
name: "Better Harvesting Tools",
description: "Harvest crops faster with bonus yields",
icon: 'tool_better_harvest',
price: 150,
unlocked: false
},
AUTO_TILLER: {
name: "Auto-Tilling Tool",
description: "Tills multiple plots at once",
icon: 'tool_auto_tiller',
price: 200,
unlocked: false
}
}
};
var ToolType = {
HOE: 0,
SEEDS: 1,
WATER: 2,
HARVEST: 3,
SHOVEL: 4,
IRRIGATION: 5,
BETTER_HARVEST: 6,
AUTO_TILLER: 7
};
var SeedType = {
WHEAT: "wheat",
CORN: "corn",
TOMATO: "tomato",
CARROT: "carrot",
POTATO: "potato",
STRAWBERRY: "strawberry"
};
// Crop configuration with growth times in ticks (60 ticks = 1 second)
var CropConfig = {
wheat: {
growthTime: 2 * 60 * 60,
// 2 days (2 min in game time)
value: 4
},
corn: {
growthTime: 3 * 60 * 60,
// 3 days (3 min in game time)
value: 7
},
tomato: {
growthTime: 4 * 60 * 60,
// 4 days (4 min in game time)
value: 10
},
carrot: {
growthTime: 3 * 60 * 60,
// 3 days (3 min in game time)
value: 6
},
potato: {
growthTime: 5 * 60 * 60,
// 5 days (5 min in game time)
value: 12
},
strawberry: {
growthTime: 6 * 60 * 60,
// 6 days (6 min in game time)
value: 15
}
};
var farmPlots = [];
var tools = [];
var currentTool = ToolType.HOE;
var gameWidth = 2048;
var gameHeight = 2732;
var gridSize = 10;
var plotSize = 180;
var plotSpacing = 10;
var coins = storage.coins || 0;
var coinDisplay;
var selectedSeedType = SeedType.CARROT; // Default selected seed
var seedSelector; // Global seed selector for accessing from plot click
var tooltip; // Tooltip for showing crop information
var plotCounter; // Display for unlocked plots
// Create game title
var titleText = new Text2("Harvest Haven", {
size: 140,
fill: 0x006400
});
titleText.anchor.set(0.5, 0);
titleText.x = gameWidth / 2;
titleText.y = 30;
game.addChild(titleText);
// Create farm grid
function createFarmGrid() {
var gridWidth = gridSize;
var gridHeight = gridSize;
var startX = (gameWidth - (plotSize * gridWidth + plotSpacing * (gridWidth - 1))) / 2;
var startY = 200;
// Get number of unlocked plots from storage
var unlockedPlots = storage.unlockedPlots || 2;
// Calculate center positions
var centerRow = Math.floor(gridHeight / 2);
var centerCol = Math.floor(gridWidth / 2);
var plotCount = 0;
for (var row = 0; row < gridHeight; row++) {
for (var col = 0; col < gridWidth; col++) {
var plot = new FarmPlot();
plot.x = startX + col * (plotSize + plotSpacing) + plotSize / 2;
plot.y = startY + row * (plotSize + plotSpacing) + plotSize / 2;
// Instead of unlocking first n plots, unlock center plots
var distanceFromCenter = Math.abs(row - centerRow) + Math.abs(col - centerCol);
// Unlock plots closest to the center
if (distanceFromCenter < gridSize && plotCount < unlockedPlots) {
plot.locked = false;
plotCount++;
}
// Update visual to match lock state
plot.updateLockVisual();
farmPlots.push(plot);
game.addChild(plot);
}
}
// Create plot counter display
plotCounter = new PlotCounter();
plotCounter.x = 250;
plotCounter.y = startY + gridHeight * (plotSize + plotSpacing) + 50;
plotCounter.updateCount(unlockedPlots);
game.addChild(plotCounter);
}
// Create tool selection panel
function createToolPanel() {
var toolbarY = gameHeight - 120;
var toolSpacing = 130;
// Load unlocked tools from storage
var unlockedTools = storage.unlockedTools || {};
// Update tool configs with saved unlock status
Object.keys(ToolConfig.advanced).forEach(function (key) {
if (unlockedTools[ToolConfig.advanced[key].name]) {
ToolConfig.advanced[key].unlocked = true;
}
});
// Create basic tools panel
var basicToolCount = Object.keys(ToolConfig.basic).length;
var startX = (gameWidth - toolSpacing * basicToolCount) / 2 + 65;
// Add basic tools
Object.keys(ToolConfig.basic).forEach(function (key, i) {
var toolData = ToolConfig.basic[key];
var tool = new Tool(ToolType[key], false, toolData);
tool.x = startX + i * toolSpacing;
tool.y = toolbarY;
tools.push(tool);
game.addChild(tool);
});
// Add "Advanced Tools" label
var advLabel = new Text2("Advanced Tools", {
size: 50,
fill: 0xFFFFFF
});
advLabel.anchor.set(0.5, 0.5);
advLabel.x = gameWidth / 2;
advLabel.y = toolbarY - 150;
game.addChild(advLabel);
// Create advanced tools panel
var advancedToolCount = Object.keys(ToolConfig.advanced).length;
startX = (gameWidth - toolSpacing * advancedToolCount) / 2 + 65;
var advToolbarY = toolbarY - 220;
// Add advanced tools
Object.keys(ToolConfig.advanced).forEach(function (key, i) {
var toolData = ToolConfig.advanced[key];
var tool = new Tool(ToolType[key], true, toolData);
tool.x = startX + i * toolSpacing;
tool.y = advToolbarY;
tools.push(tool);
game.addChild(tool);
});
// Set initial selected tool
selectTool(currentTool);
// Add panel backgrounds
var basicPanelBackground = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: gameWidth / 200,
scaleY: 2,
tint: 0x4b0082,
alpha: 0.5
});
basicPanelBackground.x = gameWidth / 2;
basicPanelBackground.y = toolbarY;
game.addChildAt(basicPanelBackground, 0);
var advPanelBackground = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: gameWidth / 200,
scaleY: 2,
tint: 0x4b0082,
alpha: 0.5
});
advPanelBackground.x = gameWidth / 2;
advPanelBackground.y = advToolbarY;
game.addChildAt(advPanelBackground, 0);
// Add seed selector button next to seeds tool
var seedButton = tools.find(function (tool) {
return !tool.isAdvanced && tool.toolType === ToolType.SEEDS;
});
var seedSelectButton = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
tint: 0x8b5a2b
});
seedSelectButton.x = seedButton.x + 60;
seedSelectButton.y = toolbarY;
game.addChild(seedSelectButton);
var arrowText = new Text2("▼", {
size: 60,
fill: 0xFFFFFF
});
arrowText.anchor.set(0.5, 0.5);
arrowText.x = seedSelectButton.x;
arrowText.y = toolbarY;
game.addChild(arrowText);
// Create seed selector (using game-wide variable)
seedSelector = new SeedSelector();
seedSelector.x = gameWidth / 2;
seedSelector.y = toolbarY - 200;
seedSelector.visible = false;
game.addChild(seedSelector);
// Seed selector button event
seedSelectButton.interactive = true;
seedSelectButton.down = function (x, y, obj) {
seedSelector.show();
};
// Add town button on the bottom right corner
var townButton = new Container();
var townButtonBg = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5,
tint: 0x4b0082
});
townButton.addChild(townButtonBg);
var townText = new Text2("Town", {
size: 50,
fill: 0xFFFFFF
});
townText.anchor.set(0.5, 0.5);
townButton.addChild(townText);
townButton.x = gameWidth - 120;
townButton.y = gameHeight - 80;
townButton.interactive = true;
game.addChild(townButton);
// Town button event
townButton.down = function (x, y, obj) {
town.show();
};
}
// Create coin display
function createCoinDisplay() {
coinDisplay = new CoinDisplay();
coinDisplay.x = gameWidth - 100;
coinDisplay.y = 80;
coinDisplay.updateCoins(coins);
game.addChild(coinDisplay);
}
// Add coins to player's balance
function addCoins(amount) {
coins += amount;
storage.coins = coins;
// Update display
coinDisplay.updateCoins(coins);
// Show floating coin animation
for (var i = 0; i < amount; i++) {
var coin = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
// Random starting position near cursor
coin.x = 200 + Math.random() * 100;
coin.y = 200 + Math.random() * 100;
game.addChild(coin);
// Animate coin floating up and towards coin display
tween(coin, {
x: coinDisplay.x,
y: coinDisplay.y,
alpha: 0.8,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 800 + Math.random() * 400,
easing: tween.easeOut,
onFinish: function onFinish() {
coin.destroy();
// Flash coin display
LK.effects.flashObject(coinDisplay, 0xFFFF00, 300);
}
});
}
}
// Find plots near a given plot within a specified radius
function findNearbyPlots(centerPlot, radius) {
var nearby = [];
// Calculate approximate grid position of centerPlot
var plotSize = 180;
var plotSpacing = 10;
var totalSize = plotSize + plotSpacing;
// For irrigation system (3x3 area) special handling
if (currentTool === "Irrigation System" && radius === 1) {
// Use a more rectangular/grid-like pattern for irrigation
farmPlots.forEach(function (plot) {
if (plot === centerPlot || plot.locked) {
return;
} // Skip the center plot and locked plots
// Get plots in a 3x3 grid (check if they're within 1 grid cell)
var dx = Math.abs(plot.x - centerPlot.x);
var dy = Math.abs(plot.y - centerPlot.y);
// If within a single grid cell horizontally and vertically
if (dx <= totalSize + 10 && dy <= totalSize + 10) {
nearby.push(plot);
}
});
return nearby;
}
// Regular radius-based search for other tools
farmPlots.forEach(function (plot) {
if (plot === centerPlot || plot.locked) {
return;
} // Skip the center plot and locked plots
// Calculate distance (using squared distance for efficiency)
var dx = plot.x - centerPlot.x;
var dy = plot.y - centerPlot.y;
var distanceSquared = dx * dx + dy * dy;
// Compare with radius (converted to pixels)
var radiusPixels = totalSize * radius + plotSize / 2;
if (distanceSquared <= radiusPixels * radiusPixels) {
nearby.push(plot);
}
});
return nearby;
}
function selectTool(toolType) {
currentTool = toolType;
// Update tool visuals
for (var i = 0; i < tools.length; i++) {
var isSelected = false;
if (typeof toolType === "string") {
// For advanced tools which use string names
isSelected = tools[i].isAdvanced && tools[i].toolData && tools[i].toolData.name === toolType;
} else {
// For basic tools which use ToolType enum
isSelected = !tools[i].isAdvanced && tools[i].toolType === toolType;
}
tools[i].setSelected(isSelected);
}
// Show visual indication of tool's effect area if it's an advanced tool
if (toolType === "Irrigation System") {
// Show irrigation system effect indicator - not implemented in tool info text
var titleText = new Text2("Irrigation System: Waters in a 3x3 area", {
size: 50,
fill: 0x1E90FF
});
titleText.anchor.set(0.5, 0);
titleText.x = gameWidth / 2;
titleText.y = 150;
// Remove after delay
game.addChild(titleText);
LK.setTimeout(function () {
titleText.destroy();
}, 3000);
} else if (toolType === "Auto-Tilling Tool") {
// Show auto-tilling effect indicator
var titleText = new Text2("Auto-Tilling Tool: Tills in a 3x3 area", {
size: 50,
fill: 0xAA00FF
});
titleText.anchor.set(0.5, 0);
titleText.x = gameWidth / 2;
titleText.y = 150;
// Remove after delay
game.addChild(titleText);
LK.setTimeout(function () {
titleText.destroy();
}, 3000);
}
}
// Initialize game
createFarmGrid();
createToolPanel();
createCoinDisplay();
// Create and add town
var town = new Town();
town.x = gameWidth / 2;
town.y = gameHeight / 2;
game.addChild(town);
// Create tooltip for crop information
tooltip = new Tooltip();
game.addChild(tooltip);
// Play background music
LK.playMusic('farm_music', {
fade: {
start: 0,
end: 0.3,
duration: 2000
}
});
// Game update loop
game.update = function () {
// Update all plots
for (var i = 0; i < farmPlots.length; i++) {
// Farm plots have their own update method called by LK engine
}
};
// Game input handling
var lastTouchPosition = {
x: 0,
y: 0
};
game.down = function (x, y, obj) {
lastTouchPosition.x = x;
lastTouchPosition.y = y;
};
game.move = function (x, y, obj) {
lastTouchPosition.x = x;
lastTouchPosition.y = y;
// Update tooltip position if visible
if (tooltip.visible) {
tooltip.x = Math.min(Math.max(x, 250), gameWidth - 250);
tooltip.y = Math.min(Math.max(y - 80, 100), gameHeight - 100);
// Check if mouse/touch is over any crop
var isOverAnyCrop = false;
for (var i = 0; i < farmPlots.length; i++) {
var plot = farmPlots[i];
if (plot.state >= PlotState.SEEDED && Math.abs(x - plot.x) < plotSize / 2 && Math.abs(y - plot.y) < plotSize / 2) {
isOverAnyCrop = true;
// Update tooltip with this plot's information
if (!plot.isHovered) {
// Different plot than before
for (var j = 0; j < farmPlots.length; j++) {
farmPlots[j].isHovered = false;
}
plot.isHovered = true;
tooltip.updateInfo(plot);
}
break;
}
}
// Hide tooltip if not over any crop
if (!isOverAnyCrop) {
tooltip.hide();
for (var i = 0; i < farmPlots.length; i++) {
farmPlots[i].isHovered = false;
}
}
}
};
game.up = function (x, y, obj) {
// We don't need to do anything special here
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
coins: 100,
unlockedPlots: 2,
unlockedSeeds: ["wheat", "corn", "tomato", "carrot", "potato", "strawberry"],
unlockedTools: {}
});
/****
* Classes
****/
var CoinDisplay = Container.expand(function () {
var self = Container.call(this);
var coinIcon = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
x: -60
});
var coinText = new Text2("0", {
size: 80,
fill: 0xFFFFFF
});
coinText.anchor.set(0, 0.5);
coinText.x = -30;
self.addChild(coinText);
self.updateCoins = function (amount) {
coinText.setText(amount.toString());
};
return self;
});
var FarmPlot = Container.expand(function () {
var self = Container.call(this);
self.state = PlotState.EMPTY;
self.growthTimer = 0;
self.seedType = null;
self.locked = true; // Plot starts locked by default
var soilGraphic = self.attachAsset('soil', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x555555 // Darker tint for locked plots
});
// Lock overlay
var lockOverlay = null;
// Update the visual state based on locked status
self.updateLockVisual = function () {
// Update soil tint
if (soilGraphic) {
soilGraphic.tint = self.locked ? 0x555555 : 0xFFFFFF;
}
// Update lock overlay
if (self.locked) {
if (!lockOverlay) {
lockOverlay = new Text2("🔒", {
size: 90,
fill: 0xFFFFFF
});
lockOverlay.anchor.set(0.5, 0.5);
lockOverlay.y = -20;
self.addChild(lockOverlay);
}
} else if (lockOverlay) {
lockOverlay.destroy();
lockOverlay = null;
}
};
var cropGraphic = null;
self.till = function () {
if (self.state === PlotState.EMPTY) {
self.state = PlotState.TILLED;
soilGraphic.destroy();
soilGraphic = self.attachAsset('tilled_soil', {
anchorX: 0.5,
anchorY: 0.5
});
// Play shovel sound effect when tilling
LK.getSound('till').play({
pitch: 0.85 + Math.random() * 0.3
});
return true;
}
return false;
};
self.plant = function (seedType) {
if (self.state === PlotState.TILLED) {
self.state = PlotState.SEEDED;
self.seedType = seedType;
if (cropGraphic) {
cropGraphic.destroy();
}
// Use the specific seed asset for each seed type
var seedAssetId = 'seed';
switch (seedType) {
case SeedType.WHEAT:
seedAssetId = 'wheat_seed';
break;
case SeedType.CORN:
seedAssetId = 'corn_seed';
break;
case SeedType.TOMATO:
seedAssetId = 'tomato_seed';
break;
case SeedType.CARROT:
seedAssetId = 'carrot_seed';
break;
case SeedType.POTATO:
seedAssetId = 'potato_seed';
break;
case SeedType.STRAWBERRY:
seedAssetId = 'strawberry_seed';
break;
}
cropGraphic = self.attachAsset(seedAssetId, {
anchorX: 0.5,
anchorY: 0.5,
y: -20
});
// Play rustling sound effect when planting seeds
LK.getSound('plant').play({
pitch: 0.9 + Math.random() * 0.2,
volume: 0.6
});
return true;
}
return false;
};
self.water = function () {
if (self.state === PlotState.SEEDED) {
self.state = PlotState.WATERED;
self.growthTimer = 0;
var waterDroplet = self.attachAsset('water_drop', {
anchorX: 0.5,
anchorY: 0.5,
y: -50,
alpha: 0.8
});
tween(waterDroplet, {
alpha: 0
}, {
duration: 1500,
onFinish: function onFinish() {
waterDroplet.destroy();
}
});
// Play splash sound effect when watering
LK.getSound('water').play({
pitch: 0.9 + Math.random() * 0.2,
volume: 0.7
});
return true;
}
return false;
};
self.grow = function () {
// Get crop configuration based on seed type
var cropConfig = CropConfig[self.seedType] || CropConfig.carrot;
var growthTime = cropConfig.growthTime;
// Calculate growth stage thresholds
var stage1Time = growthTime * 0.25; // 25% of total growth time
var stage2Time = growthTime * 0.5; // 50% of total growth time
var stage3Time = growthTime * 0.75; // 75% of total growth time
var harvestTime = growthTime; // 100% of total growth time
// Helper function to get appropriate asset for crop type and stage
function getCropAsset(seedType, stage) {
var assetId = 'crop_stage' + stage; // Default fallback
if (stage === 'growing') {
// Growing stage
switch (seedType) {
case SeedType.WHEAT:
return 'wheat_growing';
case SeedType.CORN:
return 'corn_growing';
case SeedType.TOMATO:
return 'tomato_growing';
case SeedType.CARROT:
return 'carrot_growing';
case SeedType.POTATO:
return 'potato_growing';
case SeedType.STRAWBERRY:
return 'strawberry_growing';
default:
return 'crop_stage2';
}
} else if (stage === 'mature') {
// Mature stage
switch (seedType) {
case SeedType.WHEAT:
return 'wheat_mature';
case SeedType.CORN:
return 'corn_mature';
case SeedType.TOMATO:
return 'tomato_mature';
case SeedType.CARROT:
return 'carrot_mature';
case SeedType.POTATO:
return 'potato_mature';
case SeedType.STRAWBERRY:
return 'strawberry_mature';
default:
return 'harvest_ready';
}
}
return assetId;
}
if (self.state === PlotState.WATERED) {
self.growthTimer++;
if (self.growthTimer >= stage1Time) {
self.state = PlotState.GROWING1;
if (cropGraphic) {
cropGraphic.destroy();
}
cropGraphic = self.attachAsset(getCropAsset(self.seedType, 'growing'), {
anchorX: 0.5,
anchorY: 1.0,
y: 0
});
}
} else if (self.state === PlotState.GROWING1) {
self.growthTimer++;
if (self.growthTimer >= stage2Time) {
self.state = PlotState.GROWING2;
if (cropGraphic) {
cropGraphic.destroy();
}
cropGraphic = self.attachAsset(getCropAsset(self.seedType, 'growing'), {
anchorX: 0.5,
anchorY: 1.0,
y: 0
});
cropGraphic.scaleX = 1.2;
cropGraphic.scaleY = 1.2;
}
} else if (self.state === PlotState.GROWING2) {
self.growthTimer++;
if (self.growthTimer >= stage3Time) {
self.state = PlotState.GROWING3;
if (cropGraphic) {
cropGraphic.destroy();
}
cropGraphic = self.attachAsset(getCropAsset(self.seedType, 'growing'), {
anchorX: 0.5,
anchorY: 1.0,
y: 0
});
cropGraphic.scaleX = 1.4;
cropGraphic.scaleY = 1.4;
}
} else if (self.state === PlotState.GROWING3) {
self.growthTimer++;
if (self.growthTimer >= harvestTime) {
self.state = PlotState.READY;
if (cropGraphic) {
cropGraphic.destroy();
}
cropGraphic = self.attachAsset(getCropAsset(self.seedType, 'mature'), {
anchorX: 0.5,
anchorY: 1.0,
y: 0
});
// Add bouncing animation for ready crops
tween(cropGraphic, {
y: -10
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(cropGraphic, {
y: 0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (cropGraphic && cropGraphic.parent) {
self.bounceAnimation();
}
}
});
}
});
}
}
};
self.bounceAnimation = function () {
if (self.state === PlotState.READY && cropGraphic && cropGraphic.parent) {
tween.stop(cropGraphic); // Stop any running tweens first
tween(cropGraphic, {
y: -10
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (cropGraphic && cropGraphic.parent) {
// Check if cropGraphic still exists
tween(cropGraphic, {
y: 0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (cropGraphic && cropGraphic.parent) {
self.bounceAnimation();
}
}
});
}
}
});
}
};
self.harvest = function () {
if (self.state === PlotState.READY) {
var harvestValue = 0;
if (self.seedType && CropConfig[self.seedType]) {
harvestValue = CropConfig[self.seedType].value;
} else {
harvestValue = 3; // Default value if seedType is invalid
}
self.reset();
// Play plucking sound effect when harvesting
LK.getSound('harvest').play({
pitch: 0.8 + Math.random() * 0.4,
volume: 0.8
});
return harvestValue;
}
return 0;
};
self.reset = function () {
self.state = PlotState.EMPTY;
self.growthTimer = 0;
self.seedType = null;
if (cropGraphic) {
cropGraphic.destroy();
cropGraphic = null;
}
if (soilGraphic) {
soilGraphic.destroy();
}
soilGraphic = self.attachAsset('soil', {
anchorX: 0.5,
anchorY: 0.5,
tint: self.locked ? 0x555555 : 0xFFFFFF // Maintain lock tint
});
self.updateLockVisual(); // Update lock visual after reset
};
self.down = function (x, y, obj) {
// If plot is locked, show purchase dialog
if (self.locked) {
if (coins >= 200) {
// Create confirmation dialog
var confirmDialog = new Container();
// Background
var dialogBg = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4,
scaleY: 2,
tint: 0x333333,
alpha: 0.9
});
confirmDialog.addChild(dialogBg);
// Message
var message = new Text2("Unlock this plot for 200 coins?", {
size: 50,
fill: 0xFFFFFF
});
message.anchor.set(0.5, 0);
message.y = -50;
confirmDialog.addChild(message);
// Yes button
var yesButton = new Container();
var yesBg = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1,
tint: 0x00AA00
});
yesButton.addChild(yesBg);
var yesText = new Text2("Yes", {
size: 50,
fill: 0xFFFFFF
});
yesText.anchor.set(0.5, 0.5);
yesButton.addChild(yesText);
yesButton.x = -100;
yesButton.y = 50;
yesButton.interactive = true;
confirmDialog.addChild(yesButton);
// No button
var noButton = new Container();
var noBg = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1,
tint: 0xAA0000
});
noButton.addChild(noBg);
var noText = new Text2("No", {
size: 50,
fill: 0xFFFFFF
});
noText.anchor.set(0.5, 0.5);
noButton.addChild(noText);
noButton.x = 100;
noButton.y = 50;
noButton.interactive = true;
confirmDialog.addChild(noButton);
// Position dialog
confirmDialog.x = gameWidth / 2;
confirmDialog.y = gameHeight / 2;
game.addChild(confirmDialog);
// Button handlers
yesButton.down = function () {
// Purchase plot
coins -= 200;
storage.coins = coins;
coinDisplay.updateCoins(coins);
// Unlock plot
self.locked = false;
self.updateLockVisual();
// Increment unlocked plots count
storage.unlockedPlots = (storage.unlockedPlots || 0) + 1;
// Update plot counter display
if (plotCounter) {
plotCounter.updateCount(storage.unlockedPlots);
}
// Visual feedback
LK.effects.flashObject(self, 0x00FF00, 500);
// Remove dialog
confirmDialog.destroy();
};
noButton.down = function () {
// Just remove dialog
confirmDialog.destroy();
};
} else {
// Not enough coins
LK.effects.flashObject(self, 0xFF0000, 500);
}
return;
}
var toolAction = false;
// Handle both basic and advanced tools
switch (currentTool) {
case ToolType.HOE:
case "Auto-Tilling Tool":
toolAction = self.till();
// If using auto-tiller and action succeeded, till adjacent plots
if (toolAction && currentTool === "Auto-Tilling Tool") {
// Find nearby plots
var nearbyPlots = findNearbyPlots(self, 1);
nearbyPlots.forEach(function (plot) {
if (!plot.locked) {
plot.till();
// Visual feedback for each plot
LK.effects.flashObject(plot, 0xAA7722, 300);
}
});
}
break;
case ToolType.SEEDS:
// If the plot is tilled, show seed selector
if (self.state === PlotState.TILLED) {
// Position seed selector over this plot
seedSelector.x = self.x;
seedSelector.y = self.y - 200;
seedSelector.show();
// Set the target plot for planting
seedSelector.targetPlot = self;
} else {
// If not tilled, try to plant with current seed
toolAction = self.plant(selectedSeedType);
}
break;
case ToolType.WATER:
case "Irrigation System":
toolAction = self.water();
// If using irrigation system and action succeeded, water adjacent plots
if (toolAction && currentTool === "Irrigation System") {
// Find nearby plots
var nearbyPlots = findNearbyPlots(self, 1);
nearbyPlots.forEach(function (plot) {
if (!plot.locked) {
var waterSuccess = plot.water();
if (waterSuccess) {
// Visual feedback for each watered plot
LK.effects.flashObject(plot, 0x1E90FF, 300);
}
}
});
}
break;
case ToolType.HARVEST:
case "Better Harvesting Tools":
var harvestValue = self.harvest();
if (harvestValue > 0) {
toolAction = true;
// Give bonus yield if using better harvesting tools
if (currentTool === "Better Harvesting Tools") {
harvestValue = Math.floor(harvestValue * 1.5); // 50% bonus
}
addCoins(harvestValue);
}
break;
case ToolType.SHOVEL:
// Shovel resets the plot to empty state
if (self.state !== PlotState.EMPTY) {
self.reset();
toolAction = true;
}
break;
}
if (toolAction) {
// Visual feedback
LK.effects.flashObject(self, 0xFFFFFF, 300);
}
};
self.update = function () {
if (self.state >= PlotState.WATERED && self.state < PlotState.READY) {
self.grow();
}
// Check for hover over planted crops
if (self.state >= PlotState.SEEDED && Math.abs(lastTouchPosition.x - self.x) < plotSize / 2 && Math.abs(lastTouchPosition.y - self.y) < plotSize / 2) {
// Mouse is over this plot
if (!self.isHovered) {
self.isHovered = true;
tooltip.updateInfo(self);
tooltip.show(lastTouchPosition.x, lastTouchPosition.y);
}
} else if (self.isHovered) {
self.isHovered = false;
// Don't hide tooltip here as another plot might be hovered
}
};
return self;
});
var PlotCounter = Container.expand(function () {
var self = Container.call(this);
// Create background
var background = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.5,
scaleY: 1,
tint: 0x4b0082,
alpha: 0.7
});
self.addChild(background);
// Plot counter text
var counterText = new Text2("Plots: 0/0", {
size: 50,
fill: 0xFFFFFF
});
counterText.anchor.set(0.5, 0.5);
self.addChild(counterText);
// Update counter display
self.updateCount = function (unlocked) {
counterText.setText("Plots: " + unlocked + "/" + farmPlots.length);
};
return self;
});
var SeedSelector = Container.expand(function () {
var self = Container.call(this);
// Target plot to plant on after selection
self.targetPlot = null;
// Create background
var background = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4,
scaleY: 1.5,
tint: 0x8b5a2b,
alpha: 0.8
});
self.addChild(background);
// Title
var titleText = new Text2("Select Seed", {
size: 70,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0);
titleText.y = -70;
self.addChild(titleText);
// Create seed buttons
var seedButtons = [];
var seedTypes = [{
type: SeedType.WHEAT,
name: "Wheat",
color: 0xF5DEB3
}, {
type: SeedType.CORN,
name: "Corn",
color: 0xFFF44F
}, {
type: SeedType.TOMATO,
name: "Tomato",
color: 0xFF6347
}, {
type: SeedType.CARROT,
name: "Carrot",
color: 0xFFA500
}, {
type: SeedType.POTATO,
name: "Potato",
color: 0xA0522D
}, {
type: SeedType.STRAWBERRY,
name: "Strawberry",
color: 0xFF3366
}];
var buttonSize = 60;
var spacing = 80;
var startX = -(spacing * (seedTypes.length - 1)) / 2;
seedTypes.forEach(function (seedInfo, index) {
var button = new Container();
// Seed visual
var seedVisual = LK.getAsset('seed', {
anchorX: 0.5,
anchorY: 0.5,
tint: seedInfo.color
});
button.addChild(seedVisual);
// Seed name
var nameText = new Text2(seedInfo.name, {
size: 40,
fill: 0xFFFFFF
});
nameText.anchor.set(0.5, 0);
nameText.y = 40;
button.addChild(nameText);
// Growth time text
var growthDays = CropConfig[seedInfo.type].growthTime / (60 * 60);
var growthText = new Text2(growthDays + " days", {
size: 30,
fill: 0xCCCCCC
});
growthText.anchor.set(0.5, 0);
growthText.y = 70;
button.addChild(growthText);
// Position button
button.x = startX + index * spacing;
button.y = 0;
button.interactive = true;
// Selection highlight
var highlight = LK.getAsset('seed', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFFFF00,
alpha: 0
});
button.addChildAt(highlight, 0);
// Set button data
button.seedType = seedInfo.type;
button.highlight = highlight;
// Add to container and array
self.addChild(button);
seedButtons.push(button);
// Button event
button.down = function (x, y, obj) {
// Set the selected seed type
selectedSeedType = button.seedType;
updateSelectedSeed();
// If we have a target plot, plant the seed and hide the selector
if (self.targetPlot) {
// Try to plant the selected seed
var success = self.targetPlot.plant(selectedSeedType);
if (success) {
// Visual feedback
LK.effects.flashObject(self.targetPlot, 0xFFFFFF, 300);
}
// Hide selector regardless of success
self.visible = false;
self.targetPlot = null;
}
};
});
// Update visual selection
function updateSelectedSeed() {
seedButtons.forEach(function (button) {
if (button.seedType === selectedSeedType) {
button.highlight.alpha = 0.3;
} else {
button.highlight.alpha = 0;
}
});
}
// Close button
var closeButton = new Container();
var closeVisual = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
tint: 0xFF5555
});
closeButton.addChild(closeVisual);
var closeText = new Text2("X", {
size: 60,
fill: 0xFFFFFF
});
closeText.anchor.set(0.5, 0.5);
closeButton.addChild(closeText);
closeButton.x = background.width / 2 - 30;
closeButton.y = -background.height / 2 + 30;
self.addChild(closeButton);
// Close event
closeButton.down = function (x, y, obj) {
self.visible = false;
self.targetPlot = null; // Clear target plot when closing
};
self.show = function () {
self.visible = true;
updateSelectedSeed();
};
// Initialize with default selection
updateSelectedSeed();
return self;
});
var Tool = Container.expand(function (toolType, isAdvanced, toolData) {
var self = Container.call(this);
self.toolType = toolType;
self.isAdvanced = isAdvanced || false;
self.toolData = toolData || null;
// Determine which asset to use
var assetId;
if (self.isAdvanced && self.toolData) {
// Use advanced tool specific sprites
if (self.toolData.name === "Irrigation System") {
assetId = 'tool_irrigation';
} else if (self.toolData.name === "Better Harvesting Tools") {
assetId = 'tool_better_harvest';
} else if (self.toolData.name === "Auto-Tilling Tool") {
assetId = 'tool_auto_tiller';
} else {
assetId = self.toolData.icon;
}
} else {
// Use basic tool sprites
if (toolType === ToolType.HOE) {
assetId = 'tool_hoe';
} else if (toolType === ToolType.SEEDS) {
assetId = 'tool_seeds';
} else if (toolType === ToolType.WATER) {
assetId = 'tool_water';
} else if (toolType === ToolType.HARVEST) {
assetId = 'tool_harvest';
} else if (toolType === ToolType.SHOVEL) {
assetId = 'tool_shovel';
} else {
assetId = 'tool_hoe'; // Default
}
}
var toolGraphic = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Apply tint if it's an advanced tool with tint
if (self.isAdvanced && self.toolData && self.toolData.tint) {
toolGraphic.tint = self.toolData.tint;
}
// Create tool name label
var toolName = new Text2(self.isAdvanced && self.toolData ? self.toolData.name : ToolType.HOE === toolType ? "Hoe" : ToolType.SEEDS === toolType ? "Seeds" : ToolType.WATER === toolType ? "Water" : ToolType.HARVEST === toolType ? "Harvest" : "Tool", {
size: 36,
fill: 0xFFFFFF
});
toolName.anchor.set(0.5, 0);
toolName.y = 80;
self.addChild(toolName);
// Add lock icon or price for locked tools
self.lockIcon = null;
self.priceText = null;
self.updateLockStatus = function () {
// Remove existing lock/price if any
if (self.lockIcon) {
self.lockIcon.destroy();
self.lockIcon = null;
}
if (self.priceText) {
self.priceText.destroy();
self.priceText = null;
}
// If it's an advanced tool and not unlocked, show lock or price
if (self.isAdvanced && self.toolData && !self.toolData.unlocked) {
// Show price
self.priceText = new Text2(self.toolData.price.toString(), {
size: 40,
fill: 0xFFDD00
});
self.priceText.anchor.set(0.5, 0);
self.priceText.y = -70;
self.addChild(self.priceText);
// Dim the tool
toolGraphic.alpha = 0.5;
} else {
toolGraphic.alpha = 1;
}
};
// Highlight border when selected
var selectedBorder = null;
self.setSelected = function (selected) {
if (selected) {
if (!selectedBorder) {
selectedBorder = new Container();
var borderSize = 10;
var borderAsset = LK.getAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2,
tint: 0xFFFF00,
alpha: 0.5
});
selectedBorder.addChild(borderAsset);
self.addChildAt(selectedBorder, 0);
}
} else {
if (selectedBorder) {
selectedBorder.destroy();
selectedBorder = null;
}
}
};
self.down = function (x, y, obj) {
// If it's a locked advanced tool, try to purchase
if (self.isAdvanced && self.toolData && !self.toolData.unlocked) {
if (coins >= self.toolData.price) {
// Purchase the tool
coins -= self.toolData.price;
storage.coins = coins;
coinDisplay.updateCoins(coins);
self.toolData.unlocked = true;
// Save unlocked status
var unlockedTools = storage.unlockedTools || {};
unlockedTools[self.toolData.name] = true;
storage.unlockedTools = unlockedTools;
// Update visuals
self.updateLockStatus();
// Show success animation
LK.effects.flashObject(self, 0x00FF00, 500);
} else {
// Not enough coins
LK.effects.flashObject(self, 0xFF0000, 500);
}
} else {
// Normal tool selection
selectTool(self.isAdvanced ? self.toolData.name : self.toolType);
}
};
// Initialize lock/price display
if (self.isAdvanced) {
self.updateLockStatus();
}
return self;
});
var Tooltip = Container.expand(function () {
var self = Container.call(this);
// Create background
var background = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.5,
scaleY: 1.4,
tint: 0x333333,
alpha: 0.8
});
self.addChild(background);
// Water level text
var waterLevelText = new Text2("Water Level: Unknown", {
size: 40,
fill: 0x1E90FF
});
waterLevelText.anchor.set(0.5, 0);
waterLevelText.y = -30;
self.addChild(waterLevelText);
// Growth time text
var growthTimeText = new Text2("Time Till Grown: Unknown", {
size: 40,
fill: 0xFFFFFF
});
growthTimeText.anchor.set(0.5, 0);
growthTimeText.y = 10;
self.addChild(growthTimeText);
// Update tooltip information
self.updateInfo = function (plot) {
if (!plot || plot.state === PlotState.EMPTY || plot.state === PlotState.TILLED) {
self.visible = false;
return;
}
// Calculate water level text
var waterLevel = "None";
if (plot.state >= PlotState.WATERED) {
if (plot.state === PlotState.WATERED) {
waterLevel = "High";
} else if (plot.state === PlotState.GROWING1) {
waterLevel = "High";
} else if (plot.state === PlotState.GROWING2) {
waterLevel = "Medium";
} else if (plot.state === PlotState.GROWING3) {
waterLevel = "Low";
} else if (plot.state === PlotState.READY) {
waterLevel = "Low";
}
}
waterLevelText.setText("Water Level: " + waterLevel);
// Calculate growth time remaining
var timeText = "Ready to Harvest!";
if (plot.state < PlotState.READY && plot.state >= PlotState.WATERED) {
var cropConfig = CropConfig[plot.seedType] || CropConfig.carrot;
var totalGrowthTime = cropConfig.growthTime;
var timeRemaining = totalGrowthTime - plot.growthTimer;
// Convert ticks to days (60 ticks per second, 60 seconds per minute, 60 minutes per hour)
var daysRemaining = Math.ceil(timeRemaining / (60 * 60));
timeText = "Time Till Grown: " + daysRemaining + " days";
}
growthTimeText.setText(timeText);
self.visible = true;
};
// Hide tooltip
self.hide = function () {
self.visible = false;
};
// Initialize as hidden
self.visible = false;
// Add show animation
self.show = function (x, y) {
// Position tooltip near cursor but ensure it stays on screen
self.x = Math.min(Math.max(x, 250), gameWidth - 250);
self.y = Math.min(Math.max(y - 80, 100), gameHeight - 100);
// Animation effect
self.alpha = 0;
self.scale.x = 0.8;
self.scale.y = 0.8;
tween.stop(self);
tween(self, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOutQuad
});
self.visible = true;
};
return self;
});
var Town = Container.expand(function () {
var self = Container.call(this);
// Create town background
var background = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 8,
scaleY: 10,
tint: 0x8B4513,
alpha: 0.9
});
self.addChild(background);
// Town title
var titleText = new Text2("Town", {
size: 90,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0);
titleText.y = -450;
self.addChild(titleText);
// Create shops
var shops = [{
name: "Tool Shop",
description: "Upgrade your farming tools",
y: -300
}, {
name: "Seed Shop",
description: "Buy new seed varieties",
y: -100
}, {
name: "Market",
description: "Sell your crops for coins",
y: 100
}];
var shopButtons = [];
shops.forEach(function (shop) {
var shopButton = new Container();
// Shop button background
var buttonBg = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 6,
scaleY: 1.5,
tint: 0x6B4226
});
shopButton.addChild(buttonBg);
// Shop name
var nameText = new Text2(shop.name, {
size: 60,
fill: 0xFFFFFF
});
nameText.anchor.set(0.5, 0.5);
nameText.y = -25;
shopButton.addChild(nameText);
// Shop description
var descText = new Text2(shop.description, {
size: 40,
fill: 0xCCCCCC
});
descText.anchor.set(0.5, 0.5);
descText.y = 25;
shopButton.addChild(descText);
// Position and add
shopButton.y = shop.y;
shopButton.shopType = shop.name;
shopButton.interactive = true;
self.addChild(shopButton);
shopButtons.push(shopButton);
// Click handler
shopButton.down = function (x, y, obj) {
self.openShop(shop.name);
};
});
// Close button
var closeButton = new Container();
var closeVisual = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8,
tint: 0xFF5555
});
closeButton.addChild(closeVisual);
var closeText = new Text2("X", {
size: 60,
fill: 0xFFFFFF
});
closeText.anchor.set(0.5, 0.5);
closeButton.addChild(closeText);
closeButton.x = background.width / 2 - 30;
closeButton.y = -background.height / 2 + 30;
closeButton.interactive = true;
self.addChild(closeButton);
// Close event
closeButton.down = function (x, y, obj) {
self.hide();
};
// Currently open shop content
var currentShopContent = null;
// Shop handlers
self.openShop = function (shopType) {
// Clear current shop content if any
if (currentShopContent) {
currentShopContent.destroy();
currentShopContent = null;
}
// Create new shop content based on type
currentShopContent = new Container();
self.addChild(currentShopContent);
// Shop title
var shopTitle = new Text2(shopType, {
size: 80,
fill: 0xFFD700
});
shopTitle.anchor.set(0.5, 0.5);
shopTitle.y = -350;
currentShopContent.addChild(shopTitle);
// Shop specific content
if (shopType === "Tool Shop") {
createToolShop(currentShopContent);
} else if (shopType === "Seed Shop") {
createSeedShop(currentShopContent);
} else if (shopType === "Market") {
createMarket(currentShopContent);
}
// Update shop buttons visibility
shops.forEach(function (shop, index) {
shopButtons[index].visible = false;
});
// Add back button
var backButton = new Container();
var backVisual = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 1,
tint: 0x4B0082
});
backButton.addChild(backVisual);
var backText = new Text2("Back", {
size: 50,
fill: 0xFFFFFF
});
backText.anchor.set(0.5, 0.5);
backButton.addChild(backText);
backButton.y = 400;
backButton.interactive = true;
currentShopContent.addChild(backButton);
backButton.down = function (x, y, obj) {
if (currentShopContent) {
currentShopContent.destroy();
currentShopContent = null;
}
// Show shop buttons again
shops.forEach(function (shop, index) {
shopButtons[index].visible = true;
});
};
};
// Create Tool Shop content
function createToolShop(container) {
var toolsPerRow = 3;
var spacing = 200;
var startX = -(spacing * (toolsPerRow - 1)) / 2;
var startY = -200;
var advancedTools = [];
Object.keys(ToolConfig.advanced).forEach(function (key) {
advancedTools.push(ToolConfig.advanced[key]);
});
advancedTools.forEach(function (toolData, index) {
var row = Math.floor(index / toolsPerRow);
var col = index % toolsPerRow;
var toolButton = new Container();
// Tool icon
var toolIcon = LK.getAsset(toolData.icon, {
anchorX: 0.5,
anchorY: 0.5,
tint: toolData.tint || 0xFFFFFF
});
toolButton.addChild(toolIcon);
// Tool name
var nameText = new Text2(toolData.name, {
size: 40,
fill: 0xFFFFFF
});
nameText.anchor.set(0.5, 0);
nameText.y = 70;
toolButton.addChild(nameText);
// Tool description
var descText = new Text2(toolData.description, {
size: 30,
fill: 0xCCCCCC
});
descText.anchor.set(0.5, 0);
descText.y = 100;
toolButton.addChild(descText);
// Price or status
var statusText = new Text2(toolData.unlocked ? "Owned" : toolData.price + " coins", {
size: 40,
fill: toolData.unlocked ? 0x00FF00 : 0xFFD700,
style: {} // Add style object for later modification
});
statusText.anchor.set(0.5, 0.5);
statusText.y = -60;
toolButton.addChild(statusText);
// Position and add
toolButton.x = startX + col * spacing;
toolButton.y = startY + row * 220;
toolButton.toolData = toolData;
toolButton.interactive = !toolData.unlocked;
container.addChild(toolButton);
// Click handler only for locked tools
if (!toolData.unlocked) {
toolButton.down = function (x, y, obj) {
if (coins >= toolData.price) {
// Purchase the tool
coins -= toolData.price;
storage.coins = coins;
coinDisplay.updateCoins(coins);
toolData.unlocked = true;
// Save unlocked status
var unlockedTools = storage.unlockedTools || {};
unlockedTools[toolData.name] = true;
storage.unlockedTools = unlockedTools;
// Update tool panel
for (var i = 0; i < tools.length; i++) {
if (tools[i].isAdvanced && tools[i].toolData && tools[i].toolData.name === toolData.name) {
tools[i].updateLockStatus();
break;
}
}
// Update button
statusText.setText("Owned");
statusText.style.fill = 0x00FF00;
toolButton.interactive = false;
// Show success animation
LK.effects.flashObject(toolButton, 0x00FF00, 500);
} else {
// Not enough coins
LK.effects.flashObject(toolButton, 0xFF0000, 500);
}
};
}
});
}
// Create Seed Shop content
function createSeedShop(container) {
var seedsPerRow = 3;
var spacing = 200;
var startX = -(spacing * (seedsPerRow - 1)) / 2;
var startY = -200;
var seedTypes = [{
type: SeedType.WHEAT,
name: "Wheat",
color: 0xF5DEB3,
growthDays: 2,
price: 2
}, {
type: SeedType.CORN,
name: "Corn",
color: 0xFFF44F,
growthDays: 3,
price: 3
}, {
type: SeedType.TOMATO,
name: "Tomato",
color: 0xFF6347,
growthDays: 4,
price: 5
}, {
type: SeedType.CARROT,
name: "Carrot",
color: 0xFFA500,
growthDays: 3,
price: 3
}, {
type: SeedType.POTATO,
name: "Potato",
color: 0xA0522D,
growthDays: 5,
price: 6
}, {
type: SeedType.STRAWBERRY,
name: "Strawberry",
color: 0xFF3366,
growthDays: 6,
price: 8
}];
seedTypes.forEach(function (seedInfo, index) {
var row = Math.floor(index / seedsPerRow);
var col = index % seedsPerRow;
var seedButton = new Container();
// Seed visual
var seedVisual = LK.getAsset('seed', {
anchorX: 0.5,
anchorY: 0.5,
tint: seedInfo.color,
scaleX: 1.5,
scaleY: 1.5
});
seedButton.addChild(seedVisual);
// Seed name
var nameText = new Text2(seedInfo.name, {
size: 40,
fill: 0xFFFFFF
});
nameText.anchor.set(0.5, 0);
nameText.y = 50;
seedButton.addChild(nameText);
// Growth time
var timeText = new Text2(seedInfo.growthDays + " days", {
size: 30,
fill: 0xCCCCCC
});
timeText.anchor.set(0.5, 0);
timeText.y = 80;
seedButton.addChild(timeText);
// Price
var priceText = new Text2(seedInfo.price + " coins", {
size: 40,
fill: 0xFFD700
});
priceText.anchor.set(0.5, 0.5);
priceText.y = -60;
seedButton.addChild(priceText);
// Value text
var valueText = new Text2("Value: " + CropConfig[seedInfo.type].value + " coins", {
size: 30,
fill: 0x00FF00
});
valueText.anchor.set(0.5, 0);
valueText.y = 110;
seedButton.addChild(valueText);
// Position and add
seedButton.x = startX + col * spacing;
seedButton.y = startY + row * 220;
seedButton.seedType = seedInfo.type;
seedButton.price = seedInfo.price;
seedButton.interactive = true;
container.addChild(seedButton);
// Click handler
seedButton.down = function (x, y, obj) {
if (coins >= seedButton.price) {
// Purchase the seed
coins -= seedButton.price;
storage.coins = coins;
coinDisplay.updateCoins(coins);
// Show success animation
LK.effects.flashObject(seedButton, 0x00FF00, 500);
// Select this seed type
selectedSeedType = seedButton.seedType;
selectTool(ToolType.SEEDS);
} else {
// Not enough coins
LK.effects.flashObject(seedButton, 0xFF0000, 500);
}
};
});
}
// Create Market content
function createMarket(container) {
var marketTitle = new Text2("Sell your harvested crops at the Market", {
size: 50,
fill: 0xFFFFFF
});
marketTitle.anchor.set(0.5, 0.5);
marketTitle.y = -250;
container.addChild(marketTitle);
var marketDesc = new Text2("Current market prices:", {
size: 40,
fill: 0xCCCCCC
});
marketDesc.anchor.set(0.5, 0.5);
marketDesc.y = -180;
container.addChild(marketDesc);
// Show prices for each crop
var cropsPerRow = 3;
var spacing = 200;
var startX = -(spacing * (cropsPerRow - 1)) / 2;
var startY = -100;
var cropTypes = [{
type: SeedType.WHEAT,
name: "Wheat",
color: 0xF5DEB3
}, {
type: SeedType.CORN,
name: "Corn",
color: 0xFFF44F
}, {
type: SeedType.TOMATO,
name: "Tomato",
color: 0xFF6347
}, {
type: SeedType.CARROT,
name: "Carrot",
color: 0xFFA500
}, {
type: SeedType.POTATO,
name: "Potato",
color: 0xA0522D
}, {
type: SeedType.STRAWBERRY,
name: "Strawberry",
color: 0xFF3366
}];
cropTypes.forEach(function (cropInfo, index) {
var row = Math.floor(index / cropsPerRow);
var col = index % cropsPerRow;
var cropDisplay = new Container();
// Crop visual
var cropVisual = LK.getAsset('harvest_ready', {
anchorX: 0.5,
anchorY: 0.5,
tint: cropInfo.color,
scaleX: 0.8,
scaleY: 0.8
});
cropDisplay.addChild(cropVisual);
// Crop name
var nameText = new Text2(cropInfo.name, {
size: 40,
fill: 0xFFFFFF
});
nameText.anchor.set(0.5, 0);
nameText.y = 80;
cropDisplay.addChild(nameText);
// Crop value
var valueText = new Text2(CropConfig[cropInfo.type].value + " coins", {
size: 50,
fill: 0xFFD700
});
valueText.anchor.set(0.5, 0.5);
valueText.y = 30;
cropDisplay.addChild(valueText);
// Position
cropDisplay.x = startX + col * spacing;
cropDisplay.y = startY + row * 200;
container.addChild(cropDisplay);
});
var marketNotice = new Text2("Harvest crops with the Harvest Tool to earn coins!", {
size: 40,
fill: 0xFFFFFF
});
marketNotice.anchor.set(0.5, 0.5);
marketNotice.y = 300;
container.addChild(marketNotice);
}
// Show/hide methods
self.show = function () {
self.visible = true;
// Reset to main town view
if (currentShopContent) {
currentShopContent.destroy();
currentShopContent = null;
}
// Show shop buttons
shops.forEach(function (shop, index) {
shopButtons[index].visible = true;
});
};
self.hide = function () {
self.visible = false;
};
// Initialize as hidden
self.visible = false;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB // Sky blue background
});
/****
* Game Code
****/
// Game variables
var PlotState = {
EMPTY: 0,
TILLED: 1,
SEEDED: 2,
WATERED: 3,
GROWING1: 4,
GROWING2: 5,
GROWING3: 6,
READY: 7
};
// Tool configurations
var ToolConfig = {
// Basic tools (available from start)
basic: {
HOE: {
name: "Hoe",
description: "Tills soil for planting",
icon: 'tool_hoe',
unlocked: true
},
SHOVEL: {
name: "Shovel",
description: "Digs holes in the soil",
icon: 'tool_shovel',
unlocked: true
},
WATER: {
name: "Water Bucket",
description: "Waters your plants",
icon: 'tool_water',
unlocked: true
},
SEEDS: {
name: "Seed Bag",
description: "Plants seeds in tilled soil",
icon: 'tool_seeds',
unlocked: true
},
HARVEST: {
name: "Harvest Tool",
description: "Harvests mature crops",
icon: 'tool_harvest',
unlocked: true
}
},
// Advanced tools (unlocked through purchases)
advanced: {
IRRIGATION: {
name: "Irrigation System",
description: "Waters multiple plots at once",
icon: 'tool_irrigation',
price: 100,
unlocked: false
},
BETTER_HARVEST: {
name: "Better Harvesting Tools",
description: "Harvest crops faster with bonus yields",
icon: 'tool_better_harvest',
price: 150,
unlocked: false
},
AUTO_TILLER: {
name: "Auto-Tilling Tool",
description: "Tills multiple plots at once",
icon: 'tool_auto_tiller',
price: 200,
unlocked: false
}
}
};
var ToolType = {
HOE: 0,
SEEDS: 1,
WATER: 2,
HARVEST: 3,
SHOVEL: 4,
IRRIGATION: 5,
BETTER_HARVEST: 6,
AUTO_TILLER: 7
};
var SeedType = {
WHEAT: "wheat",
CORN: "corn",
TOMATO: "tomato",
CARROT: "carrot",
POTATO: "potato",
STRAWBERRY: "strawberry"
};
// Crop configuration with growth times in ticks (60 ticks = 1 second)
var CropConfig = {
wheat: {
growthTime: 2 * 60 * 60,
// 2 days (2 min in game time)
value: 4
},
corn: {
growthTime: 3 * 60 * 60,
// 3 days (3 min in game time)
value: 7
},
tomato: {
growthTime: 4 * 60 * 60,
// 4 days (4 min in game time)
value: 10
},
carrot: {
growthTime: 3 * 60 * 60,
// 3 days (3 min in game time)
value: 6
},
potato: {
growthTime: 5 * 60 * 60,
// 5 days (5 min in game time)
value: 12
},
strawberry: {
growthTime: 6 * 60 * 60,
// 6 days (6 min in game time)
value: 15
}
};
var farmPlots = [];
var tools = [];
var currentTool = ToolType.HOE;
var gameWidth = 2048;
var gameHeight = 2732;
var gridSize = 10;
var plotSize = 180;
var plotSpacing = 10;
var coins = storage.coins || 0;
var coinDisplay;
var selectedSeedType = SeedType.CARROT; // Default selected seed
var seedSelector; // Global seed selector for accessing from plot click
var tooltip; // Tooltip for showing crop information
var plotCounter; // Display for unlocked plots
// Create game title
var titleText = new Text2("Harvest Haven", {
size: 140,
fill: 0x006400
});
titleText.anchor.set(0.5, 0);
titleText.x = gameWidth / 2;
titleText.y = 30;
game.addChild(titleText);
// Create farm grid
function createFarmGrid() {
var gridWidth = gridSize;
var gridHeight = gridSize;
var startX = (gameWidth - (plotSize * gridWidth + plotSpacing * (gridWidth - 1))) / 2;
var startY = 200;
// Get number of unlocked plots from storage
var unlockedPlots = storage.unlockedPlots || 2;
// Calculate center positions
var centerRow = Math.floor(gridHeight / 2);
var centerCol = Math.floor(gridWidth / 2);
var plotCount = 0;
for (var row = 0; row < gridHeight; row++) {
for (var col = 0; col < gridWidth; col++) {
var plot = new FarmPlot();
plot.x = startX + col * (plotSize + plotSpacing) + plotSize / 2;
plot.y = startY + row * (plotSize + plotSpacing) + plotSize / 2;
// Instead of unlocking first n plots, unlock center plots
var distanceFromCenter = Math.abs(row - centerRow) + Math.abs(col - centerCol);
// Unlock plots closest to the center
if (distanceFromCenter < gridSize && plotCount < unlockedPlots) {
plot.locked = false;
plotCount++;
}
// Update visual to match lock state
plot.updateLockVisual();
farmPlots.push(plot);
game.addChild(plot);
}
}
// Create plot counter display
plotCounter = new PlotCounter();
plotCounter.x = 250;
plotCounter.y = startY + gridHeight * (plotSize + plotSpacing) + 50;
plotCounter.updateCount(unlockedPlots);
game.addChild(plotCounter);
}
// Create tool selection panel
function createToolPanel() {
var toolbarY = gameHeight - 120;
var toolSpacing = 130;
// Load unlocked tools from storage
var unlockedTools = storage.unlockedTools || {};
// Update tool configs with saved unlock status
Object.keys(ToolConfig.advanced).forEach(function (key) {
if (unlockedTools[ToolConfig.advanced[key].name]) {
ToolConfig.advanced[key].unlocked = true;
}
});
// Create basic tools panel
var basicToolCount = Object.keys(ToolConfig.basic).length;
var startX = (gameWidth - toolSpacing * basicToolCount) / 2 + 65;
// Add basic tools
Object.keys(ToolConfig.basic).forEach(function (key, i) {
var toolData = ToolConfig.basic[key];
var tool = new Tool(ToolType[key], false, toolData);
tool.x = startX + i * toolSpacing;
tool.y = toolbarY;
tools.push(tool);
game.addChild(tool);
});
// Add "Advanced Tools" label
var advLabel = new Text2("Advanced Tools", {
size: 50,
fill: 0xFFFFFF
});
advLabel.anchor.set(0.5, 0.5);
advLabel.x = gameWidth / 2;
advLabel.y = toolbarY - 150;
game.addChild(advLabel);
// Create advanced tools panel
var advancedToolCount = Object.keys(ToolConfig.advanced).length;
startX = (gameWidth - toolSpacing * advancedToolCount) / 2 + 65;
var advToolbarY = toolbarY - 220;
// Add advanced tools
Object.keys(ToolConfig.advanced).forEach(function (key, i) {
var toolData = ToolConfig.advanced[key];
var tool = new Tool(ToolType[key], true, toolData);
tool.x = startX + i * toolSpacing;
tool.y = advToolbarY;
tools.push(tool);
game.addChild(tool);
});
// Set initial selected tool
selectTool(currentTool);
// Add panel backgrounds
var basicPanelBackground = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: gameWidth / 200,
scaleY: 2,
tint: 0x4b0082,
alpha: 0.5
});
basicPanelBackground.x = gameWidth / 2;
basicPanelBackground.y = toolbarY;
game.addChildAt(basicPanelBackground, 0);
var advPanelBackground = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: gameWidth / 200,
scaleY: 2,
tint: 0x4b0082,
alpha: 0.5
});
advPanelBackground.x = gameWidth / 2;
advPanelBackground.y = advToolbarY;
game.addChildAt(advPanelBackground, 0);
// Add seed selector button next to seeds tool
var seedButton = tools.find(function (tool) {
return !tool.isAdvanced && tool.toolType === ToolType.SEEDS;
});
var seedSelectButton = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
tint: 0x8b5a2b
});
seedSelectButton.x = seedButton.x + 60;
seedSelectButton.y = toolbarY;
game.addChild(seedSelectButton);
var arrowText = new Text2("▼", {
size: 60,
fill: 0xFFFFFF
});
arrowText.anchor.set(0.5, 0.5);
arrowText.x = seedSelectButton.x;
arrowText.y = toolbarY;
game.addChild(arrowText);
// Create seed selector (using game-wide variable)
seedSelector = new SeedSelector();
seedSelector.x = gameWidth / 2;
seedSelector.y = toolbarY - 200;
seedSelector.visible = false;
game.addChild(seedSelector);
// Seed selector button event
seedSelectButton.interactive = true;
seedSelectButton.down = function (x, y, obj) {
seedSelector.show();
};
// Add town button on the bottom right corner
var townButton = new Container();
var townButtonBg = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5,
tint: 0x4b0082
});
townButton.addChild(townButtonBg);
var townText = new Text2("Town", {
size: 50,
fill: 0xFFFFFF
});
townText.anchor.set(0.5, 0.5);
townButton.addChild(townText);
townButton.x = gameWidth - 120;
townButton.y = gameHeight - 80;
townButton.interactive = true;
game.addChild(townButton);
// Town button event
townButton.down = function (x, y, obj) {
town.show();
};
}
// Create coin display
function createCoinDisplay() {
coinDisplay = new CoinDisplay();
coinDisplay.x = gameWidth - 100;
coinDisplay.y = 80;
coinDisplay.updateCoins(coins);
game.addChild(coinDisplay);
}
// Add coins to player's balance
function addCoins(amount) {
coins += amount;
storage.coins = coins;
// Update display
coinDisplay.updateCoins(coins);
// Show floating coin animation
for (var i = 0; i < amount; i++) {
var coin = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
// Random starting position near cursor
coin.x = 200 + Math.random() * 100;
coin.y = 200 + Math.random() * 100;
game.addChild(coin);
// Animate coin floating up and towards coin display
tween(coin, {
x: coinDisplay.x,
y: coinDisplay.y,
alpha: 0.8,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 800 + Math.random() * 400,
easing: tween.easeOut,
onFinish: function onFinish() {
coin.destroy();
// Flash coin display
LK.effects.flashObject(coinDisplay, 0xFFFF00, 300);
}
});
}
}
// Find plots near a given plot within a specified radius
function findNearbyPlots(centerPlot, radius) {
var nearby = [];
// Calculate approximate grid position of centerPlot
var plotSize = 180;
var plotSpacing = 10;
var totalSize = plotSize + plotSpacing;
// For irrigation system (3x3 area) special handling
if (currentTool === "Irrigation System" && radius === 1) {
// Use a more rectangular/grid-like pattern for irrigation
farmPlots.forEach(function (plot) {
if (plot === centerPlot || plot.locked) {
return;
} // Skip the center plot and locked plots
// Get plots in a 3x3 grid (check if they're within 1 grid cell)
var dx = Math.abs(plot.x - centerPlot.x);
var dy = Math.abs(plot.y - centerPlot.y);
// If within a single grid cell horizontally and vertically
if (dx <= totalSize + 10 && dy <= totalSize + 10) {
nearby.push(plot);
}
});
return nearby;
}
// Regular radius-based search for other tools
farmPlots.forEach(function (plot) {
if (plot === centerPlot || plot.locked) {
return;
} // Skip the center plot and locked plots
// Calculate distance (using squared distance for efficiency)
var dx = plot.x - centerPlot.x;
var dy = plot.y - centerPlot.y;
var distanceSquared = dx * dx + dy * dy;
// Compare with radius (converted to pixels)
var radiusPixels = totalSize * radius + plotSize / 2;
if (distanceSquared <= radiusPixels * radiusPixels) {
nearby.push(plot);
}
});
return nearby;
}
function selectTool(toolType) {
currentTool = toolType;
// Update tool visuals
for (var i = 0; i < tools.length; i++) {
var isSelected = false;
if (typeof toolType === "string") {
// For advanced tools which use string names
isSelected = tools[i].isAdvanced && tools[i].toolData && tools[i].toolData.name === toolType;
} else {
// For basic tools which use ToolType enum
isSelected = !tools[i].isAdvanced && tools[i].toolType === toolType;
}
tools[i].setSelected(isSelected);
}
// Show visual indication of tool's effect area if it's an advanced tool
if (toolType === "Irrigation System") {
// Show irrigation system effect indicator - not implemented in tool info text
var titleText = new Text2("Irrigation System: Waters in a 3x3 area", {
size: 50,
fill: 0x1E90FF
});
titleText.anchor.set(0.5, 0);
titleText.x = gameWidth / 2;
titleText.y = 150;
// Remove after delay
game.addChild(titleText);
LK.setTimeout(function () {
titleText.destroy();
}, 3000);
} else if (toolType === "Auto-Tilling Tool") {
// Show auto-tilling effect indicator
var titleText = new Text2("Auto-Tilling Tool: Tills in a 3x3 area", {
size: 50,
fill: 0xAA00FF
});
titleText.anchor.set(0.5, 0);
titleText.x = gameWidth / 2;
titleText.y = 150;
// Remove after delay
game.addChild(titleText);
LK.setTimeout(function () {
titleText.destroy();
}, 3000);
}
}
// Initialize game
createFarmGrid();
createToolPanel();
createCoinDisplay();
// Create and add town
var town = new Town();
town.x = gameWidth / 2;
town.y = gameHeight / 2;
game.addChild(town);
// Create tooltip for crop information
tooltip = new Tooltip();
game.addChild(tooltip);
// Play background music
LK.playMusic('farm_music', {
fade: {
start: 0,
end: 0.3,
duration: 2000
}
});
// Game update loop
game.update = function () {
// Update all plots
for (var i = 0; i < farmPlots.length; i++) {
// Farm plots have their own update method called by LK engine
}
};
// Game input handling
var lastTouchPosition = {
x: 0,
y: 0
};
game.down = function (x, y, obj) {
lastTouchPosition.x = x;
lastTouchPosition.y = y;
};
game.move = function (x, y, obj) {
lastTouchPosition.x = x;
lastTouchPosition.y = y;
// Update tooltip position if visible
if (tooltip.visible) {
tooltip.x = Math.min(Math.max(x, 250), gameWidth - 250);
tooltip.y = Math.min(Math.max(y - 80, 100), gameHeight - 100);
// Check if mouse/touch is over any crop
var isOverAnyCrop = false;
for (var i = 0; i < farmPlots.length; i++) {
var plot = farmPlots[i];
if (plot.state >= PlotState.SEEDED && Math.abs(x - plot.x) < plotSize / 2 && Math.abs(y - plot.y) < plotSize / 2) {
isOverAnyCrop = true;
// Update tooltip with this plot's information
if (!plot.isHovered) {
// Different plot than before
for (var j = 0; j < farmPlots.length; j++) {
farmPlots[j].isHovered = false;
}
plot.isHovered = true;
tooltip.updateInfo(plot);
}
break;
}
}
// Hide tooltip if not over any crop
if (!isOverAnyCrop) {
tooltip.hide();
for (var i = 0; i < farmPlots.length; i++) {
farmPlots[i].isHovered = false;
}
}
}
};
game.up = function (x, y, obj) {
// We don't need to do anything special here
};
carrot seed. In-Game asset. 2d. High contrast. No shadows
farming hoe. In-Game asset. 2d. High contrast. No shadows
harvesting tool. In-Game asset. 2d. High contrast. No shadows
Irrigation tool. In-Game asset. 2d. High contrast. No shadows
watering can. In-Game asset. 2d. High contrast. No shadows
shovel. In-Game asset. 2d. High contrast. No shadows
Seed bag. In-Game asset. 2d. High contrast. No shadows
Auto harvester. In-Game asset. 2d. High contrast. No shadows
Auto Tiller. In-Game asset. 2d. High contrast. No shadows
water drop. In-Game asset. 2d. High contrast. No shadows
money sign. In-Game asset. 2d. High contrast. No shadows
corn seed. In-Game asset. 2d. High contrast. No shadows
carrot in dirt. In-Game asset. 2d. High contrast. No shadows
Carrot growing in dirt. In-Game asset. 2d. High contrast. No shadows
corn stage 2 growth. In-Game asset. 2d. High contrast. No shadows
Corn growth stage final. In-Game asset. 2d. High contrast. No shadows
Potato seed. In-Game asset. 2d. High contrast. No shadows
Potato growth stage 2. In-Game asset. 2d. High contrast. No shadows
potato growth stage final. In-Game asset. 2d. High contrast. No shadows
Wheat growing stage 2. In-Game asset. 2d. High contrast. No shadows
Wheat growth stage final. In-Game asset. 2d. High contrast. No shadows