From 5fbc84d1b7e3ccdaa65ead374428010d0ca32fa3 Mon Sep 17 00:00:00 2001 From: Sarahtonin Date: Wed, 2 Sep 2026 21:44:57 +0200 Subject: [PATCH] Added permanent upgrades! Currently just adding rows or columns to farm. --- Pages/Shop.php | 20 ++- Scripts/Garden/Save.js | 12 +- Scripts/Garden/Shop.js | 254 +++++++++++++++++++++++++++++++++++++ Scripts/Garden/Upgrades.js | 103 +++++++++++++++ 4 files changed, 384 insertions(+), 5 deletions(-) create mode 100644 Scripts/Garden/Upgrades.js diff --git a/Pages/Shop.php b/Pages/Shop.php index 891878d..a9f5c5e 100644 --- a/Pages/Shop.php +++ b/Pages/Shop.php @@ -40,6 +40,23 @@ $PageSection = "Shop"; seed price, rounded up.

+
+

Permanent upgrades

+ +

+ Expand your Garden one row or column at a time. + Existing plants keep their positions. +

+ +
+
+

- Choose a seed to buy. + Choose something to buy.

@@ -63,6 +80,7 @@ $PageSection = "Shop"; + diff --git a/Scripts/Garden/Save.js b/Scripts/Garden/Save.js index 2be3d65..68da5d7 100644 --- a/Scripts/Garden/Save.js +++ b/Scripts/Garden/Save.js @@ -249,15 +249,19 @@ function NormalizeSaveData( SaveData.Garden.Width = Math.max( 1, - Number( - SaveData.Garden.Width ?? 3 + Math.floor( + Number( + SaveData.Garden.Width ?? 3 + ) || 3 ) ); SaveData.Garden.Height = Math.max( 1, - Number( - SaveData.Garden.Height ?? 3 + Math.floor( + Number( + SaveData.Garden.Height ?? 3 + ) || 3 ) ); diff --git a/Scripts/Garden/Shop.js b/Scripts/Garden/Shop.js index e8d8b76..0e55f11 100644 --- a/Scripts/Garden/Shop.js +++ b/Scripts/Garden/Shop.js @@ -28,6 +28,7 @@ async function StartShop() { function RenderShop() { RenderShopCurrency(); RenderShopSeeds(); + RenderGardenUpgrades(); } @@ -106,6 +107,169 @@ function RenderShopSeeds() { } +function RenderGardenUpgrades() { + const UpgradeList = + document.getElementById( + "ShopGardenUpgradeList" + ); + + if (UpgradeList === null) { + return; + } + + UpgradeList.replaceChildren( + CreateGardenExpansionCard( + "Column" + ), + CreateGardenExpansionCard( + "Row" + ) + ); +} + + +function CreateGardenExpansionCard( + Direction +) { + const IsColumn = + Direction === "Column"; + + const AddedPlots = + IsColumn + ? ShopSave.Garden.Height + : ShopSave.Garden.Width; + + const Cost = + IsColumn + ? GetGardenColumnUpgradeCost( + ShopSave + ) + : GetGardenRowUpgradeCost( + ShopSave + ); + + const NewWidth = + ShopSave.Garden.Width + + (IsColumn ? 1 : 0); + + const NewHeight = + ShopSave.Garden.Height + + (IsColumn ? 0 : 1); + + + const Card = + document.createElement( + "article" + ); + + Card.className = + "Panel ShopItem"; + + + const Header = + document.createElement( + "div" + ); + + Header.className = + "ShopItemHeader"; + + + const Name = + document.createElement( + "h3" + ); + + Name.textContent = + "Add " + + Direction.toLowerCase(); + + Header.appendChild(Name); + + + const Description = + document.createElement( + "p" + ); + + Description.textContent = + IsColumn + ? "Add one column to the right side of your Garden." + : "Add one row to the bottom of your Garden."; + + + const Details = + document.createElement( + "div" + ); + + Details.className = + "ShopItemDetails"; + + Details.append( + CreateShopStat( + "Current size", + ShopSave.Garden.Width + + "×" + + ShopSave.Garden.Height + ), + CreateShopStat( + "Adds", + AddedPlots.toLocaleString() + + (AddedPlots === 1 + ? " plot" + : " plots") + ), + CreateShopStat( + "New size", + NewWidth + + "×" + + NewHeight + ) + ); + + + const BuyButton = + document.createElement( + "button" + ); + + BuyButton.className = + "ActionButton ShopBuyButton"; + + BuyButton.type = "button"; + + BuyButton.textContent = + "Buy - " + + Cost.toLocaleString() + + " Dew"; + + BuyButton.disabled = + ShopSave.Currency.Dew < Cost || + ShopPurchasePending; + + BuyButton.addEventListener( + "click", + () => { + BuyGardenExpansion( + Direction + ); + } + ); + + + Card.append( + Header, + Description, + Details, + BuyButton + ); + + + return Card; +} + + function CreateShopSeedCard( Plant ) { @@ -585,6 +749,96 @@ async function BuyPlantSeed( } +async function BuyGardenExpansion( + Direction +) { + if (ShopPurchasePending) { + return; + } + + + const IsColumn = + Direction === "Column"; + + const IsRow = + Direction === "Row"; + + if ( + !IsColumn && + !IsRow + ) { + return; + } + + + const Cost = + IsColumn + ? GetGardenColumnUpgradeCost( + ShopSave + ) + : GetGardenRowUpgradeCost( + ShopSave + ); + + if ( + ShopSave.Currency.Dew < + Cost + ) { + SetShopMessage( + "You don't have enough Dew to add a " + + Direction.toLowerCase() + + "." + ); + + return; + } + + + ShopPurchasePending = true; + + try { + ShopSave.Currency.Dew -= + Cost; + + ShopSave.Statistics.CurrencySpent.Dew += + Cost; + + + if (IsColumn) { + AddGardenColumn( + ShopSave + ); + } else { + AddGardenRow( + ShopSave + ); + } + + + SetShopMessage( + "Added a Garden " + + Direction.toLowerCase() + + " for " + + Cost.toLocaleString() + + " Dew. Garden size is now " + + ShopSave.Garden.Width + + "×" + + ShopSave.Garden.Height + + "." + ); + + RenderShop(); + + await SaveGame( + ShopSave + ); + } finally { + ShopPurchasePending = false; + RenderShop(); + } +} + + function SetShopMessage( Message ) { diff --git a/Scripts/Garden/Upgrades.js b/Scripts/Garden/Upgrades.js new file mode 100644 index 0000000..3733c4e --- /dev/null +++ b/Scripts/Garden/Upgrades.js @@ -0,0 +1,103 @@ +const GardenExpansionBaseCost = 1000; + + +function GetGardenColumnUpgradeCost( + SaveData +) { + return CalculateGardenExpansionCost( + SaveData.Garden.Height + ); +} + + +function GetGardenRowUpgradeCost( + SaveData +) { + return CalculateGardenExpansionCost( + SaveData.Garden.Width + ); +} + + +function CalculateGardenExpansionCost( + AddedPlots +) { + const PlotCount = Math.max( + 1, + Math.floor( + Number(AddedPlots) || 1 + ) + ); + + return Math.round( + GardenExpansionBaseCost * + PlotCount * + (1 + PlotCount / 10) + ); +} + + +function AddGardenColumn( + SaveData +) { + const Garden = SaveData.Garden; + const OldWidth = Garden.Width; + const Height = Garden.Height; + const NewWidth = OldWidth + 1; + + const NewPlots = Array( + NewWidth * Height + ).fill(null); + + + for ( + let Y = 0; + Y < Height; + Y++ + ) { + for ( + let X = 0; + X < OldWidth; + X++ + ) { + NewPlots[ + Y * NewWidth + X + ] = Garden.Plots[ + Y * OldWidth + X + ] ?? null; + } + } + + + Garden.Width = NewWidth; + Garden.Plots = NewPlots; + + ResetGardenMutationCooldowns( + SaveData + ); +} + + +function AddGardenRow( + SaveData +) { + const Garden = SaveData.Garden; + const Width = Garden.Width; + + Garden.Height++; + + Garden.Plots.push( + ...Array(Width).fill(null) + ); + + ResetGardenMutationCooldowns( + SaveData + ); +} + + +function ResetGardenMutationCooldowns( + SaveData +) { + SaveData.MutationCooldowns = {}; +}