mirror of
https://git.srhtnin.garden/sarah/srhtnin.github.io.git
synced 2026-10-13 18:38:11 +02:00
649 lines
9.8 KiB
JavaScript
649 lines
9.8 KiB
JavaScript
let GameSave;
|
|
let SelectedSeed = "Rose";
|
|
|
|
const GardenUpdateInterval = 1000;
|
|
|
|
|
|
async function StartGame() {
|
|
GameSave = await LoadGame();
|
|
NormalizeSave();
|
|
|
|
RenderGame();
|
|
|
|
setInterval(
|
|
RenderGarden,
|
|
GardenUpdateInterval
|
|
);
|
|
await RenderUser();
|
|
await RenderLeaderboard();
|
|
}
|
|
|
|
|
|
function NormalizeSave() {
|
|
GameSave.Currency ??= {};
|
|
GameSave.Currency.Dew ??= 0;
|
|
|
|
GameSave.Seeds ??= {};
|
|
GameSave.Seeds.Unlocked ??= [
|
|
"Rose"
|
|
];
|
|
|
|
GameSave.Statistics ??= {};
|
|
GameSave.Statistics.CurrencyEarned ??= {};
|
|
|
|
GameSave.Statistics.CurrencyEarned.Dew ??=
|
|
GameSave.Currency.Dew;
|
|
|
|
GameSave.Garden ??= {
|
|
Width: 3,
|
|
Height: 3,
|
|
Plots: []
|
|
};
|
|
|
|
const RequiredPlots =
|
|
GameSave.Garden.Width *
|
|
GameSave.Garden.Height;
|
|
|
|
while (
|
|
GameSave.Garden.Plots.length <
|
|
RequiredPlots
|
|
) {
|
|
GameSave.Garden.Plots.push(null);
|
|
}
|
|
}
|
|
|
|
|
|
function RenderGame() {
|
|
RenderCurrency();
|
|
RenderSeeds();
|
|
RenderGarden();
|
|
}
|
|
|
|
|
|
function RenderCurrency() {
|
|
const DewAmount =
|
|
document.getElementById(
|
|
"DewAmount"
|
|
);
|
|
|
|
DewAmount.textContent =
|
|
GameSave.Currency.Dew;
|
|
}
|
|
|
|
|
|
function RenderSeeds() {
|
|
const SeedList =
|
|
document.getElementById(
|
|
"SeedList"
|
|
);
|
|
|
|
SeedList.replaceChildren();
|
|
|
|
for (
|
|
const PlantId
|
|
of GameSave.Seeds.Unlocked
|
|
) {
|
|
const Plant =
|
|
Plants[PlantId];
|
|
|
|
if (Plant === undefined) {
|
|
continue;
|
|
}
|
|
|
|
const Button =
|
|
document.createElement(
|
|
"button"
|
|
);
|
|
|
|
Button.className =
|
|
"SeedButton";
|
|
|
|
Button.type = "button";
|
|
|
|
Button.textContent =
|
|
Plant.Name;
|
|
|
|
if (
|
|
PlantId ===
|
|
SelectedSeed
|
|
) {
|
|
Button.setAttribute(
|
|
"aria-current",
|
|
"true"
|
|
);
|
|
}
|
|
|
|
Button.addEventListener(
|
|
"click",
|
|
() => {
|
|
SelectedSeed =
|
|
PlantId;
|
|
|
|
RenderSeeds();
|
|
|
|
SetGardenMessage(
|
|
"Selected " +
|
|
Plant.Name +
|
|
"."
|
|
);
|
|
}
|
|
);
|
|
|
|
SeedList.appendChild(
|
|
Button
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
function RenderGarden() {
|
|
const GardenGrid =
|
|
document.getElementById(
|
|
"GardenGrid"
|
|
);
|
|
|
|
GardenGrid.style.setProperty(
|
|
"--GardenWidth",
|
|
GameSave.Garden.Width
|
|
);
|
|
|
|
GardenGrid.replaceChildren();
|
|
|
|
GameSave.Garden.Plots.forEach(
|
|
(Plot, PlotIndex) => {
|
|
const PlotElement =
|
|
CreatePlotElement(
|
|
Plot,
|
|
PlotIndex
|
|
);
|
|
|
|
GardenGrid.appendChild(
|
|
PlotElement
|
|
);
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
function CreatePlotElement(
|
|
Plot,
|
|
PlotIndex
|
|
) {
|
|
const Button =
|
|
document.createElement(
|
|
"button"
|
|
);
|
|
|
|
Button.className =
|
|
"GardenPlot";
|
|
|
|
Button.type = "button";
|
|
|
|
|
|
/*
|
|
* Empty plot.
|
|
*/
|
|
|
|
if (Plot === null) {
|
|
Button.classList.add(
|
|
"GardenPlotEmpty"
|
|
);
|
|
|
|
Button.title =
|
|
"Empty plot";
|
|
|
|
Button.addEventListener(
|
|
"click",
|
|
() => {
|
|
PlantSeed(
|
|
PlotIndex
|
|
);
|
|
}
|
|
);
|
|
|
|
return Button;
|
|
}
|
|
|
|
|
|
const Plant =
|
|
Plants[Plot.Plant];
|
|
|
|
if (Plant === undefined) {
|
|
Button.textContent = "?";
|
|
|
|
return Button;
|
|
}
|
|
|
|
|
|
/*
|
|
* Plant image.
|
|
*/
|
|
|
|
const ImagePath =
|
|
GetPlantImage(
|
|
Plot,
|
|
Plant
|
|
);
|
|
|
|
if (ImagePath !== null) {
|
|
const Image =
|
|
document.createElement(
|
|
"img"
|
|
);
|
|
|
|
Image.className =
|
|
"GardenPlant";
|
|
|
|
Image.alt =
|
|
Plant.Name;
|
|
|
|
Image.src =
|
|
ImagePath;
|
|
|
|
Button.appendChild(
|
|
Image
|
|
);
|
|
}
|
|
|
|
|
|
/*
|
|
* Mature plants can be harvested.
|
|
*/
|
|
|
|
if (
|
|
IsPlantMature(
|
|
Plot,
|
|
Plant
|
|
)
|
|
) {
|
|
Button.classList.add(
|
|
"GardenPlotMature"
|
|
);
|
|
|
|
Button.title =
|
|
"Harvest " +
|
|
Plant.Name;
|
|
|
|
Button.addEventListener(
|
|
"click",
|
|
() => {
|
|
HarvestPlant(
|
|
PlotIndex
|
|
);
|
|
}
|
|
);
|
|
} else {
|
|
const Progress =
|
|
GetPlantGrowthProgress(
|
|
Plot,
|
|
Plant
|
|
);
|
|
|
|
Button.title =
|
|
Plant.Name +
|
|
" - " +
|
|
Math.floor(
|
|
Progress * 100
|
|
) +
|
|
"% grown";
|
|
}
|
|
|
|
return Button;
|
|
}
|
|
|
|
|
|
async function PlantSeed(
|
|
PlotIndex
|
|
) {
|
|
if (
|
|
GameSave.Garden.Plots[
|
|
PlotIndex
|
|
] !== null
|
|
) {
|
|
return;
|
|
}
|
|
|
|
if (
|
|
!GameSave.Seeds.Unlocked
|
|
.includes(
|
|
SelectedSeed
|
|
)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
GameSave.Garden.Plots[
|
|
PlotIndex
|
|
] = {
|
|
Plant: SelectedSeed,
|
|
|
|
AddedTags: [],
|
|
|
|
VisualVariant: null,
|
|
|
|
PlantedAt: Date.now()
|
|
};
|
|
|
|
SetGardenMessage(
|
|
"Planted " +
|
|
Plants[SelectedSeed].Name +
|
|
"."
|
|
);
|
|
|
|
RenderGarden();
|
|
|
|
await SaveGame(
|
|
GameSave
|
|
);
|
|
}
|
|
|
|
|
|
async function HarvestPlant(
|
|
PlotIndex
|
|
) {
|
|
const Plot =
|
|
GameSave.Garden.Plots[
|
|
PlotIndex
|
|
];
|
|
|
|
if (Plot === null) {
|
|
return;
|
|
}
|
|
|
|
const Plant =
|
|
Plants[Plot.Plant];
|
|
|
|
if (
|
|
!IsPlantMature(
|
|
Plot,
|
|
Plant
|
|
)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
GiveReward(
|
|
Plant.Reward
|
|
);
|
|
|
|
GameSave.Garden.Plots[
|
|
PlotIndex
|
|
] = null;
|
|
|
|
SetGardenMessage(
|
|
"Harvested " +
|
|
Plant.Name +
|
|
" for " +
|
|
Plant.Reward.Amount +
|
|
" " +
|
|
Plant.Reward.Currency +
|
|
"."
|
|
);
|
|
|
|
RenderGame();
|
|
|
|
await SaveGame(
|
|
GameSave
|
|
);
|
|
}
|
|
|
|
|
|
function GiveReward(
|
|
Reward
|
|
) {
|
|
GameSave.Currency[
|
|
Reward.Currency
|
|
] ??= 0;
|
|
|
|
GameSave.Currency[
|
|
Reward.Currency
|
|
] += Reward.Amount;
|
|
|
|
|
|
GameSave.Statistics ??= {};
|
|
GameSave.Statistics.CurrencyEarned ??= {};
|
|
|
|
GameSave.Statistics.CurrencyEarned[
|
|
Reward.Currency
|
|
] ??= 0;
|
|
|
|
GameSave.Statistics.CurrencyEarned[
|
|
Reward.Currency
|
|
] += Reward.Amount;
|
|
}
|
|
|
|
|
|
function GetPlantGrowthProgress(
|
|
Plot,
|
|
Plant
|
|
) {
|
|
if (
|
|
Plant.GrowthTime <= 0
|
|
) {
|
|
return 1;
|
|
}
|
|
|
|
const Age =
|
|
Date.now() -
|
|
Plot.PlantedAt;
|
|
|
|
return Math.max(
|
|
0,
|
|
Math.min(
|
|
Age /
|
|
Plant.GrowthTime,
|
|
1
|
|
)
|
|
);
|
|
}
|
|
|
|
function GetPlantTags(
|
|
Plot,
|
|
Plant
|
|
) {
|
|
return [
|
|
...Plant.Tags,
|
|
...(Plot.AddedTags ?? [])
|
|
];
|
|
}
|
|
|
|
|
|
function GetPlantVariant(
|
|
Plot,
|
|
Plant
|
|
) {
|
|
if (
|
|
Plot.VisualVariant !==
|
|
null
|
|
) {
|
|
return Plot.VisualVariant;
|
|
}
|
|
|
|
const Tags =
|
|
GetPlantTags(
|
|
Plot,
|
|
Plant
|
|
);
|
|
|
|
const Variants = [
|
|
...Plant.Variants
|
|
].sort(
|
|
(A, B) =>
|
|
B.Priority -
|
|
A.Priority
|
|
);
|
|
|
|
for (
|
|
const Variant
|
|
of Variants
|
|
) {
|
|
const Matches =
|
|
Variant.Tags.every(
|
|
Tag =>
|
|
Tags.includes(
|
|
Tag
|
|
)
|
|
);
|
|
|
|
if (Matches) {
|
|
return Variant.Name;
|
|
}
|
|
}
|
|
|
|
return "Default";
|
|
}
|
|
|
|
|
|
function IsPlantMature(
|
|
Plot,
|
|
Plant
|
|
) {
|
|
return (
|
|
GetPlantGrowthProgress(
|
|
Plot,
|
|
Plant
|
|
) >= 1
|
|
);
|
|
}
|
|
|
|
|
|
function GetPlantImages(
|
|
Plot,
|
|
Plant
|
|
) {
|
|
const Variants =
|
|
PlantImages[
|
|
Plot.Plant
|
|
];
|
|
|
|
if (Variants === undefined) {
|
|
return [];
|
|
}
|
|
|
|
|
|
const Variant =
|
|
GetPlantVariant(
|
|
Plot,
|
|
Plant
|
|
);
|
|
|
|
|
|
/*
|
|
* Preferred variant.
|
|
*/
|
|
|
|
if (
|
|
Array.isArray(
|
|
Variants[Variant]
|
|
) &&
|
|
Variants[Variant].length > 0
|
|
) {
|
|
return Variants[
|
|
Variant
|
|
];
|
|
}
|
|
|
|
|
|
/*
|
|
* Default visual fallback.
|
|
*/
|
|
|
|
if (
|
|
Array.isArray(
|
|
Variants.Default
|
|
) &&
|
|
Variants.Default.length > 0
|
|
) {
|
|
return Variants.Default;
|
|
}
|
|
|
|
|
|
/*
|
|
* Absolute fallback:
|
|
* use the first variant that has images.
|
|
*/
|
|
|
|
for (
|
|
const Images
|
|
of Object.values(
|
|
Variants
|
|
)
|
|
) {
|
|
if (
|
|
Array.isArray(Images) &&
|
|
Images.length > 0
|
|
) {
|
|
return Images;
|
|
}
|
|
}
|
|
|
|
|
|
return [];
|
|
}
|
|
|
|
|
|
function GetPlantImage(
|
|
Plot,
|
|
Plant
|
|
) {
|
|
const Images =
|
|
GetPlantImages(
|
|
Plot,
|
|
Plant
|
|
);
|
|
|
|
if (Images.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
if (Images.length === 1) {
|
|
return Images[0];
|
|
}
|
|
|
|
|
|
const Progress =
|
|
GetPlantGrowthProgress(
|
|
Plot,
|
|
Plant
|
|
);
|
|
|
|
if (Progress >= 1) {
|
|
return Images[
|
|
Images.length - 1
|
|
];
|
|
}
|
|
|
|
const GrowingImageCount =
|
|
Images.length - 1;
|
|
|
|
const ImageIndex =
|
|
Math.min(
|
|
Math.floor(
|
|
Progress *
|
|
GrowingImageCount
|
|
),
|
|
|
|
GrowingImageCount - 1
|
|
);
|
|
|
|
|
|
return Images[
|
|
ImageIndex
|
|
];
|
|
}
|
|
|
|
|
|
function SetGardenMessage(
|
|
Message
|
|
) {
|
|
document.getElementById(
|
|
"GardenMessage"
|
|
).textContent = Message;
|
|
}
|
|
|
|
|
|
document.addEventListener(
|
|
"DOMContentLoaded",
|
|
StartGame
|
|
);
|