From dde47ff5a65cb2a7a46108cb67109f177669da48 Mon Sep 17 00:00:00 2001 From: Sarahtonin Date: Mon, 31 Aug 2026 19:26:25 +0200 Subject: [PATCH] BIG UPDATE: Plants and mutations moved to database. Fetchable with API. --- Assets/FSEX302.ttf | Bin Scripts/Garden/Economy.js | 102 ++++++++++++------ Scripts/Garden/Garden.js | 16 +++ Scripts/Garden/Mutations.js | 207 +++++++++++++++++------------------- Scripts/Garden/Plants.js | 157 ++++++++++++--------------- Scripts/Garden/Profile.js | 2 + Scripts/Garden/Shop.js | 16 +++ 7 files changed, 272 insertions(+), 228 deletions(-) mode change 100755 => 100644 Assets/FSEX302.ttf diff --git a/Assets/FSEX302.ttf b/Assets/FSEX302.ttf old mode 100755 new mode 100644 diff --git a/Scripts/Garden/Economy.js b/Scripts/Garden/Economy.js index c4083e0..a062b46 100644 --- a/Scripts/Garden/Economy.js +++ b/Scripts/Garden/Economy.js @@ -1,54 +1,90 @@ -const MutationTimeFeePerMinute = 15; +const MutationTimeFeePerMinute = 3; const PlantKeysById = new Map(); const PlantsById = new Map(); const MutationsById = new Map(); +let IndexedPlants = null; +let IndexedMutations = null; -for ( - const [PlantKey, Plant] - of Object.entries(Plants) -) { - if (PlantsById.has(Plant.Id)) { - throw new Error( - "Duplicate plant ID: " + - Plant.Id + +function EnsureEconomyIndexes() { + if ( + IndexedPlants === Plants && + IndexedMutations === + MutationSets + ) { + return; + } + + + PlantKeysById.clear(); + PlantsById.clear(); + MutationsById.clear(); + + + for ( + const [PlantKey, Plant] + of Object.entries(Plants) + ) { + if ( + PlantsById.has( + Plant.Id + ) + ) { + throw new Error( + "Duplicate plant ID: " + + Plant.Id + ); + } + + PlantKeysById.set( + Plant.Id, + PlantKey + ); + + PlantsById.set( + Plant.Id, + Plant ); } - PlantKeysById.set( - Plant.Id, - PlantKey - ); - PlantsById.set( - Plant.Id, - Plant - ); -} + for ( + const Mutation + of Object.values( + MutationSets + ) + ) { + if ( + MutationsById.has( + Mutation.Id + ) + ) { + throw new Error( + "Duplicate mutation ID: " + + Mutation.Id + ); + } - -for ( - const Mutation - of Object.values(MutationSets) -) { - if (MutationsById.has(Mutation.Id)) { - throw new Error( - "Duplicate mutation ID: " + - Mutation.Id + MutationsById.set( + Mutation.Id, + Mutation ); } - MutationsById.set( - Mutation.Id, - Mutation - ); + + IndexedPlants = Plants; + IndexedMutations = + MutationSets; } function GetPlantKeyById( PlantId ) { + EnsureEconomyIndexes(); + return PlantKeysById.get( Number(PlantId) ) ?? null; @@ -58,6 +94,8 @@ function GetPlantKeyById( function GetPlantById( PlantId ) { + EnsureEconomyIndexes(); + return PlantsById.get( Number(PlantId) ) ?? null; @@ -67,6 +105,8 @@ function GetPlantById( function GetMutationById( MutationId ) { + EnsureEconomyIndexes(); + return MutationsById.get( Number(MutationId) ) ?? null; diff --git a/Scripts/Garden/Garden.js b/Scripts/Garden/Garden.js index cfb8f24..3b48827 100644 --- a/Scripts/Garden/Garden.js +++ b/Scripts/Garden/Garden.js @@ -8,6 +8,22 @@ const GardenUpdateInterval = 1000; async function StartGame() { + try { + await LoadGameContent(); + } catch (Error) { + console.error( + "Couldn't load Garden content:", + Error + ); + + SetGardenMessage( + "Couldn't load plant or mutation data." + ); + + return; + } + + GameSave = await LoadGame(); BindGardenTools(); diff --git a/Scripts/Garden/Mutations.js b/Scripts/Garden/Mutations.js index e3279b0..b405b48 100644 --- a/Scripts/Garden/Mutations.js +++ b/Scripts/Garden/Mutations.js @@ -1,114 +1,101 @@ -const MutationSets = { - RoseDarkening: { - Id: 1, - Name: "Rose darkening", +let MutationSets = {}; - Description: - "A mutation that seems to corrupt roses.", +let MutationsLoadPromise = null; +let GameContentLoadPromise = null; - Priority: 10, - Rotation: "Any", - Chance: 0.1, - Cooldown: 120000, - - Relations: { - PlantsUsed: [ - 1 - ], - - PlantsCreated: [ - 2 - ] - }, - - Pattern: [ - [ - { - Tags: ["Rose"], - Capture: "ParentA" - }, - "Empty" - ], - - [ - "Empty", - { - Tags: ["Rose"], - Capture: "ParentB" - } - ] - ], - - Success: [ - [ - "Empty", - "DarkRose" - ], - - [ - "DarkRose", - "Empty" - ] - ], - - Failure: "Keep" - }, - - RoseDyePurple: { - Id: 2, - Name: "Rose dying purple", - - Description: - "A colourful mutation that makes a purple rose.", - - Priority: 20, - Rotation: "Any", - - Chance: 1.0, - Cooldown: 100000, - - Relations: { - PlantsUsed: [ - 1, - 3 - ], - - PlantsCreated: [ - 4 - ] - }, - - Pattern: [ - [ - { - Tags: [ - "Rose", - "Red" - ], - Capture: "ParentA" - }, - - "Empty", - - { - Tags: [ - "Rose", - "Blue" - ], - Capture: "ParentB" - } - ] - ], - - Success: [ - [ - "Empty", - "PurpleRose", - "Empty" - ] - ], - - Failure: "Keep" +async function LoadMutations() { + if (MutationsLoadPromise !== null) { + return MutationsLoadPromise; } -}; + + + MutationsLoadPromise = + LoadMutationsFromApi(); + + + try { + return await MutationsLoadPromise; + } catch (Error) { + MutationsLoadPromise = null; + + throw Error; + } +} + + +async function LoadMutationsFromApi() { + const Response = + await fetch( + ApiUrl + "/Mutations.php", + { + method: "GET", + + headers: { + "Accept": + "application/json" + } + } + ); + + + if (!Response.ok) { + throw new Error( + "Mutations API returned HTTP " + + Response.status + ); + } + + + const Result = + await Response.json(); + + + if ( + !Result.Success || + Result.Mutations === null || + typeof Result.Mutations !== + "object" || + Array.isArray( + Result.Mutations + ) + ) { + throw new Error( + Result.Error ?? + "Mutations API returned invalid data." + ); + } + + + MutationSets = + Result.Mutations; + + + return MutationSets; +} + + +async function LoadGameContent() { + if (GameContentLoadPromise === null) { + GameContentLoadPromise = + Promise.all([ + LoadPlants(), + LoadMutations() + ]); + } + + + try { + await GameContentLoadPromise; + } catch (Error) { + GameContentLoadPromise = null; + + throw Error; + } + + + return { + Plants: Plants, + Mutations: MutationSets + }; +} diff --git a/Scripts/Garden/Plants.js b/Scripts/Garden/Plants.js index d4fc741..57bcc71 100644 --- a/Scripts/Garden/Plants.js +++ b/Scripts/Garden/Plants.js @@ -1,91 +1,74 @@ -const Plants = { - RedRose: { - Id: 1, - Name: "Red Rose", +let Plants = {}; - Description: - "A common red rose.", +let PlantsLoadPromise = null; - Tags: [ - "Rose", - "Flower", - "Red" - ], - GrowthTime: 3600000, - - Effects: [], - - Shop: { - ShopPlant: true, - BaseCost: 10 - } - }, - - DarkRose: { - Id: 2, - Name: "Dark Rose", - - Description: - "A jet-black rose.", - - Tags: [ - "Rose", - "Flower", - "Black" - ], - - GrowthTime: 4000000, - - Effects: [], - - Shop: { - ShopPlant: false - } - }, - - BlueRose: { - Id: 3, - Name: "Blue Rose", - - Description: - "An uncommon blue rose.", - - Tags: [ - "Rose", - "Flower", - "Blue" - ], - - GrowthTime: 3600000, - - Effects: [], - - Shop: { - ShopPlant: true, - BaseCost: 15 - } - }, - - PurpleRose: { - Id: 4, - Name: "Purple Rose", - - Description: - "A rare purple rose.", - - Tags: [ - "Rose", - "Flower", - "Purple" - ], - - GrowthTime: 3600000, - - Effects: [], - - Shop: { - ShopPlant: false - } +async function LoadPlants() { + if (PlantsLoadPromise !== null) { + return PlantsLoadPromise; } -}; + + + PlantsLoadPromise = + LoadPlantsFromApi(); + + + try { + return await PlantsLoadPromise; + } catch (Error) { + PlantsLoadPromise = null; + + throw Error; + } +} + + +async function LoadPlantsFromApi() { + const Response = + await fetch( + ApiUrl + "/Plants.php", + { + method: "GET", + + headers: { + "Accept": + "application/json" + } + } + ); + + + if (!Response.ok) { + throw new Error( + "Plants API returned HTTP " + + Response.status + ); + } + + + const Result = + await Response.json(); + + + if ( + !Result.Success || + Result.Plants === null || + typeof Result.Plants !== + "object" || + Array.isArray( + Result.Plants + ) + ) { + throw new Error( + Result.Error ?? + "Plants API returned invalid data." + ); + } + + + Plants = + Result.Plants; + + + return Plants; +} diff --git a/Scripts/Garden/Profile.js b/Scripts/Garden/Profile.js index f984182..e1884b7 100644 --- a/Scripts/Garden/Profile.js +++ b/Scripts/Garden/Profile.js @@ -5,6 +5,8 @@ async function StartProfile() { await RenderProfilePlayer(); try { + await LoadGameContent(); + ProfileSave = await LoadGame(); diff --git a/Scripts/Garden/Shop.js b/Scripts/Garden/Shop.js index 01fda45..2b6d5ae 100644 --- a/Scripts/Garden/Shop.js +++ b/Scripts/Garden/Shop.js @@ -3,6 +3,22 @@ let ShopPurchasePending = false; async function StartShop() { + try { + await LoadGameContent(); + } catch (Error) { + console.error( + "Couldn't load Shop content:", + Error + ); + + SetShopMessage( + "Couldn't load plant or mutation data." + ); + + return; + } + + ShopSave = await LoadGame(); RenderShop();