mirror of
https://git.srhtnin.garden/sarah/srhtnin.github.io.git
synced 2026-10-14 18:58:11 +02:00
Added multiple gardens per user upgrade. Pretty cool!!!!
This commit is contained in:
1 parent
c7b5494385
commit
d72045d615
7 files changed
+930
-103
No files matched your search
@@ -78,6 +78,38 @@ $PageSection = "Garden";
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
id="GardenSelector"
|
||||||
|
class="GardenSelectorPanel"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
id="PreviousGardenButton"
|
||||||
|
class="ActionButton GardenSelectorButton"
|
||||||
|
type="button"
|
||||||
|
aria-label="Previous Garden"
|
||||||
|
>
|
||||||
|
<
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<input
|
||||||
|
id="GardenNameInput"
|
||||||
|
class="GardenNameInput"
|
||||||
|
type="text"
|
||||||
|
maxlength="32"
|
||||||
|
value="Garden"
|
||||||
|
aria-label="Garden name"
|
||||||
|
>
|
||||||
|
|
||||||
|
<button
|
||||||
|
id="NextGardenButton"
|
||||||
|
class="ActionButton GardenSelectorButton"
|
||||||
|
type="button"
|
||||||
|
aria-label="Next Garden"
|
||||||
|
>
|
||||||
|
>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="GardenLayout">
|
<div class="GardenLayout">
|
||||||
<section id="Plots">
|
<section id="Plots">
|
||||||
<h2>Plots</h2>
|
<h2>Plots</h2>
|
||||||
|
|||||||
+2
-2
@@ -47,8 +47,8 @@ $PageSection = "Shop";
|
|||||||
<h2>Permanent upgrades</h2>
|
<h2>Permanent upgrades</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Permanently expand your Garden or unlock
|
Expand your active Garden, buy additional Gardens,
|
||||||
extra information and quality-of-life features.
|
or unlock information and quality-of-life features.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|||||||
+245
-2
@@ -27,10 +27,11 @@ async function StartGame() {
|
|||||||
GameSave = await LoadGame();
|
GameSave = await LoadGame();
|
||||||
|
|
||||||
BindGardenTools();
|
BindGardenTools();
|
||||||
|
BindGardenSelector();
|
||||||
EnsureSelectedSeed();
|
EnsureSelectedSeed();
|
||||||
|
|
||||||
const InitialMutationResult =
|
const InitialMutationResult =
|
||||||
CheckGardenMutations(
|
CheckAllGardenMutations(
|
||||||
GameSave
|
GameSave
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -57,12 +58,235 @@ function RenderGame() {
|
|||||||
RenderCurrency();
|
RenderCurrency();
|
||||||
RenderSeeds();
|
RenderSeeds();
|
||||||
RenderTools();
|
RenderTools();
|
||||||
|
RenderGardenSelector();
|
||||||
RenderGarden();
|
RenderGarden();
|
||||||
RenderNextHarvest();
|
RenderNextHarvest();
|
||||||
RenderGardenOverview();
|
RenderGardenOverview();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function BindGardenSelector() {
|
||||||
|
const PreviousButton =
|
||||||
|
document.getElementById(
|
||||||
|
"PreviousGardenButton"
|
||||||
|
);
|
||||||
|
|
||||||
|
const NextButton =
|
||||||
|
document.getElementById(
|
||||||
|
"NextGardenButton"
|
||||||
|
);
|
||||||
|
|
||||||
|
const NameInput =
|
||||||
|
document.getElementById(
|
||||||
|
"GardenNameInput"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
PreviousButton?.addEventListener(
|
||||||
|
"click",
|
||||||
|
() => {
|
||||||
|
SwitchGarden(-1);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
NextButton?.addEventListener(
|
||||||
|
"click",
|
||||||
|
() => {
|
||||||
|
SwitchGarden(1);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
NameInput?.addEventListener(
|
||||||
|
"change",
|
||||||
|
async () => {
|
||||||
|
const GardenIndex =
|
||||||
|
GameSave.ActiveGardenIndex;
|
||||||
|
|
||||||
|
const GardenName =
|
||||||
|
RenameGarden(
|
||||||
|
GameSave,
|
||||||
|
GardenIndex,
|
||||||
|
NameInput.value
|
||||||
|
);
|
||||||
|
|
||||||
|
NameInput.value =
|
||||||
|
GardenName;
|
||||||
|
|
||||||
|
SetGardenMessage(
|
||||||
|
"Garden renamed to " +
|
||||||
|
GardenName +
|
||||||
|
"."
|
||||||
|
);
|
||||||
|
|
||||||
|
await SaveGame(
|
||||||
|
GameSave
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
NameInput?.addEventListener(
|
||||||
|
"keydown",
|
||||||
|
Event => {
|
||||||
|
if (Event.key !== "Enter") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Event.preventDefault();
|
||||||
|
NameInput.blur();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function SwitchGarden(
|
||||||
|
Direction
|
||||||
|
) {
|
||||||
|
const GardenCount =
|
||||||
|
GameSave.Gardens.length;
|
||||||
|
|
||||||
|
if (GardenCount <= 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NewIndex =
|
||||||
|
GameSave.ActiveGardenIndex +
|
||||||
|
Direction;
|
||||||
|
|
||||||
|
if (
|
||||||
|
NewIndex < 0 ||
|
||||||
|
NewIndex >= GardenCount
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetActiveGardenIndex(
|
||||||
|
GameSave,
|
||||||
|
NewIndex
|
||||||
|
);
|
||||||
|
|
||||||
|
const MutationResult =
|
||||||
|
CheckGardenMutations(
|
||||||
|
GameSave
|
||||||
|
);
|
||||||
|
|
||||||
|
RenderGame();
|
||||||
|
|
||||||
|
SetGardenMessage(
|
||||||
|
"Switched to " +
|
||||||
|
GameSave.Garden.Name +
|
||||||
|
"."
|
||||||
|
);
|
||||||
|
|
||||||
|
await SaveGame(
|
||||||
|
GameSave
|
||||||
|
);
|
||||||
|
|
||||||
|
if (MutationResult.Attempted) {
|
||||||
|
RenderGame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function RenderGardenSelector() {
|
||||||
|
const PreviousButton =
|
||||||
|
document.getElementById(
|
||||||
|
"PreviousGardenButton"
|
||||||
|
);
|
||||||
|
|
||||||
|
const NextButton =
|
||||||
|
document.getElementById(
|
||||||
|
"NextGardenButton"
|
||||||
|
);
|
||||||
|
|
||||||
|
const NameInput =
|
||||||
|
document.getElementById(
|
||||||
|
"GardenNameInput"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
PreviousButton === null ||
|
||||||
|
NextButton === null ||
|
||||||
|
NameInput === null
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GardenCount =
|
||||||
|
GameSave.Gardens.length;
|
||||||
|
|
||||||
|
const GardenIndex =
|
||||||
|
GameSave.ActiveGardenIndex;
|
||||||
|
|
||||||
|
PreviousButton.disabled =
|
||||||
|
GardenIndex <= 0;
|
||||||
|
|
||||||
|
NextButton.disabled =
|
||||||
|
GardenIndex >=
|
||||||
|
GardenCount - 1;
|
||||||
|
|
||||||
|
if (
|
||||||
|
document.activeElement !==
|
||||||
|
NameInput
|
||||||
|
) {
|
||||||
|
NameInput.value =
|
||||||
|
GameSave.Garden.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
NameInput.title =
|
||||||
|
"Garden " +
|
||||||
|
(GardenIndex + 1) +
|
||||||
|
" of " +
|
||||||
|
GardenCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function CheckAllGardenMutations(
|
||||||
|
SaveData
|
||||||
|
) {
|
||||||
|
const OriginalGardenIndex =
|
||||||
|
SaveData.ActiveGardenIndex;
|
||||||
|
|
||||||
|
const Result = {
|
||||||
|
Attempted: false,
|
||||||
|
Changed: false
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
for (
|
||||||
|
let GardenIndex = 0;
|
||||||
|
GardenIndex <
|
||||||
|
SaveData.Gardens.length;
|
||||||
|
GardenIndex++
|
||||||
|
) {
|
||||||
|
SetActiveGardenIndex(
|
||||||
|
SaveData,
|
||||||
|
GardenIndex
|
||||||
|
);
|
||||||
|
|
||||||
|
const GardenResult =
|
||||||
|
CheckGardenMutations(
|
||||||
|
SaveData
|
||||||
|
);
|
||||||
|
|
||||||
|
Result.Attempted =
|
||||||
|
Result.Attempted ||
|
||||||
|
GardenResult.Attempted;
|
||||||
|
|
||||||
|
Result.Changed =
|
||||||
|
Result.Changed ||
|
||||||
|
GardenResult.Changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SetActiveGardenIndex(
|
||||||
|
SaveData,
|
||||||
|
OriginalGardenIndex
|
||||||
|
);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function BindGardenTools() {
|
function BindGardenTools() {
|
||||||
const ShovelButton =
|
const ShovelButton =
|
||||||
document.getElementById(
|
document.getElementById(
|
||||||
@@ -326,6 +550,25 @@ function RenderGarden() {
|
|||||||
GameSave.Garden.Width
|
GameSave.Garden.Width
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const GardenBorderColours = [
|
||||||
|
"var(--Lavender)",
|
||||||
|
"var(--Mauve)",
|
||||||
|
"var(--Pink)",
|
||||||
|
"var(--Blue)",
|
||||||
|
"var(--Teal)",
|
||||||
|
"var(--Peach)",
|
||||||
|
"var(--Yellow)",
|
||||||
|
"var(--Green)"
|
||||||
|
];
|
||||||
|
|
||||||
|
GardenGrid.style.setProperty(
|
||||||
|
"--GardenBorderColour",
|
||||||
|
GardenBorderColours[
|
||||||
|
GameSave.ActiveGardenIndex %
|
||||||
|
GardenBorderColours.length
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
GardenGrid.replaceChildren();
|
GardenGrid.replaceChildren();
|
||||||
|
|
||||||
|
|
||||||
@@ -954,7 +1197,7 @@ async function GardenTick() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const MutationResult =
|
const MutationResult =
|
||||||
CheckGardenMutations(
|
CheckAllGardenMutations(
|
||||||
GameSave
|
GameSave
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
+395
-98
@@ -10,6 +10,357 @@ const StartingSeeds = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const DefaultGardenName = "Garden";
|
||||||
|
const MaximumGardenNameLength = 32;
|
||||||
|
const StartingGardenWidth = 3;
|
||||||
|
const StartingGardenHeight = 3;
|
||||||
|
|
||||||
|
|
||||||
|
function CreateGardenData(
|
||||||
|
Name = DefaultGardenName
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
Name: NormalizeGardenName(
|
||||||
|
Name
|
||||||
|
),
|
||||||
|
Width: StartingGardenWidth,
|
||||||
|
Height: StartingGardenHeight,
|
||||||
|
Plots: Array(
|
||||||
|
StartingGardenWidth *
|
||||||
|
StartingGardenHeight
|
||||||
|
).fill(null),
|
||||||
|
MutationCooldowns: {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function NormalizeGardenName(
|
||||||
|
Value
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
typeof Value !== "string"
|
||||||
|
) {
|
||||||
|
return DefaultGardenName;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Name = Value
|
||||||
|
.trim()
|
||||||
|
.slice(
|
||||||
|
0,
|
||||||
|
MaximumGardenNameLength
|
||||||
|
);
|
||||||
|
|
||||||
|
return Name.length > 0
|
||||||
|
? Name
|
||||||
|
: DefaultGardenName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function NormalizeGardenData(
|
||||||
|
Garden,
|
||||||
|
LegacyMutationCooldowns = null
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
Garden === null ||
|
||||||
|
typeof Garden !== "object" ||
|
||||||
|
Array.isArray(Garden)
|
||||||
|
) {
|
||||||
|
Garden = CreateGardenData();
|
||||||
|
}
|
||||||
|
|
||||||
|
Garden.Name = NormalizeGardenName(
|
||||||
|
Garden.Name
|
||||||
|
);
|
||||||
|
|
||||||
|
Garden.Width = Math.max(
|
||||||
|
1,
|
||||||
|
Math.floor(
|
||||||
|
Number(
|
||||||
|
Garden.Width ??
|
||||||
|
StartingGardenWidth
|
||||||
|
) || StartingGardenWidth
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
Garden.Height = Math.max(
|
||||||
|
1,
|
||||||
|
Math.floor(
|
||||||
|
Number(
|
||||||
|
Garden.Height ??
|
||||||
|
StartingGardenHeight
|
||||||
|
) || StartingGardenHeight
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!Array.isArray(Garden.Plots)) {
|
||||||
|
Garden.Plots = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (
|
||||||
|
let PlotIndex = 0;
|
||||||
|
PlotIndex < Garden.Plots.length;
|
||||||
|
PlotIndex++
|
||||||
|
) {
|
||||||
|
const Plot =
|
||||||
|
Garden.Plots[PlotIndex];
|
||||||
|
|
||||||
|
if (Plot === null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof Plot !== "object" ||
|
||||||
|
Array.isArray(Plot)
|
||||||
|
) {
|
||||||
|
Garden.Plots[PlotIndex] = null;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
Plot.Plant === "Rose"
|
||||||
|
) {
|
||||||
|
Plot.Plant = "RedRose";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof Plot.Plant ===
|
||||||
|
"number"
|
||||||
|
) {
|
||||||
|
const PlantKey =
|
||||||
|
ResolvePlantKeyById(
|
||||||
|
Plot.Plant
|
||||||
|
);
|
||||||
|
|
||||||
|
if (PlantKey !== null) {
|
||||||
|
Plot.Plant = PlantKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Plot.PlantedAt = Number(
|
||||||
|
Plot.PlantedAt ??
|
||||||
|
Date.now()
|
||||||
|
);
|
||||||
|
|
||||||
|
delete Plot.VisualVariant;
|
||||||
|
delete Plot.AddedTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const RequiredPlots =
|
||||||
|
Garden.Width *
|
||||||
|
Garden.Height;
|
||||||
|
|
||||||
|
while (
|
||||||
|
Garden.Plots.length <
|
||||||
|
RequiredPlots
|
||||||
|
) {
|
||||||
|
Garden.Plots.push(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
Garden.Plots.length >
|
||||||
|
RequiredPlots
|
||||||
|
) {
|
||||||
|
Garden.Plots.length =
|
||||||
|
RequiredPlots;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
Garden.MutationCooldowns ===
|
||||||
|
undefined &&
|
||||||
|
LegacyMutationCooldowns !== null &&
|
||||||
|
typeof LegacyMutationCooldowns ===
|
||||||
|
"object" &&
|
||||||
|
!Array.isArray(
|
||||||
|
LegacyMutationCooldowns
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Garden.MutationCooldowns =
|
||||||
|
LegacyMutationCooldowns;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
Garden.MutationCooldowns === null ||
|
||||||
|
typeof Garden.MutationCooldowns !==
|
||||||
|
"object" ||
|
||||||
|
Array.isArray(
|
||||||
|
Garden.MutationCooldowns
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Garden.MutationCooldowns = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return Garden;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function GetActiveGarden(
|
||||||
|
SaveData
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
!Array.isArray(
|
||||||
|
SaveData.Gardens
|
||||||
|
) ||
|
||||||
|
SaveData.Gardens.length === 0
|
||||||
|
) {
|
||||||
|
SaveData.Gardens = [
|
||||||
|
CreateGardenData()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
const GardenIndex = Math.min(
|
||||||
|
SaveData.Gardens.length - 1,
|
||||||
|
Math.max(
|
||||||
|
0,
|
||||||
|
Math.floor(
|
||||||
|
Number(
|
||||||
|
SaveData.ActiveGardenIndex ??
|
||||||
|
0
|
||||||
|
) || 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
SaveData.ActiveGardenIndex =
|
||||||
|
GardenIndex;
|
||||||
|
|
||||||
|
return SaveData.Gardens[
|
||||||
|
GardenIndex
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function SetActiveGardenIndex(
|
||||||
|
SaveData,
|
||||||
|
GardenIndex
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
!Array.isArray(
|
||||||
|
SaveData.Gardens
|
||||||
|
) ||
|
||||||
|
SaveData.Gardens.length === 0
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NormalizedIndex = Math.min(
|
||||||
|
SaveData.Gardens.length - 1,
|
||||||
|
Math.max(
|
||||||
|
0,
|
||||||
|
Math.floor(
|
||||||
|
Number(
|
||||||
|
GardenIndex
|
||||||
|
) || 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const Changed =
|
||||||
|
SaveData.ActiveGardenIndex !==
|
||||||
|
NormalizedIndex;
|
||||||
|
|
||||||
|
SaveData.ActiveGardenIndex =
|
||||||
|
NormalizedIndex;
|
||||||
|
|
||||||
|
return Changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function RenameGarden(
|
||||||
|
SaveData,
|
||||||
|
GardenIndex,
|
||||||
|
Name
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
!Array.isArray(
|
||||||
|
SaveData.Gardens
|
||||||
|
) ||
|
||||||
|
SaveData.Gardens[GardenIndex] ===
|
||||||
|
undefined
|
||||||
|
) {
|
||||||
|
return DefaultGardenName;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NormalizedName =
|
||||||
|
NormalizeGardenName(
|
||||||
|
Name
|
||||||
|
);
|
||||||
|
|
||||||
|
SaveData.Gardens[
|
||||||
|
GardenIndex
|
||||||
|
].Name = NormalizedName;
|
||||||
|
|
||||||
|
return NormalizedName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function DefineActiveGardenAliases(
|
||||||
|
SaveData
|
||||||
|
) {
|
||||||
|
delete SaveData.Garden;
|
||||||
|
delete SaveData.MutationCooldowns;
|
||||||
|
|
||||||
|
Object.defineProperty(
|
||||||
|
SaveData,
|
||||||
|
"Garden",
|
||||||
|
{
|
||||||
|
configurable: true,
|
||||||
|
enumerable: false,
|
||||||
|
|
||||||
|
get() {
|
||||||
|
return GetActiveGarden(
|
||||||
|
SaveData
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
set(Value) {
|
||||||
|
const GardenIndex =
|
||||||
|
SaveData.ActiveGardenIndex ??
|
||||||
|
0;
|
||||||
|
|
||||||
|
SaveData.Gardens[
|
||||||
|
GardenIndex
|
||||||
|
] = NormalizeGardenData(
|
||||||
|
Value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Object.defineProperty(
|
||||||
|
SaveData,
|
||||||
|
"MutationCooldowns",
|
||||||
|
{
|
||||||
|
configurable: true,
|
||||||
|
enumerable: false,
|
||||||
|
|
||||||
|
get() {
|
||||||
|
return GetActiveGarden(
|
||||||
|
SaveData
|
||||||
|
).MutationCooldowns;
|
||||||
|
},
|
||||||
|
|
||||||
|
set(Value) {
|
||||||
|
const Garden =
|
||||||
|
GetActiveGarden(
|
||||||
|
SaveData
|
||||||
|
);
|
||||||
|
|
||||||
|
Garden.MutationCooldowns =
|
||||||
|
Value !== null &&
|
||||||
|
typeof Value === "object" &&
|
||||||
|
!Array.isArray(Value)
|
||||||
|
? Value
|
||||||
|
: {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function CreateNewSave() {
|
function CreateNewSave() {
|
||||||
const SeedInventory = {};
|
const SeedInventory = {};
|
||||||
const StartingPlants = [];
|
const StartingPlants = [];
|
||||||
@@ -40,8 +391,8 @@ function CreateNewSave() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return {
|
return NormalizeSaveData({
|
||||||
Version: 2,
|
Version: 3,
|
||||||
Revision: 0,
|
Revision: 0,
|
||||||
LastSavedAt: Date.now(),
|
LastSavedAt: Date.now(),
|
||||||
|
|
||||||
@@ -83,19 +434,17 @@ function CreateNewSave() {
|
|||||||
ShowReadyPlots: true
|
ShowReadyPlots: true
|
||||||
},
|
},
|
||||||
|
|
||||||
Garden: {
|
Gardens: [
|
||||||
Width: 3,
|
CreateGardenData()
|
||||||
Height: 3,
|
],
|
||||||
Plots: Array(9).fill(null)
|
|
||||||
},
|
ActiveGardenIndex: 0,
|
||||||
|
|
||||||
Discoveries: {
|
Discoveries: {
|
||||||
Plants: StartingPlants,
|
Plants: StartingPlants,
|
||||||
Mutations: []
|
Mutations: []
|
||||||
},
|
}
|
||||||
|
});
|
||||||
MutationCooldowns: {}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -106,7 +455,7 @@ function NormalizeSaveData(
|
|||||||
Number(
|
Number(
|
||||||
SaveData.Version ?? 1
|
SaveData.Version ?? 1
|
||||||
),
|
),
|
||||||
2
|
3
|
||||||
);
|
);
|
||||||
|
|
||||||
SaveData.Revision = Number(
|
SaveData.Revision = Number(
|
||||||
@@ -301,100 +650,48 @@ function NormalizeSaveData(
|
|||||||
false;
|
false;
|
||||||
|
|
||||||
|
|
||||||
SaveData.Garden ??= {
|
const LegacyGarden =
|
||||||
Width: 3,
|
SaveData.Garden ??
|
||||||
Height: 3,
|
null;
|
||||||
Plots: []
|
|
||||||
};
|
|
||||||
|
|
||||||
SaveData.Garden.Width = Math.max(
|
const LegacyMutationCooldowns =
|
||||||
1,
|
SaveData.MutationCooldowns ??
|
||||||
Math.floor(
|
null;
|
||||||
Number(
|
|
||||||
SaveData.Garden.Width ?? 3
|
|
||||||
) || 3
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
SaveData.Garden.Height = Math.max(
|
|
||||||
1,
|
|
||||||
Math.floor(
|
|
||||||
Number(
|
|
||||||
SaveData.Garden.Height ?? 3
|
|
||||||
) || 3
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
SaveData.Garden.Plots ??= [];
|
|
||||||
|
|
||||||
|
|
||||||
for (
|
|
||||||
let PlotIndex = 0;
|
|
||||||
PlotIndex <
|
|
||||||
SaveData.Garden.Plots.length;
|
|
||||||
PlotIndex++
|
|
||||||
) {
|
|
||||||
const Plot =
|
|
||||||
SaveData.Garden.Plots[
|
|
||||||
PlotIndex
|
|
||||||
];
|
|
||||||
|
|
||||||
if (Plot === null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
Plot.Plant === "Rose"
|
|
||||||
) {
|
|
||||||
Plot.Plant =
|
|
||||||
"RedRose";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
typeof Plot.Plant ===
|
|
||||||
"number"
|
|
||||||
) {
|
|
||||||
const PlantKey =
|
|
||||||
ResolvePlantKeyById(
|
|
||||||
Plot.Plant
|
|
||||||
);
|
|
||||||
|
|
||||||
if (PlantKey !== null) {
|
|
||||||
Plot.Plant = PlantKey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Plot.PlantedAt = Number(
|
|
||||||
Plot.PlantedAt ??
|
|
||||||
Date.now()
|
|
||||||
);
|
|
||||||
|
|
||||||
delete Plot.VisualVariant;
|
|
||||||
delete Plot.AddedTags;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const RequiredPlots =
|
|
||||||
SaveData.Garden.Width *
|
|
||||||
SaveData.Garden.Height;
|
|
||||||
|
|
||||||
while (
|
|
||||||
SaveData.Garden.Plots.length <
|
|
||||||
RequiredPlots
|
|
||||||
) {
|
|
||||||
SaveData.Garden.Plots.push(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
SaveData.Garden.Plots.length >
|
!Array.isArray(
|
||||||
RequiredPlots
|
SaveData.Gardens
|
||||||
|
) ||
|
||||||
|
SaveData.Gardens.length === 0
|
||||||
) {
|
) {
|
||||||
SaveData.Garden.Plots.length =
|
SaveData.Gardens = [
|
||||||
RequiredPlots;
|
LegacyGarden ??
|
||||||
|
CreateGardenData()
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SaveData.MutationCooldowns ??= {};
|
SaveData.Gardens =
|
||||||
|
SaveData.Gardens.map(
|
||||||
|
(Garden, GardenIndex) =>
|
||||||
|
NormalizeGardenData(
|
||||||
|
Garden,
|
||||||
|
GardenIndex === 0
|
||||||
|
? LegacyMutationCooldowns
|
||||||
|
: null
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
SetActiveGardenIndex(
|
||||||
|
SaveData,
|
||||||
|
SaveData.ActiveGardenIndex ?? 0
|
||||||
|
);
|
||||||
|
|
||||||
|
DefineActiveGardenAliases(
|
||||||
|
SaveData
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
return SaveData;
|
return SaveData;
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ function RenderGardenUpgrades() {
|
|||||||
CreateGardenExpansionCard(
|
CreateGardenExpansionCard(
|
||||||
"Row"
|
"Row"
|
||||||
),
|
),
|
||||||
|
CreateNewGardenCard(),
|
||||||
CreatePlantInformationUpgradeCard(),
|
CreatePlantInformationUpgradeCard(),
|
||||||
CreateGardenOverviewUpgradeCard(),
|
CreateGardenOverviewUpgradeCard(),
|
||||||
CreateMutationHintsUpgradeCard()
|
CreateMutationHintsUpgradeCard()
|
||||||
@@ -210,6 +211,10 @@ function CreateGardenExpansionCard(
|
|||||||
"ShopItemDetails";
|
"ShopItemDetails";
|
||||||
|
|
||||||
Details.append(
|
Details.append(
|
||||||
|
CreateShopStat(
|
||||||
|
"Garden",
|
||||||
|
ShopSave.Garden.Name
|
||||||
|
),
|
||||||
CreateShopStat(
|
CreateShopStat(
|
||||||
"Current size",
|
"Current size",
|
||||||
ShopSave.Garden.Width +
|
ShopSave.Garden.Width +
|
||||||
@@ -273,6 +278,115 @@ function CreateGardenExpansionCard(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function CreateNewGardenCard() {
|
||||||
|
const Cost =
|
||||||
|
GetNewGardenCost(
|
||||||
|
ShopSave
|
||||||
|
);
|
||||||
|
|
||||||
|
const GardensOwned =
|
||||||
|
ShopSave.Gardens.length;
|
||||||
|
|
||||||
|
|
||||||
|
const Card =
|
||||||
|
document.createElement(
|
||||||
|
"article"
|
||||||
|
);
|
||||||
|
|
||||||
|
Card.className =
|
||||||
|
"Panel ShopItem";
|
||||||
|
|
||||||
|
|
||||||
|
const Header =
|
||||||
|
document.createElement(
|
||||||
|
"div"
|
||||||
|
);
|
||||||
|
|
||||||
|
Header.className =
|
||||||
|
"ShopItemHeader";
|
||||||
|
|
||||||
|
|
||||||
|
const Name =
|
||||||
|
document.createElement(
|
||||||
|
"h3"
|
||||||
|
);
|
||||||
|
|
||||||
|
Name.textContent =
|
||||||
|
"Buy new Garden";
|
||||||
|
|
||||||
|
Header.appendChild(Name);
|
||||||
|
|
||||||
|
|
||||||
|
const Description =
|
||||||
|
document.createElement(
|
||||||
|
"p"
|
||||||
|
);
|
||||||
|
|
||||||
|
Description.textContent =
|
||||||
|
"Buy another independent 3×3 Garden. New Gardens can be named and expanded separately.";
|
||||||
|
|
||||||
|
|
||||||
|
const Details =
|
||||||
|
document.createElement(
|
||||||
|
"div"
|
||||||
|
);
|
||||||
|
|
||||||
|
Details.className =
|
||||||
|
"ShopItemDetails";
|
||||||
|
|
||||||
|
Details.append(
|
||||||
|
CreateShopStat(
|
||||||
|
"Gardens owned",
|
||||||
|
GardensOwned.toLocaleString()
|
||||||
|
),
|
||||||
|
CreateShopStat(
|
||||||
|
"New Garden size",
|
||||||
|
"3×3 (9 plots)"
|
||||||
|
),
|
||||||
|
CreateShopStat(
|
||||||
|
"Price scaling",
|
||||||
|
"+50% per Garden"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
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",
|
||||||
|
BuyNewGarden
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
Card.append(
|
||||||
|
Header,
|
||||||
|
Description,
|
||||||
|
Details,
|
||||||
|
BuyButton
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
return Card;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function CreatePlantInformationUpgradeCard() {
|
function CreatePlantInformationUpgradeCard() {
|
||||||
const Cost =
|
const Cost =
|
||||||
GetPlantInformationUpgradeCost();
|
GetPlantInformationUpgradeCost();
|
||||||
@@ -1188,6 +1302,60 @@ async function BuyGardenExpansion(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function BuyNewGarden() {
|
||||||
|
if (ShopPurchasePending) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Cost =
|
||||||
|
GetNewGardenCost(
|
||||||
|
ShopSave
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
ShopSave.Currency.Dew <
|
||||||
|
Cost
|
||||||
|
) {
|
||||||
|
SetShopMessage(
|
||||||
|
"You don't have enough Dew for a new Garden."
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ShopPurchasePending = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
ShopSave.Currency.Dew -=
|
||||||
|
Cost;
|
||||||
|
|
||||||
|
ShopSave.Statistics.CurrencySpent.Dew +=
|
||||||
|
Cost;
|
||||||
|
|
||||||
|
AddNewGarden(
|
||||||
|
ShopSave
|
||||||
|
);
|
||||||
|
|
||||||
|
SetShopMessage(
|
||||||
|
"Bought a new 3×3 Garden for " +
|
||||||
|
Cost.toLocaleString() +
|
||||||
|
" Dew. It is now your active Garden."
|
||||||
|
);
|
||||||
|
|
||||||
|
RenderShop();
|
||||||
|
|
||||||
|
await SaveGame(
|
||||||
|
ShopSave
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
ShopPurchasePending = false;
|
||||||
|
RenderShop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async function BuyPlantInformationUpgrade() {
|
async function BuyPlantInformationUpgrade() {
|
||||||
if (
|
if (
|
||||||
ShopPurchasePending ||
|
ShopPurchasePending ||
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ const GardenExpansionBaseCost = 1000;
|
|||||||
const PlantInformationUpgradeCost = 500;
|
const PlantInformationUpgradeCost = 500;
|
||||||
const GardenOverviewUpgradeCost = 1000;
|
const GardenOverviewUpgradeCost = 1000;
|
||||||
const MutationHintsUpgradeCost = 1500;
|
const MutationHintsUpgradeCost = 1500;
|
||||||
|
const NewGardenBaseCost = 30000;
|
||||||
|
const NewGardenCostMultiplier = 1.5;
|
||||||
|
const NewGardenCostRounding = 1000;
|
||||||
|
|
||||||
|
|
||||||
function GetGardenColumnUpgradeCost(
|
function GetGardenColumnUpgradeCost(
|
||||||
@@ -112,6 +115,51 @@ function ResetGardenMutationCooldowns(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function GetNewGardenCost(
|
||||||
|
SaveData
|
||||||
|
) {
|
||||||
|
const GardensOwned = Math.max(
|
||||||
|
1,
|
||||||
|
SaveData.Gardens?.length ?? 1
|
||||||
|
);
|
||||||
|
|
||||||
|
let Cost =
|
||||||
|
NewGardenBaseCost;
|
||||||
|
|
||||||
|
for (
|
||||||
|
let GardenNumber = 1;
|
||||||
|
GardenNumber < GardensOwned;
|
||||||
|
GardenNumber++
|
||||||
|
) {
|
||||||
|
Cost = Math.round(
|
||||||
|
Cost *
|
||||||
|
NewGardenCostMultiplier /
|
||||||
|
NewGardenCostRounding
|
||||||
|
) * NewGardenCostRounding;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function AddNewGarden(
|
||||||
|
SaveData
|
||||||
|
) {
|
||||||
|
SaveData.Gardens ??= [];
|
||||||
|
|
||||||
|
SaveData.Gardens.push(
|
||||||
|
CreateGardenData()
|
||||||
|
);
|
||||||
|
|
||||||
|
SetActiveGardenIndex(
|
||||||
|
SaveData,
|
||||||
|
SaveData.Gardens.length - 1
|
||||||
|
);
|
||||||
|
|
||||||
|
return SaveData.Garden;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function HasPlantInformationUpgrade(
|
function HasPlantInformationUpgrade(
|
||||||
SaveData
|
SaveData
|
||||||
) {
|
) {
|
||||||
|
|||||||
+40
-1
@@ -313,6 +313,45 @@ input, button, textarea, select {
|
|||||||
image-rendering: auto;
|
image-rendering: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.GardenSelectorPanel {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 3rem minmax(0, 1fr) 3rem;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
padding: 0.5rem;
|
||||||
|
background-color: var(--Mantle);
|
||||||
|
border: 3px solid var(--Surface2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.GardenSelectorButton {
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.GardenNameInput {
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
padding: 0.6rem 0.75rem;
|
||||||
|
color: var(--Text);
|
||||||
|
background-color: var(--Surface0);
|
||||||
|
border: 3px solid var(--Surface2);
|
||||||
|
border-radius: 0;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 3px 3px 0 var(--Crust);
|
||||||
|
}
|
||||||
|
|
||||||
|
.GardenNameInput:hover {
|
||||||
|
border-color: var(--Sky);
|
||||||
|
}
|
||||||
|
|
||||||
|
.GardenNameInput:focus {
|
||||||
|
outline: 3px solid var(--Yellow);
|
||||||
|
outline-offset: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
.GardenLayout {
|
.GardenLayout {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(0, 1fr) 12rem;
|
grid-template-columns: minmax(0, 1fr) 12rem;
|
||||||
@@ -327,7 +366,7 @@ input, button, textarea, select {
|
|||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
background-color: var(--Mantle);
|
background-color: var(--Mantle);
|
||||||
border: 4px solid var(--Lavender);
|
border: 4px solid var(--GardenBorderColour, var(--Lavender));
|
||||||
}
|
}
|
||||||
|
|
||||||
.GardenPlot {
|
.GardenPlot {
|
||||||
|
|||||||
Reference in new issue
Block a user