mirror of
https://git.srhtnin.garden/sarah/srhtnin.github.io.git
synced 2026-10-13 18:38:11 +02:00
573 lines
10 KiB
JavaScript
573 lines
10 KiB
JavaScript
const GardenBorderColours = [
|
|
"var(--Rosewater)",
|
|
"var(--Flamingo)",
|
|
"var(--Pink)",
|
|
"var(--Mauve)",
|
|
"var(--Red)",
|
|
"var(--Maroon)",
|
|
"var(--Peach)",
|
|
"var(--Yellow)",
|
|
"var(--Green)",
|
|
"var(--Teal)",
|
|
"var(--Sky)",
|
|
"var(--Sapphire)",
|
|
"var(--Blue)",
|
|
"var(--Lavender)"
|
|
];
|
|
|
|
const GardenPlotDefaultRotation = "East";
|
|
const GardenPlotRotations = [
|
|
"North",
|
|
"East",
|
|
"South",
|
|
"West"
|
|
];
|
|
const GardenPlotRotationLabels = {
|
|
North: "^",
|
|
East: "->",
|
|
South: "v",
|
|
West: "<-"
|
|
};
|
|
|
|
|
|
function GetGardenBorderColour(
|
|
GardenIndex
|
|
) {
|
|
const ColourCount =
|
|
GardenBorderColours.length;
|
|
|
|
const NormalizedIndex =
|
|
(
|
|
Number(GardenIndex) %
|
|
ColourCount +
|
|
ColourCount
|
|
) % ColourCount;
|
|
|
|
return GardenBorderColours[
|
|
NormalizedIndex
|
|
];
|
|
}
|
|
|
|
|
|
function GetGardenPlotRotation(
|
|
Plot
|
|
) {
|
|
return GardenPlotRotations.includes(
|
|
Plot?.Rotation
|
|
)
|
|
? Plot.Rotation
|
|
: GardenPlotDefaultRotation;
|
|
}
|
|
|
|
|
|
function GetGardenPlotRotationLabel(
|
|
Plot
|
|
) {
|
|
return GardenPlotRotationLabels[
|
|
GetGardenPlotRotation(
|
|
Plot
|
|
)
|
|
] ?? "->";
|
|
}
|
|
|
|
|
|
function GetGardenPlotGrowthProgress(
|
|
Plot,
|
|
Plant,
|
|
AtTime = Date.now()
|
|
) {
|
|
const GrowthTime =
|
|
Number(Plant?.GrowthTime ?? 0);
|
|
|
|
if (GrowthTime <= 0) {
|
|
return 1;
|
|
}
|
|
|
|
const PlantedAt =
|
|
Number(Plot?.PlantedAt ?? 0);
|
|
|
|
return Math.max(
|
|
0,
|
|
Math.min(
|
|
(
|
|
Number(AtTime) -
|
|
PlantedAt
|
|
) /
|
|
GrowthTime,
|
|
1
|
|
)
|
|
);
|
|
}
|
|
|
|
|
|
function GetGardenPlotImageSources(
|
|
Plot,
|
|
Plant
|
|
) {
|
|
const Direction =
|
|
Plot !== null &&
|
|
Plant?.DirectionalSprites === true
|
|
? GetGardenPlotRotation(
|
|
Plot
|
|
)
|
|
: null;
|
|
|
|
return GetPlantImageSources(
|
|
Plant ?? Plot?.Plant,
|
|
Direction
|
|
);
|
|
}
|
|
|
|
|
|
function GetGardenPlotImage(
|
|
Plot,
|
|
Plant,
|
|
Progress
|
|
) {
|
|
const Images =
|
|
GetGardenPlotImageSources(
|
|
Plot,
|
|
Plant
|
|
);
|
|
|
|
if (Images.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
if (Images.length === 1) {
|
|
return Images[0] ?? null;
|
|
}
|
|
|
|
if (Progress >= 1) {
|
|
return Images[
|
|
Images.length - 1
|
|
] ?? null;
|
|
}
|
|
|
|
const GrowingImageCount =
|
|
Images.length - 1;
|
|
|
|
const ImageIndex = Math.min(
|
|
Math.floor(
|
|
Progress *
|
|
GrowingImageCount
|
|
),
|
|
GrowingImageCount - 1
|
|
);
|
|
|
|
return Images[
|
|
ImageIndex
|
|
] ?? null;
|
|
}
|
|
|
|
|
|
function FormatGardenRemainingTime(
|
|
Milliseconds
|
|
) {
|
|
const TotalSeconds =
|
|
Math.max(
|
|
0,
|
|
Math.ceil(
|
|
Number(
|
|
Milliseconds
|
|
) / 1000
|
|
)
|
|
);
|
|
|
|
const Hours = Math.floor(
|
|
TotalSeconds / 3600
|
|
);
|
|
|
|
const Minutes = Math.floor(
|
|
(TotalSeconds % 3600) / 60
|
|
);
|
|
|
|
const Seconds =
|
|
TotalSeconds % 60;
|
|
|
|
if (Hours > 0) {
|
|
return (
|
|
Hours +
|
|
":" +
|
|
String(Minutes).padStart(
|
|
2,
|
|
"0"
|
|
) +
|
|
":" +
|
|
String(Seconds).padStart(
|
|
2,
|
|
"0"
|
|
)
|
|
);
|
|
}
|
|
|
|
return (
|
|
Minutes +
|
|
":" +
|
|
String(Seconds).padStart(
|
|
2,
|
|
"0"
|
|
)
|
|
);
|
|
}
|
|
|
|
|
|
function GetGardenPlotTimerText(
|
|
Plot,
|
|
Plant,
|
|
Progress,
|
|
AtTime = Date.now(),
|
|
CooldownState = null
|
|
) {
|
|
if (
|
|
Plot === null ||
|
|
Plant === null ||
|
|
Plant === undefined
|
|
) {
|
|
return "";
|
|
}
|
|
|
|
if (
|
|
Progress >= 1 &&
|
|
CooldownState !== null
|
|
) {
|
|
return FormatGardenRemainingTime(
|
|
CooldownState.Remaining
|
|
);
|
|
}
|
|
|
|
if (Progress >= 1) {
|
|
return "Ready";
|
|
}
|
|
|
|
return FormatGardenRemainingTime(
|
|
Math.max(
|
|
0,
|
|
Number(Plant.GrowthTime ?? 0) -
|
|
(
|
|
Number(AtTime) -
|
|
Number(Plot.PlantedAt ?? 0)
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
|
|
function CreateGardenPlotView(
|
|
Options
|
|
) {
|
|
const Plot =
|
|
Options.Plot ?? null;
|
|
|
|
const Plant =
|
|
Options.Plant;
|
|
|
|
const Progress =
|
|
Number(
|
|
Options.Progress ?? 0
|
|
);
|
|
|
|
const BorderProgress =
|
|
Number(
|
|
Options.BorderProgress ??
|
|
Progress
|
|
);
|
|
|
|
const DisplaySettings =
|
|
Options.DisplaySettings ?? {};
|
|
|
|
const Tile =
|
|
document.createElement(
|
|
"div"
|
|
);
|
|
|
|
Tile.className =
|
|
"PlantTile GardenPlot";
|
|
|
|
if (Options.ReadOnly === true) {
|
|
Tile.classList.add(
|
|
"GardenPlotReadOnly"
|
|
);
|
|
}
|
|
|
|
if (
|
|
Options.FunctionalCooldown ===
|
|
true
|
|
) {
|
|
Tile.classList.add(
|
|
"GardenPlotFunctionalCooldown"
|
|
);
|
|
}
|
|
|
|
if (
|
|
Options.Mature === true
|
|
) {
|
|
Tile.classList.add(
|
|
"GardenPlotMature"
|
|
);
|
|
}
|
|
|
|
if (Plot === null) {
|
|
Tile.classList.add(
|
|
"GardenPlotEmpty"
|
|
);
|
|
} else if (
|
|
Plant !== null &&
|
|
Plant !== undefined
|
|
) {
|
|
Tile.style.setProperty(
|
|
"--GrowthProgress",
|
|
`${BorderProgress * 100}%`
|
|
);
|
|
}
|
|
|
|
const MainButton =
|
|
document.createElement(
|
|
"button"
|
|
);
|
|
|
|
MainButton.className =
|
|
"GardenPlotMain";
|
|
MainButton.type = "button";
|
|
MainButton.disabled =
|
|
Options.ReadOnly === true;
|
|
|
|
if (
|
|
DisplaySettings.ShowPlantNames
|
|
) {
|
|
Tile.classList.add(
|
|
"GardenPlotWithName"
|
|
);
|
|
|
|
MainButton.appendChild(
|
|
CreateGardenPlotName(
|
|
Plot,
|
|
Plant
|
|
)
|
|
);
|
|
}
|
|
|
|
const Visual =
|
|
document.createElement(
|
|
"span"
|
|
);
|
|
|
|
Visual.className =
|
|
"GardenPlotVisual";
|
|
|
|
if (
|
|
Plot !== null &&
|
|
Plant === undefined
|
|
) {
|
|
Visual.textContent = "?";
|
|
} else if (
|
|
Plot !== null &&
|
|
Plant !== null
|
|
) {
|
|
const ImagePath =
|
|
Options.ImagePath ?? null;
|
|
|
|
if (ImagePath !== null) {
|
|
const Image =
|
|
document.createElement(
|
|
"img"
|
|
);
|
|
|
|
Image.className =
|
|
"PlantSprite";
|
|
Image.alt =
|
|
Plant.Name ?? "";
|
|
Image.src =
|
|
ImagePath;
|
|
Image.draggable = false;
|
|
|
|
Visual.appendChild(
|
|
Image
|
|
);
|
|
} else {
|
|
const MissingImage =
|
|
document.createElement(
|
|
"span"
|
|
);
|
|
|
|
MissingImage.className =
|
|
"GardenPlantMissing";
|
|
MissingImage.textContent =
|
|
Plant.Name ?? "Unknown";
|
|
|
|
Visual.appendChild(
|
|
MissingImage
|
|
);
|
|
}
|
|
}
|
|
|
|
MainButton.appendChild(
|
|
Visual
|
|
);
|
|
|
|
Tile.appendChild(
|
|
MainButton
|
|
);
|
|
|
|
AppendGardenPlotFooter(
|
|
Tile,
|
|
Plot,
|
|
Plant,
|
|
DisplaySettings,
|
|
Options.TimerText ?? "",
|
|
Options.ShowRotation === true,
|
|
Options.OnRotate,
|
|
Options.ReadOnly === true
|
|
);
|
|
|
|
return {
|
|
Tile,
|
|
MainButton,
|
|
Visual
|
|
};
|
|
}
|
|
|
|
|
|
function AppendGardenPlotFooter(
|
|
Tile,
|
|
Plot,
|
|
Plant,
|
|
DisplaySettings,
|
|
TimerText,
|
|
ShowRotation,
|
|
OnRotate,
|
|
ReadOnly
|
|
) {
|
|
const ShowTimer =
|
|
DisplaySettings.ShowGrowthTimers ===
|
|
true;
|
|
|
|
if (
|
|
!ShowTimer &&
|
|
!ShowRotation
|
|
) {
|
|
return;
|
|
}
|
|
|
|
Tile.classList.add(
|
|
"GardenPlotWithFooter"
|
|
);
|
|
|
|
const Footer =
|
|
document.createElement(
|
|
"span"
|
|
);
|
|
|
|
Footer.className =
|
|
"GardenPlotFooter";
|
|
|
|
if (
|
|
ShowTimer &&
|
|
ShowRotation
|
|
) {
|
|
Footer.classList.add(
|
|
"GardenPlotFooterSplit"
|
|
);
|
|
}
|
|
|
|
if (ShowTimer) {
|
|
const Timer =
|
|
document.createElement(
|
|
"span"
|
|
);
|
|
|
|
Timer.className =
|
|
"GardenPlotTimer";
|
|
Timer.textContent =
|
|
TimerText;
|
|
|
|
Footer.appendChild(
|
|
Timer
|
|
);
|
|
}
|
|
|
|
if (ShowRotation) {
|
|
const RotateButton =
|
|
document.createElement(
|
|
"button"
|
|
);
|
|
|
|
RotateButton.className =
|
|
"GardenPlotRotationButton";
|
|
RotateButton.type = "button";
|
|
RotateButton.textContent =
|
|
GetGardenPlotRotationLabel(
|
|
Plot
|
|
);
|
|
RotateButton.title =
|
|
ReadOnly
|
|
? "Plot rotation"
|
|
: "Rotate plot clockwise";
|
|
RotateButton.setAttribute(
|
|
"aria-label",
|
|
ReadOnly
|
|
? (
|
|
Plant?.Name ?? "Plot"
|
|
) +
|
|
" faces " +
|
|
GetGardenPlotRotation(
|
|
Plot
|
|
).toLowerCase()
|
|
: "Rotate " +
|
|
(Plant?.Name ?? "plot") +
|
|
" clockwise"
|
|
);
|
|
RotateButton.disabled =
|
|
ReadOnly;
|
|
|
|
if (
|
|
!ReadOnly &&
|
|
typeof OnRotate ===
|
|
"function"
|
|
) {
|
|
RotateButton.addEventListener(
|
|
"click",
|
|
OnRotate
|
|
);
|
|
}
|
|
|
|
Footer.appendChild(
|
|
RotateButton
|
|
);
|
|
}
|
|
|
|
Tile.appendChild(
|
|
Footer
|
|
);
|
|
}
|
|
|
|
|
|
function CreateGardenPlotName(
|
|
Plot,
|
|
Plant
|
|
) {
|
|
const Name =
|
|
document.createElement(
|
|
"span"
|
|
);
|
|
|
|
Name.className =
|
|
"GardenPlotName";
|
|
|
|
if (Plot === null) {
|
|
Name.textContent =
|
|
"Empty";
|
|
} else if (Plant === undefined) {
|
|
Name.textContent =
|
|
"Unknown";
|
|
} else {
|
|
Name.textContent =
|
|
Plant.Name;
|
|
|
|
Name.title =
|
|
Plant.Name;
|
|
}
|
|
|
|
return Name;
|
|
}
|