mirror of
https://git.srhtnin.garden/sarah/srhtnin.github.io.git
synced 2026-10-15 11:03:17 +02:00
Added rotation to plots.. Only does stuff for functional plants.
This commit is contained in:
1 parent
75e4f31ccd
commit
132aba0b9a
14 files changed
+1189
-142
No files matched your search
+63
-2
@@ -246,6 +246,17 @@ $PageSection = "Admin";
|
|||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
<label class="AdminEditorCheckField">
|
||||||
|
<input
|
||||||
|
id="AdminPlantDirectionalSprites"
|
||||||
|
name="DirectionalSprites"
|
||||||
|
type="checkbox"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Directional sprites
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
<label class="AdminEditorField AdminEditorWideField">
|
<label class="AdminEditorField AdminEditorWideField">
|
||||||
<span>Effects JSON</span>
|
<span>Effects JSON</span>
|
||||||
<textarea
|
<textarea
|
||||||
@@ -323,15 +334,66 @@ $PageSection = "Admin";
|
|||||||
Optional. You can save a plant with no sprites and add them later.
|
Optional. You can save a plant with no sprites and add them later.
|
||||||
Upload PNG files named by stage, such as
|
Upload PNG files named by stage, such as
|
||||||
<code>1.png</code>, <code>2.png</code>, <code>3.png</code>.
|
<code>1.png</code>, <code>2.png</code>, <code>3.png</code>.
|
||||||
|
Directional plants use one stage set for each direction.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="AdminPlantImageUpload">
|
<div
|
||||||
|
id="AdminPlantDefaultImageUpload"
|
||||||
|
class="AdminPlantImageUpload"
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
id="AdminPlantImageFiles"
|
id="AdminPlantImageFiles"
|
||||||
type="file"
|
type="file"
|
||||||
accept="image/png,.png"
|
accept="image/png,.png"
|
||||||
multiple
|
multiple
|
||||||
>
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
id="AdminPlantDirectionalImageUpload"
|
||||||
|
class="AdminPlantDirectionalImageUpload"
|
||||||
|
hidden
|
||||||
|
>
|
||||||
|
<label class="AdminEditorField">
|
||||||
|
<span>North sprites</span>
|
||||||
|
<input
|
||||||
|
id="AdminPlantImageFilesNorth"
|
||||||
|
type="file"
|
||||||
|
accept="image/png,.png"
|
||||||
|
multiple
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="AdminEditorField">
|
||||||
|
<span>East sprites</span>
|
||||||
|
<input
|
||||||
|
id="AdminPlantImageFilesEast"
|
||||||
|
type="file"
|
||||||
|
accept="image/png,.png"
|
||||||
|
multiple
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="AdminEditorField">
|
||||||
|
<span>South sprites</span>
|
||||||
|
<input
|
||||||
|
id="AdminPlantImageFilesSouth"
|
||||||
|
type="file"
|
||||||
|
accept="image/png,.png"
|
||||||
|
multiple
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="AdminEditorField">
|
||||||
|
<span>West sprites</span>
|
||||||
|
<input
|
||||||
|
id="AdminPlantImageFilesWest"
|
||||||
|
type="file"
|
||||||
|
accept="image/png,.png"
|
||||||
|
multiple
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
id="AdminPlantImageUploadButton"
|
id="AdminPlantImageUploadButton"
|
||||||
@@ -340,7 +402,6 @@ $PageSection = "Admin";
|
|||||||
>
|
>
|
||||||
Upload selected sprites
|
Upload selected sprites
|
||||||
</button>
|
</button>
|
||||||
</div>
|
|
||||||
|
|
||||||
<p
|
<p
|
||||||
id="AdminPlantImageNote"
|
id="AdminPlantImageNote"
|
||||||
|
|||||||
@@ -159,6 +159,30 @@ $PageTitle = "Profile";
|
|||||||
to use these settings.
|
to use these settings.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h3>Plot rotation</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Choose whether plot directions are shown
|
||||||
|
beside plot timers.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="ProfileButtonRow">
|
||||||
|
<button
|
||||||
|
id="TogglePlotRotationButton"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Plot rotation: Locked
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p
|
||||||
|
id="PlotRotationDisplayMessage"
|
||||||
|
class="ProfileMessage"
|
||||||
|
>
|
||||||
|
Unlock Plot rotation in the Shop
|
||||||
|
to use this setting.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h3>Garden overview</h3>
|
<h3>Garden overview</h3>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
@@ -402,6 +402,8 @@ function BuildAdminMassPlantPayload(
|
|||||||
Source.Effects ?? {}
|
Source.Effects ?? {}
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
DirectionalSprites:
|
||||||
|
Source.DirectionalSprites === true,
|
||||||
ShopPlant:
|
ShopPlant:
|
||||||
Source.Shop?.ShopPlant === true,
|
Source.Shop?.ShopPlant === true,
|
||||||
BaseCost:
|
BaseCost:
|
||||||
|
|||||||
@@ -95,10 +95,23 @@ function GetAdminOverviewMissingSprites(
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const DirectionalStages =
|
||||||
|
Array.isArray(
|
||||||
|
Plant.DirectionalImageStages
|
||||||
|
)
|
||||||
|
? Plant.DirectionalImageStages
|
||||||
|
: [];
|
||||||
|
|
||||||
const HighestApiStage =
|
const HighestApiStage =
|
||||||
Math.max(
|
Math.max(
|
||||||
0,
|
0,
|
||||||
...ApiStages
|
...ApiStages,
|
||||||
|
...DirectionalStages.map(
|
||||||
|
Stage =>
|
||||||
|
Number(
|
||||||
|
Stage?.Stage ?? 0
|
||||||
|
)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
const HighestStage =
|
const HighestStage =
|
||||||
@@ -110,6 +123,51 @@ function GetAdminOverviewMissingSprites(
|
|||||||
|
|
||||||
const Missing = [];
|
const Missing = [];
|
||||||
|
|
||||||
|
if (Plant.DirectionalSprites === true) {
|
||||||
|
const Directions = [
|
||||||
|
["N", "North"],
|
||||||
|
["E", "East"],
|
||||||
|
["S", "South"],
|
||||||
|
["W", "West"]
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const [Code, Name] of Directions) {
|
||||||
|
const Stages = new Set(
|
||||||
|
DirectionalStages
|
||||||
|
.filter(
|
||||||
|
Stage =>
|
||||||
|
String(
|
||||||
|
Stage?.Direction ?? ""
|
||||||
|
).toUpperCase() === Code
|
||||||
|
)
|
||||||
|
.map(
|
||||||
|
Stage =>
|
||||||
|
Number(Stage.Stage)
|
||||||
|
)
|
||||||
|
.filter(
|
||||||
|
Stage =>
|
||||||
|
Number.isInteger(Stage) &&
|
||||||
|
Stage > 0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
for (
|
||||||
|
let Stage = 1;
|
||||||
|
Stage <= HighestStage;
|
||||||
|
Stage++
|
||||||
|
) {
|
||||||
|
if (!Stages.has(Stage)) {
|
||||||
|
Missing.push(
|
||||||
|
Name + "/" +
|
||||||
|
Stage + ".png"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Missing;
|
||||||
|
}
|
||||||
|
|
||||||
for (
|
for (
|
||||||
let Stage = 1;
|
let Stage = 1;
|
||||||
Stage <= HighestStage;
|
Stage <= HighestStage;
|
||||||
@@ -132,7 +190,6 @@ function GetAdminOverviewMissingSprites(
|
|||||||
return Missing;
|
return Missing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function CollectAdminOverviewCreatedPlants() {
|
function CollectAdminOverviewCreatedPlants() {
|
||||||
const Created = new Set();
|
const Created = new Set();
|
||||||
|
|
||||||
|
|||||||
@@ -168,6 +168,16 @@ function BindAdminPlantEditor() {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
document.getElementById(
|
||||||
|
"AdminPlantDirectionalSprites"
|
||||||
|
).addEventListener(
|
||||||
|
"change",
|
||||||
|
() => {
|
||||||
|
RenderAdminPlantImageManager();
|
||||||
|
RenderAdminPlantPreview();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
document.getElementById(
|
document.getElementById(
|
||||||
"AdminPlantImageUploadButton"
|
"AdminPlantImageUploadButton"
|
||||||
).addEventListener(
|
).addEventListener(
|
||||||
@@ -540,6 +550,11 @@ function LoadAdminPlantIntoForm(
|
|||||||
).checked =
|
).checked =
|
||||||
Plant.Shop?.ShopPlant === true;
|
Plant.Shop?.ShopPlant === true;
|
||||||
|
|
||||||
|
document.getElementById(
|
||||||
|
"AdminPlantDirectionalSprites"
|
||||||
|
).checked =
|
||||||
|
Plant.DirectionalSprites === true;
|
||||||
|
|
||||||
SetAdminPlantField(
|
SetAdminPlantField(
|
||||||
"AdminPlantBaseCost",
|
"AdminPlantBaseCost",
|
||||||
Plant.Shop?.BaseCost ?? ""
|
Plant.Shop?.BaseCost ?? ""
|
||||||
@@ -648,6 +663,11 @@ function DuplicateAdminPlant() {
|
|||||||
).checked =
|
).checked =
|
||||||
SourcePlant.Shop?.ShopPlant === true;
|
SourcePlant.Shop?.ShopPlant === true;
|
||||||
|
|
||||||
|
document.getElementById(
|
||||||
|
"AdminPlantDirectionalSprites"
|
||||||
|
).checked =
|
||||||
|
SourcePlant.DirectionalSprites === true;
|
||||||
|
|
||||||
SetAdminPlantField(
|
SetAdminPlantField(
|
||||||
"AdminPlantBaseCost",
|
"AdminPlantBaseCost",
|
||||||
SourcePlant.Shop?.BaseCost ?? ""
|
SourcePlant.Shop?.BaseCost ?? ""
|
||||||
@@ -734,6 +754,10 @@ function StartNewAdminPlant() {
|
|||||||
"AdminPlantShopPlant"
|
"AdminPlantShopPlant"
|
||||||
).checked = false;
|
).checked = false;
|
||||||
|
|
||||||
|
document.getElementById(
|
||||||
|
"AdminPlantDirectionalSprites"
|
||||||
|
).checked = false;
|
||||||
|
|
||||||
SetAdminPlantField(
|
SetAdminPlantField(
|
||||||
"AdminPlantBaseCost",
|
"AdminPlantBaseCost",
|
||||||
""
|
""
|
||||||
@@ -910,6 +934,11 @@ function GetAdminPlantFormData() {
|
|||||||
Effects:
|
Effects:
|
||||||
ParseAdminPlantEffects(),
|
ParseAdminPlantEffects(),
|
||||||
|
|
||||||
|
DirectionalSprites:
|
||||||
|
document.getElementById(
|
||||||
|
"AdminPlantDirectionalSprites"
|
||||||
|
).checked,
|
||||||
|
|
||||||
ShopPlant: ShopPlant,
|
ShopPlant: ShopPlant,
|
||||||
|
|
||||||
BaseCost:
|
BaseCost:
|
||||||
@@ -1249,6 +1278,10 @@ function GetAdminPlantPreviewDefinition() {
|
|||||||
"AdminPlantHarvestMultiplier"
|
"AdminPlantHarvestMultiplier"
|
||||||
).value
|
).value
|
||||||
),
|
),
|
||||||
|
DirectionalSprites:
|
||||||
|
document.getElementById(
|
||||||
|
"AdminPlantDirectionalSprites"
|
||||||
|
).checked,
|
||||||
Shop: {
|
Shop: {
|
||||||
ShopPlant: ShopPlant,
|
ShopPlant: ShopPlant,
|
||||||
BaseCost:
|
BaseCost:
|
||||||
@@ -1426,16 +1459,43 @@ function RenderAdminPlantImageManager() {
|
|||||||
"AdminPlantImageUploadButton"
|
"AdminPlantImageUploadButton"
|
||||||
);
|
);
|
||||||
|
|
||||||
const FileInput =
|
const DefaultUpload =
|
||||||
document.getElementById(
|
document.getElementById(
|
||||||
"AdminPlantImageFiles"
|
"AdminPlantDefaultImageUpload"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const DirectionalUpload =
|
||||||
|
document.getElementById(
|
||||||
|
"AdminPlantDirectionalImageUpload"
|
||||||
|
);
|
||||||
|
|
||||||
|
const DirectionalToggle =
|
||||||
|
document.getElementById(
|
||||||
|
"AdminPlantDirectionalSprites"
|
||||||
|
);
|
||||||
|
|
||||||
|
const Inputs = [
|
||||||
|
"AdminPlantImageFiles",
|
||||||
|
"AdminPlantImageFilesNorth",
|
||||||
|
"AdminPlantImageFilesEast",
|
||||||
|
"AdminPlantImageFilesSouth",
|
||||||
|
"AdminPlantImageFilesWest"
|
||||||
|
]
|
||||||
|
.map(
|
||||||
|
ElementId =>
|
||||||
|
document.getElementById(
|
||||||
|
ElementId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
List === null ||
|
List === null ||
|
||||||
Note === null ||
|
Note === null ||
|
||||||
UploadButton === null ||
|
UploadButton === null ||
|
||||||
FileInput === null
|
DefaultUpload === null ||
|
||||||
|
DirectionalUpload === null ||
|
||||||
|
DirectionalToggle === null
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1449,6 +1509,15 @@ function RenderAdminPlantImageManager() {
|
|||||||
AdminPlantEditingKey
|
AdminPlantEditingKey
|
||||||
] ?? null;
|
] ?? null;
|
||||||
|
|
||||||
|
const IsDirectional =
|
||||||
|
DirectionalToggle.checked;
|
||||||
|
|
||||||
|
DefaultUpload.hidden =
|
||||||
|
IsDirectional;
|
||||||
|
|
||||||
|
DirectionalUpload.hidden =
|
||||||
|
!IsDirectional;
|
||||||
|
|
||||||
const CanEdit =
|
const CanEdit =
|
||||||
Plant !== null &&
|
Plant !== null &&
|
||||||
!AdminPlantImagePending;
|
!AdminPlantImagePending;
|
||||||
@@ -1456,8 +1525,9 @@ function RenderAdminPlantImageManager() {
|
|||||||
UploadButton.disabled =
|
UploadButton.disabled =
|
||||||
!CanEdit;
|
!CanEdit;
|
||||||
|
|
||||||
FileInput.disabled =
|
for (const Input of Inputs) {
|
||||||
!CanEdit;
|
Input.disabled = !CanEdit;
|
||||||
|
}
|
||||||
|
|
||||||
if (Plant === null) {
|
if (Plant === null) {
|
||||||
Note.textContent =
|
Note.textContent =
|
||||||
@@ -1466,6 +1536,7 @@ function RenderAdminPlantImageManager() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const StaticImages =
|
const StaticImages =
|
||||||
|
typeof PlantImages !== "undefined" &&
|
||||||
Array.isArray(
|
Array.isArray(
|
||||||
PlantImages[
|
PlantImages[
|
||||||
AdminPlantEditingKey
|
AdminPlantEditingKey
|
||||||
@@ -1488,6 +1559,44 @@ function RenderAdminPlantImageManager() {
|
|||||||
)
|
)
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
|
const DirectionOrder = {
|
||||||
|
N: 0,
|
||||||
|
E: 1,
|
||||||
|
S: 2,
|
||||||
|
W: 3
|
||||||
|
};
|
||||||
|
|
||||||
|
const DirectionNames = {
|
||||||
|
N: "North",
|
||||||
|
E: "East",
|
||||||
|
S: "South",
|
||||||
|
W: "West"
|
||||||
|
};
|
||||||
|
|
||||||
|
const DirectionalStages =
|
||||||
|
Array.isArray(
|
||||||
|
Plant.DirectionalImageStages
|
||||||
|
)
|
||||||
|
? [...Plant.DirectionalImageStages]
|
||||||
|
.sort(
|
||||||
|
(A, B) =>
|
||||||
|
Number(A.Stage) -
|
||||||
|
Number(B.Stage) ||
|
||||||
|
(
|
||||||
|
DirectionOrder[
|
||||||
|
String(A.Direction)
|
||||||
|
.toUpperCase()
|
||||||
|
] ?? 99
|
||||||
|
) -
|
||||||
|
(
|
||||||
|
DirectionOrder[
|
||||||
|
String(B.Direction)
|
||||||
|
.toUpperCase()
|
||||||
|
] ?? 99
|
||||||
|
)
|
||||||
|
)
|
||||||
|
: [];
|
||||||
|
|
||||||
const FallbackText =
|
const FallbackText =
|
||||||
StaticImages.length > 0
|
StaticImages.length > 0
|
||||||
? " Repository fallback: " +
|
? " Repository fallback: " +
|
||||||
@@ -1500,28 +1609,45 @@ function RenderAdminPlantImageManager() {
|
|||||||
)
|
)
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
if (ApiStages.length === 0) {
|
const DisplayStages =
|
||||||
|
IsDirectional
|
||||||
|
? DirectionalStages
|
||||||
|
: ApiStages;
|
||||||
|
|
||||||
|
if (DisplayStages.length === 0) {
|
||||||
Note.textContent =
|
Note.textContent =
|
||||||
"No API sprites uploaded." +
|
IsDirectional
|
||||||
|
? "No directional API sprites uploaded. Choose stage-numbered PNGs for each direction." +
|
||||||
|
FallbackText
|
||||||
|
: "No API sprites uploaded." +
|
||||||
FallbackText;
|
FallbackText;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Note.textContent =
|
Note.textContent =
|
||||||
ApiStages.length +
|
DisplayStages.length +
|
||||||
" API sprite" +
|
(IsDirectional
|
||||||
|
? " directional API sprite"
|
||||||
|
: " API sprite") +
|
||||||
(
|
(
|
||||||
ApiStages.length === 1
|
DisplayStages.length === 1
|
||||||
? " uploaded."
|
? " uploaded."
|
||||||
: "s uploaded."
|
: "s uploaded."
|
||||||
) +
|
) +
|
||||||
FallbackText;
|
FallbackText;
|
||||||
|
|
||||||
for (const ImageStage of ApiStages) {
|
for (const ImageStage of DisplayStages) {
|
||||||
const Stage = Number(
|
const Stage = Number(
|
||||||
ImageStage.Stage
|
ImageStage.Stage
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const Direction =
|
||||||
|
IsDirectional
|
||||||
|
? String(
|
||||||
|
ImageStage.Direction ?? ""
|
||||||
|
).toUpperCase()
|
||||||
|
: null;
|
||||||
|
|
||||||
const Row =
|
const Row =
|
||||||
document.createElement(
|
document.createElement(
|
||||||
"div"
|
"div"
|
||||||
@@ -1550,13 +1676,24 @@ function RenderAdminPlantImageManager() {
|
|||||||
GetAdminPlantApiImageUrl(
|
GetAdminPlantApiImageUrl(
|
||||||
Plant.Id,
|
Plant.Id,
|
||||||
Stage,
|
Stage,
|
||||||
ImageStage.Revision
|
ImageStage.Revision,
|
||||||
|
Direction
|
||||||
);
|
);
|
||||||
|
|
||||||
Image.alt =
|
Image.alt =
|
||||||
Plant.Name +
|
Plant.Name +
|
||||||
" stage " +
|
" stage " +
|
||||||
Stage;
|
Stage +
|
||||||
|
(
|
||||||
|
Direction === null
|
||||||
|
? ""
|
||||||
|
: " " +
|
||||||
|
(
|
||||||
|
DirectionNames[
|
||||||
|
Direction
|
||||||
|
] ?? Direction
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
Preview.appendChild(Image);
|
Preview.appendChild(Image);
|
||||||
|
|
||||||
@@ -1566,7 +1703,17 @@ function RenderAdminPlantImageManager() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
Label.textContent =
|
Label.textContent =
|
||||||
"Stage " + Stage;
|
"Stage " + Stage +
|
||||||
|
(
|
||||||
|
Direction === null
|
||||||
|
? ""
|
||||||
|
: " · " +
|
||||||
|
(
|
||||||
|
DirectionNames[
|
||||||
|
Direction
|
||||||
|
] ?? Direction
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
const RemoveButton =
|
const RemoveButton =
|
||||||
document.createElement(
|
document.createElement(
|
||||||
@@ -1586,7 +1733,8 @@ function RenderAdminPlantImageManager() {
|
|||||||
() =>
|
() =>
|
||||||
DeleteAdminPlantImage(
|
DeleteAdminPlantImage(
|
||||||
Plant.Id,
|
Plant.Id,
|
||||||
Stage
|
Stage,
|
||||||
|
Direction
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1604,14 +1752,24 @@ function RenderAdminPlantImageManager() {
|
|||||||
function GetAdminPlantApiImageUrl(
|
function GetAdminPlantApiImageUrl(
|
||||||
PlantId,
|
PlantId,
|
||||||
Stage,
|
Stage,
|
||||||
Revision = 0
|
Revision = 0,
|
||||||
|
Direction = null
|
||||||
) {
|
) {
|
||||||
const Query =
|
const QueryData = {
|
||||||
new URLSearchParams({
|
|
||||||
PlantId: String(PlantId),
|
PlantId: String(PlantId),
|
||||||
Stage: String(Stage),
|
Stage: String(Stage),
|
||||||
v: String(Revision ?? 0)
|
v: String(Revision ?? 0)
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if (Direction !== null) {
|
||||||
|
QueryData.Direction =
|
||||||
|
String(Direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Query =
|
||||||
|
new URLSearchParams(
|
||||||
|
QueryData
|
||||||
|
);
|
||||||
|
|
||||||
return ApiUrl +
|
return ApiUrl +
|
||||||
"/PlantImage.php?" +
|
"/PlantImage.php?" +
|
||||||
@@ -1619,6 +1777,41 @@ function GetAdminPlantApiImageUrl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function GetAdminPlantImageUploadSets() {
|
||||||
|
const IsDirectional =
|
||||||
|
document.getElementById(
|
||||||
|
"AdminPlantDirectionalSprites"
|
||||||
|
).checked;
|
||||||
|
|
||||||
|
if (!IsDirectional) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
Direction: null,
|
||||||
|
Input:
|
||||||
|
document.getElementById(
|
||||||
|
"AdminPlantImageFiles"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
["N", "AdminPlantImageFilesNorth"],
|
||||||
|
["E", "AdminPlantImageFilesEast"],
|
||||||
|
["S", "AdminPlantImageFilesSouth"],
|
||||||
|
["W", "AdminPlantImageFilesWest"]
|
||||||
|
].map(
|
||||||
|
([Direction, ElementId]) => ({
|
||||||
|
Direction: Direction,
|
||||||
|
Input:
|
||||||
|
document.getElementById(
|
||||||
|
ElementId
|
||||||
|
)
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async function UploadAdminPlantImages() {
|
async function UploadAdminPlantImages() {
|
||||||
if (
|
if (
|
||||||
AdminPlantImagePending ||
|
AdminPlantImagePending ||
|
||||||
@@ -1636,30 +1829,22 @@ async function UploadAdminPlantImages() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FileInput =
|
|
||||||
document.getElementById(
|
|
||||||
"AdminPlantImageFiles"
|
|
||||||
);
|
|
||||||
|
|
||||||
const Files =
|
|
||||||
Array.from(
|
|
||||||
FileInput.files ?? []
|
|
||||||
);
|
|
||||||
|
|
||||||
if (Files.length === 0) {
|
|
||||||
SetAdminPlantMessage(
|
|
||||||
"Choose one or more PNG sprites first."
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Stages = new Set();
|
|
||||||
const Uploads = [];
|
const Uploads = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
for (
|
||||||
|
const UploadSet
|
||||||
|
of GetAdminPlantImageUploadSets()
|
||||||
|
) {
|
||||||
|
const Files = Array.from(
|
||||||
|
UploadSet.Input?.files ?? []
|
||||||
|
);
|
||||||
|
|
||||||
|
const Stages = new Set();
|
||||||
|
|
||||||
for (const File of Files) {
|
for (const File of Files) {
|
||||||
const Match =
|
const Match =
|
||||||
/^(\\d+)\\.png$/i.exec(
|
/^(\d+)\.png$/i.exec(
|
||||||
File.name
|
File.name
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1685,9 +1870,8 @@ async function UploadAdminPlantImages() {
|
|||||||
|
|
||||||
if (Stages.has(Stage)) {
|
if (Stages.has(Stage)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Stage " +
|
"Stage " + Stage +
|
||||||
Stage +
|
" was selected more than once for the same direction."
|
||||||
" was selected more than once."
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1695,9 +1879,12 @@ async function UploadAdminPlantImages() {
|
|||||||
|
|
||||||
Uploads.push({
|
Uploads.push({
|
||||||
Stage: Stage,
|
Stage: Stage,
|
||||||
|
Direction:
|
||||||
|
UploadSet.Direction,
|
||||||
File: File
|
File: File
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (Error) {
|
} catch (Error) {
|
||||||
SetAdminPlantMessage(
|
SetAdminPlantMessage(
|
||||||
Error.message
|
Error.message
|
||||||
@@ -1705,6 +1892,13 @@ async function UploadAdminPlantImages() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Uploads.length === 0) {
|
||||||
|
SetAdminPlantMessage(
|
||||||
|
"Choose one or more PNG sprites first."
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
AdminPlantImagePending = true;
|
AdminPlantImagePending = true;
|
||||||
RenderAdminPlantImageManager();
|
RenderAdminPlantImageManager();
|
||||||
|
|
||||||
@@ -1719,18 +1913,32 @@ async function UploadAdminPlantImages() {
|
|||||||
Upload.File
|
Upload.File
|
||||||
);
|
);
|
||||||
|
|
||||||
await AdminPlantRequest(
|
const RequestData = {
|
||||||
"UploadImage",
|
|
||||||
{
|
|
||||||
PlantId: Plant.Id,
|
PlantId: Plant.Id,
|
||||||
Stage: Upload.Stage,
|
Stage: Upload.Stage,
|
||||||
MimeType: "image/png",
|
MimeType: "image/png",
|
||||||
DataBase64: DataBase64
|
DataBase64: DataBase64
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Upload.Direction !== null) {
|
||||||
|
RequestData.Direction =
|
||||||
|
Upload.Direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await AdminPlantRequest(
|
||||||
|
"UploadImage",
|
||||||
|
RequestData
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
FileInput.value = "";
|
for (
|
||||||
|
const UploadSet
|
||||||
|
of GetAdminPlantImageUploadSets()
|
||||||
|
) {
|
||||||
|
if (UploadSet.Input !== null) {
|
||||||
|
UploadSet.Input.value = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
localStorage.removeItem(
|
localStorage.removeItem(
|
||||||
"SarahtoninGardenContent"
|
"SarahtoninGardenContent"
|
||||||
@@ -1818,7 +2026,8 @@ function ReadAdminPlantFileBase64(
|
|||||||
|
|
||||||
async function DeleteAdminPlantImage(
|
async function DeleteAdminPlantImage(
|
||||||
PlantId,
|
PlantId,
|
||||||
Stage
|
Stage,
|
||||||
|
Direction = null
|
||||||
) {
|
) {
|
||||||
if (AdminPlantImagePending) {
|
if (AdminPlantImagePending) {
|
||||||
return;
|
return;
|
||||||
@@ -1830,16 +2039,28 @@ async function DeleteAdminPlantImage(
|
|||||||
SetAdminPlantMessage(
|
SetAdminPlantMessage(
|
||||||
"Removing stage " +
|
"Removing stage " +
|
||||||
Stage +
|
Stage +
|
||||||
|
(
|
||||||
|
Direction === null
|
||||||
|
? ""
|
||||||
|
: " " + Direction
|
||||||
|
) +
|
||||||
" sprite..."
|
" sprite..."
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await AdminPlantRequest(
|
const RequestData = {
|
||||||
"DeleteImage",
|
|
||||||
{
|
|
||||||
PlantId: PlantId,
|
PlantId: PlantId,
|
||||||
Stage: Stage
|
Stage: Stage
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Direction !== null) {
|
||||||
|
RequestData.Direction =
|
||||||
|
Direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await AdminPlantRequest(
|
||||||
|
"DeleteImage",
|
||||||
|
RequestData
|
||||||
);
|
);
|
||||||
|
|
||||||
localStorage.removeItem(
|
localStorage.removeItem(
|
||||||
@@ -1853,6 +2074,11 @@ async function DeleteAdminPlantImage(
|
|||||||
SetAdminPlantMessage(
|
SetAdminPlantMessage(
|
||||||
"Stage " +
|
"Stage " +
|
||||||
Stage +
|
Stage +
|
||||||
|
(
|
||||||
|
Direction === null
|
||||||
|
? ""
|
||||||
|
: " " + Direction
|
||||||
|
) +
|
||||||
" sprite removed."
|
" sprite removed."
|
||||||
);
|
);
|
||||||
} catch (Error) {
|
} catch (Error) {
|
||||||
@@ -1888,6 +2114,8 @@ function GetAdminPlantPortableData(
|
|||||||
Plant.Effects ?? {}
|
Plant.Effects ?? {}
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
DirectionalSprites:
|
||||||
|
Plant.DirectionalSprites === true,
|
||||||
Shop: {
|
Shop: {
|
||||||
ShopPlant:
|
ShopPlant:
|
||||||
Plant.ShopPlant === true,
|
Plant.ShopPlant === true,
|
||||||
@@ -2060,6 +2288,9 @@ async function ImportAdminPlantJson(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
: {},
|
: {},
|
||||||
|
DirectionalSprites:
|
||||||
|
Imported.DirectionalSprites ===
|
||||||
|
true,
|
||||||
ShopPlant:
|
ShopPlant:
|
||||||
Shop.ShopPlant === true ||
|
Shop.ShopPlant === true ||
|
||||||
Imported.ShopPlant === true,
|
Imported.ShopPlant === true,
|
||||||
@@ -2120,6 +2351,11 @@ async function ImportAdminPlantJson(
|
|||||||
"AdminPlantShopPlant"
|
"AdminPlantShopPlant"
|
||||||
).checked = Plant.ShopPlant;
|
).checked = Plant.ShopPlant;
|
||||||
|
|
||||||
|
document.getElementById(
|
||||||
|
"AdminPlantDirectionalSprites"
|
||||||
|
).checked =
|
||||||
|
Plant.DirectionalSprites;
|
||||||
|
|
||||||
SetAdminPlantField(
|
SetAdminPlantField(
|
||||||
"AdminPlantBaseCost",
|
"AdminPlantBaseCost",
|
||||||
Plant.BaseCost ?? ""
|
Plant.BaseCost ?? ""
|
||||||
|
|||||||
@@ -205,6 +205,15 @@ function ValidateAdminPlant(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
Plant.DirectionalSprites !== undefined &&
|
||||||
|
typeof Plant.DirectionalSprites !== "boolean"
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
"Directional sprites must be On or Off."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (Plant.ShopPlant === true) {
|
if (Plant.ShopPlant === true) {
|
||||||
ValidateAdminInteger(
|
ValidateAdminInteger(
|
||||||
Number(Plant.BaseCost),
|
Number(Plant.BaseCost),
|
||||||
|
|||||||
+293
-75
@@ -26,6 +26,20 @@ const GardenBorderColours = [
|
|||||||
"var(--Lavender)"
|
"var(--Lavender)"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const GardenPlotDefaultRotation = "East";
|
||||||
|
const GardenPlotRotations = [
|
||||||
|
"North",
|
||||||
|
"East",
|
||||||
|
"South",
|
||||||
|
"West"
|
||||||
|
];
|
||||||
|
const GardenPlotRotationLabels = {
|
||||||
|
North: "^",
|
||||||
|
East: "->",
|
||||||
|
South: "v",
|
||||||
|
West: "<-"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
function GetGardenBorderColour(
|
function GetGardenBorderColour(
|
||||||
GardenIndex
|
GardenIndex
|
||||||
@@ -1383,7 +1397,9 @@ function AreGardenPlotsEqual(
|
|||||||
return (
|
return (
|
||||||
A.Plant === B.Plant &&
|
A.Plant === B.Plant &&
|
||||||
Number(A.PlantedAt) ===
|
Number(A.PlantedAt) ===
|
||||||
Number(B.PlantedAt)
|
Number(B.PlantedAt) &&
|
||||||
|
GetGardenPlotRotation(A) ===
|
||||||
|
GetGardenPlotRotation(B)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1405,44 +1421,135 @@ function GetGardenDisplaySettings() {
|
|||||||
HasPlantInformation &&
|
HasPlantInformation &&
|
||||||
GameSave.Preferences
|
GameSave.Preferences
|
||||||
.ShowGrowthTimers !==
|
.ShowGrowthTimers !==
|
||||||
|
false,
|
||||||
|
|
||||||
|
ShowPlotRotation:
|
||||||
|
HasRotationUpgrade(
|
||||||
|
GameSave
|
||||||
|
) &&
|
||||||
|
GameSave.Preferences
|
||||||
|
.ShowPlotRotation !==
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function GetGardenPlotRotation(
|
||||||
|
Plot
|
||||||
|
) {
|
||||||
|
return GardenPlotRotations.includes(
|
||||||
|
Plot?.Rotation
|
||||||
|
)
|
||||||
|
? Plot.Rotation
|
||||||
|
: GardenPlotDefaultRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function GetGardenPlotRotationLabel(
|
||||||
|
Plot
|
||||||
|
) {
|
||||||
|
return GardenPlotRotationLabels[
|
||||||
|
GetGardenPlotRotation(
|
||||||
|
Plot
|
||||||
|
)
|
||||||
|
] ?? "->";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function RotateGardenPlot(
|
||||||
|
PlotIndex
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
!HasRotationUpgrade(
|
||||||
|
GameSave
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ActionTime = Date.now();
|
||||||
|
|
||||||
|
AdvanceGameSimulation(
|
||||||
|
GameSave,
|
||||||
|
ActionTime
|
||||||
|
);
|
||||||
|
|
||||||
|
const Plot =
|
||||||
|
GameSave.Garden.Plots[
|
||||||
|
PlotIndex
|
||||||
|
];
|
||||||
|
|
||||||
|
if (
|
||||||
|
Plot === null ||
|
||||||
|
typeof Plot !== "object"
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CurrentIndex =
|
||||||
|
GardenPlotRotations.indexOf(
|
||||||
|
GetGardenPlotRotation(
|
||||||
|
Plot
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
Plot.Rotation =
|
||||||
|
GardenPlotRotations[
|
||||||
|
(CurrentIndex + 1) %
|
||||||
|
GardenPlotRotations.length
|
||||||
|
];
|
||||||
|
|
||||||
|
const Plant =
|
||||||
|
Plants[Plot.Plant];
|
||||||
|
|
||||||
|
SetGardenMessage(
|
||||||
|
"Rotated " +
|
||||||
|
(Plant?.Name ?? "plot") +
|
||||||
|
" " +
|
||||||
|
Plot.Rotation.toLowerCase() +
|
||||||
|
"."
|
||||||
|
);
|
||||||
|
|
||||||
|
RenderGame();
|
||||||
|
|
||||||
|
await SaveGame(
|
||||||
|
GameSave
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function CreatePlotElement(
|
function CreatePlotElement(
|
||||||
Plot,
|
Plot,
|
||||||
PlotIndex,
|
PlotIndex,
|
||||||
DisplaySettings,
|
DisplaySettings,
|
||||||
IsPreview = false
|
IsPreview = false
|
||||||
) {
|
) {
|
||||||
const Button =
|
const Tile =
|
||||||
|
document.createElement(
|
||||||
|
"div"
|
||||||
|
);
|
||||||
|
|
||||||
|
Tile.className =
|
||||||
|
"PlantTile GardenPlot";
|
||||||
|
|
||||||
|
const MainButton =
|
||||||
document.createElement(
|
document.createElement(
|
||||||
"button"
|
"button"
|
||||||
);
|
);
|
||||||
|
|
||||||
Button.className =
|
MainButton.className =
|
||||||
"PlantTile GardenPlot";
|
"GardenPlotMain";
|
||||||
|
MainButton.type = "button";
|
||||||
Button.type = "button";
|
|
||||||
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
DisplaySettings.ShowPlantNames
|
DisplaySettings.ShowPlantNames
|
||||||
) {
|
) {
|
||||||
Button.classList.add(
|
Tile.classList.add(
|
||||||
"GardenPlotWithName"
|
"GardenPlotWithName"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
|
||||||
DisplaySettings.ShowGrowthTimers
|
|
||||||
) {
|
|
||||||
Button.classList.add(
|
|
||||||
"GardenPlotWithTimer"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const Plant =
|
const Plant =
|
||||||
Plot === null
|
Plot === null
|
||||||
@@ -1452,7 +1559,7 @@ function CreatePlotElement(
|
|||||||
if (
|
if (
|
||||||
DisplaySettings.ShowPlantNames
|
DisplaySettings.ShowPlantNames
|
||||||
) {
|
) {
|
||||||
Button.appendChild(
|
MainButton.appendChild(
|
||||||
CreateGardenPlotName(
|
CreateGardenPlotName(
|
||||||
Plot,
|
Plot,
|
||||||
Plant
|
Plant
|
||||||
@@ -1469,43 +1576,45 @@ function CreatePlotElement(
|
|||||||
Visual.className =
|
Visual.className =
|
||||||
"GardenPlotVisual";
|
"GardenPlotVisual";
|
||||||
|
|
||||||
Button.appendChild(
|
MainButton.appendChild(
|
||||||
Visual
|
Visual
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Tile.appendChild(
|
||||||
|
MainButton
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
if (Plot === null) {
|
if (Plot === null) {
|
||||||
Button.classList.add(
|
Tile.classList.add(
|
||||||
"GardenPlotEmpty"
|
"GardenPlotEmpty"
|
||||||
);
|
);
|
||||||
|
|
||||||
Button.title =
|
MainButton.title =
|
||||||
IsPreview
|
IsPreview
|
||||||
? "Future Sight: empty plot"
|
? "Future Sight: empty plot"
|
||||||
: "Empty plot";
|
: "Empty plot";
|
||||||
|
|
||||||
if (
|
AppendGardenPlotFooter(
|
||||||
DisplaySettings
|
Tile,
|
||||||
.ShowGrowthTimers
|
|
||||||
) {
|
|
||||||
Button.appendChild(
|
|
||||||
CreateGardenPlotTimer(
|
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
0
|
0,
|
||||||
)
|
PlotIndex,
|
||||||
|
DisplaySettings,
|
||||||
|
IsPreview
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
if (IsPreview) {
|
if (IsPreview) {
|
||||||
return Button;
|
MainButton.disabled = true;
|
||||||
|
return Tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
SelectedGardenTool ===
|
SelectedGardenTool ===
|
||||||
"Trowel"
|
"Trowel"
|
||||||
) {
|
) {
|
||||||
Button.addEventListener(
|
MainButton.addEventListener(
|
||||||
"click",
|
"click",
|
||||||
() => {
|
() => {
|
||||||
PlantSeed(
|
PlantSeed(
|
||||||
@@ -1517,40 +1626,40 @@ function CreatePlotElement(
|
|||||||
SelectedGardenTool ===
|
SelectedGardenTool ===
|
||||||
"MagicTrowel"
|
"MagicTrowel"
|
||||||
) {
|
) {
|
||||||
Button.classList.add(
|
Tile.classList.add(
|
||||||
"GardenPlotMagicPlant"
|
"GardenPlotMagicPlant"
|
||||||
);
|
);
|
||||||
|
|
||||||
Button.title =
|
MainButton.title =
|
||||||
"Fill empty plots with the selected seed";
|
"Fill empty plots with the selected seed";
|
||||||
|
|
||||||
Button.addEventListener(
|
MainButton.addEventListener(
|
||||||
"click",
|
"click",
|
||||||
PlantManySeeds
|
PlantManySeeds
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
MainButton.disabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Button;
|
return Tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (Plant === undefined) {
|
if (Plant === undefined) {
|
||||||
Visual.textContent = "?";
|
Visual.textContent = "?";
|
||||||
|
|
||||||
if (
|
AppendGardenPlotFooter(
|
||||||
DisplaySettings
|
Tile,
|
||||||
.ShowGrowthTimers
|
|
||||||
) {
|
|
||||||
Button.appendChild(
|
|
||||||
CreateGardenPlotTimer(
|
|
||||||
Plot,
|
Plot,
|
||||||
null,
|
null,
|
||||||
0
|
0,
|
||||||
)
|
PlotIndex,
|
||||||
|
DisplaySettings,
|
||||||
|
IsPreview
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
return Button;
|
MainButton.disabled = true;
|
||||||
|
return Tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1560,7 +1669,7 @@ function CreatePlotElement(
|
|||||||
Plant
|
Plant
|
||||||
);
|
);
|
||||||
|
|
||||||
Button.style.setProperty(
|
Tile.style.setProperty(
|
||||||
"--GrowthProgress",
|
"--GrowthProgress",
|
||||||
`${Progress * 100}%`
|
`${Progress * 100}%`
|
||||||
);
|
);
|
||||||
@@ -1608,25 +1717,24 @@ function CreatePlotElement(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (
|
AppendGardenPlotFooter(
|
||||||
DisplaySettings.ShowGrowthTimers
|
Tile,
|
||||||
) {
|
|
||||||
Button.appendChild(
|
|
||||||
CreateGardenPlotTimer(
|
|
||||||
Plot,
|
Plot,
|
||||||
Plant,
|
Plant,
|
||||||
Progress
|
Progress,
|
||||||
)
|
PlotIndex,
|
||||||
|
DisplaySettings,
|
||||||
|
IsPreview
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (IsPreview) {
|
if (IsPreview) {
|
||||||
Button.title =
|
MainButton.title =
|
||||||
"Future Sight: " +
|
"Future Sight: " +
|
||||||
Plant.Name;
|
Plant.Name;
|
||||||
|
|
||||||
return Button;
|
MainButton.disabled = true;
|
||||||
|
return Tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1634,15 +1742,15 @@ function CreatePlotElement(
|
|||||||
SelectedGardenTool ===
|
SelectedGardenTool ===
|
||||||
"Shovel"
|
"Shovel"
|
||||||
) {
|
) {
|
||||||
Button.classList.add(
|
Tile.classList.add(
|
||||||
"GardenPlotRemove"
|
"GardenPlotRemove"
|
||||||
);
|
);
|
||||||
|
|
||||||
Button.title =
|
MainButton.title =
|
||||||
"Remove " +
|
"Remove " +
|
||||||
Plant.Name;
|
Plant.Name;
|
||||||
|
|
||||||
Button.addEventListener(
|
MainButton.addEventListener(
|
||||||
"click",
|
"click",
|
||||||
() => {
|
() => {
|
||||||
RemovePlant(
|
RemovePlant(
|
||||||
@@ -1651,7 +1759,7 @@ function CreatePlotElement(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return Button;
|
return Tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1660,18 +1768,19 @@ function CreatePlotElement(
|
|||||||
"Fertilizer"
|
"Fertilizer"
|
||||||
) {
|
) {
|
||||||
if (Progress >= 1) {
|
if (Progress >= 1) {
|
||||||
Button.title =
|
MainButton.title =
|
||||||
Plant.Name +
|
Plant.Name +
|
||||||
" is already fully grown";
|
" is already fully grown";
|
||||||
|
|
||||||
return Button;
|
MainButton.disabled = true;
|
||||||
|
return Tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
Button.classList.add(
|
Tile.classList.add(
|
||||||
"GardenPlotFertilize"
|
"GardenPlotFertilize"
|
||||||
);
|
);
|
||||||
|
|
||||||
Button.title =
|
MainButton.title =
|
||||||
"Fertilize " +
|
"Fertilize " +
|
||||||
Plant.Name +
|
Plant.Name +
|
||||||
" (" +
|
" (" +
|
||||||
@@ -1680,7 +1789,7 @@ function CreatePlotElement(
|
|||||||
) +
|
) +
|
||||||
" minutes)";
|
" minutes)";
|
||||||
|
|
||||||
Button.addEventListener(
|
MainButton.addEventListener(
|
||||||
"click",
|
"click",
|
||||||
() => {
|
() => {
|
||||||
FertilizePlant(
|
FertilizePlant(
|
||||||
@@ -1689,7 +1798,7 @@ function CreatePlotElement(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return Button;
|
return Tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1697,7 +1806,7 @@ function CreatePlotElement(
|
|||||||
SelectedGardenTool !==
|
SelectedGardenTool !==
|
||||||
"Trowel"
|
"Trowel"
|
||||||
) {
|
) {
|
||||||
Button.title =
|
MainButton.title =
|
||||||
Plant.Name +
|
Plant.Name +
|
||||||
" - " +
|
" - " +
|
||||||
Math.floor(
|
Math.floor(
|
||||||
@@ -1705,22 +1814,23 @@ function CreatePlotElement(
|
|||||||
) +
|
) +
|
||||||
"% grown";
|
"% grown";
|
||||||
|
|
||||||
return Button;
|
MainButton.disabled = true;
|
||||||
|
return Tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
Progress >= 1
|
Progress >= 1
|
||||||
) {
|
) {
|
||||||
Button.classList.add(
|
Tile.classList.add(
|
||||||
"GardenPlotMature"
|
"GardenPlotMature"
|
||||||
);
|
);
|
||||||
|
|
||||||
Button.title =
|
MainButton.title =
|
||||||
"Harvest " +
|
"Harvest " +
|
||||||
Plant.Name;
|
Plant.Name;
|
||||||
|
|
||||||
Button.addEventListener(
|
MainButton.addEventListener(
|
||||||
"click",
|
"click",
|
||||||
() => {
|
() => {
|
||||||
HarvestPlant(
|
HarvestPlant(
|
||||||
@@ -1729,17 +1839,114 @@ function CreatePlotElement(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
Button.title =
|
MainButton.title =
|
||||||
Plant.Name +
|
Plant.Name +
|
||||||
" - " +
|
" - " +
|
||||||
Math.floor(
|
Math.floor(
|
||||||
Progress * 100
|
Progress * 100
|
||||||
) +
|
) +
|
||||||
"% grown";
|
"% grown";
|
||||||
|
|
||||||
|
MainButton.disabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return Button;
|
return Tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function AppendGardenPlotFooter(
|
||||||
|
Tile,
|
||||||
|
Plot,
|
||||||
|
Plant,
|
||||||
|
Progress,
|
||||||
|
PlotIndex,
|
||||||
|
DisplaySettings,
|
||||||
|
IsPreview
|
||||||
|
) {
|
||||||
|
const ShowTimer =
|
||||||
|
DisplaySettings.ShowGrowthTimers;
|
||||||
|
|
||||||
|
const ShowRotation =
|
||||||
|
Plot !== null &&
|
||||||
|
DisplaySettings.ShowPlotRotation &&
|
||||||
|
!IsPreview;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
Footer.appendChild(
|
||||||
|
CreateGardenPlotTimer(
|
||||||
|
Plot,
|
||||||
|
Plant,
|
||||||
|
Progress
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ShowRotation) {
|
||||||
|
const RotateButton =
|
||||||
|
document.createElement(
|
||||||
|
"button"
|
||||||
|
);
|
||||||
|
|
||||||
|
RotateButton.className =
|
||||||
|
"GardenPlotRotationButton";
|
||||||
|
RotateButton.type = "button";
|
||||||
|
RotateButton.textContent =
|
||||||
|
GetGardenPlotRotationLabel(
|
||||||
|
Plot
|
||||||
|
);
|
||||||
|
RotateButton.title =
|
||||||
|
"Rotate plot clockwise";
|
||||||
|
RotateButton.setAttribute(
|
||||||
|
"aria-label",
|
||||||
|
"Rotate " +
|
||||||
|
(Plant?.Name ?? "plot") +
|
||||||
|
" clockwise"
|
||||||
|
);
|
||||||
|
|
||||||
|
RotateButton.addEventListener(
|
||||||
|
"click",
|
||||||
|
() => {
|
||||||
|
RotateGardenPlot(
|
||||||
|
PlotIndex
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Footer.appendChild(
|
||||||
|
RotateButton
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Tile.appendChild(Footer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1946,7 +2153,8 @@ async function PlantSeed(
|
|||||||
PlotIndex
|
PlotIndex
|
||||||
] = {
|
] = {
|
||||||
Plant: PlantKey,
|
Plant: PlantKey,
|
||||||
PlantedAt: ActionTime
|
PlantedAt: ActionTime,
|
||||||
|
Rotation: GardenPlotDefaultRotation
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -2072,7 +2280,8 @@ async function PlantManySeeds() {
|
|||||||
EmptyPlotIndexes[Index]
|
EmptyPlotIndexes[Index]
|
||||||
] = {
|
] = {
|
||||||
Plant: PlantKey,
|
Plant: PlantKey,
|
||||||
PlantedAt: PlantedAt
|
PlantedAt: PlantedAt,
|
||||||
|
Rotation: GardenPlotDefaultRotation
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2597,8 +2806,17 @@ function GetPlantImages(
|
|||||||
Plot,
|
Plot,
|
||||||
Plant
|
Plant
|
||||||
) {
|
) {
|
||||||
|
const Direction =
|
||||||
|
Plot !== null &&
|
||||||
|
Plant?.DirectionalSprites === true
|
||||||
|
? GetGardenPlotRotation(
|
||||||
|
Plot
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
|
||||||
return GetPlantImageSources(
|
return GetPlantImageSources(
|
||||||
Plant ?? Plot.Plant
|
Plant ?? Plot.Plant,
|
||||||
|
Direction
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -768,6 +768,27 @@ function ApplyMutationResult(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ExistingPlot =
|
||||||
|
SaveData.Garden.Plots[
|
||||||
|
PlotIndex
|
||||||
|
];
|
||||||
|
|
||||||
|
if (
|
||||||
|
NewPlot !== null &&
|
||||||
|
typeof NewPlot === "object" &&
|
||||||
|
typeof NewPlot.Rotation !==
|
||||||
|
"string"
|
||||||
|
) {
|
||||||
|
NewPlot.Rotation =
|
||||||
|
ExistingPlot !== null &&
|
||||||
|
typeof ExistingPlot ===
|
||||||
|
"object" &&
|
||||||
|
typeof ExistingPlot.Rotation ===
|
||||||
|
"string"
|
||||||
|
? ExistingPlot.Rotation
|
||||||
|
: "East";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SaveData.Garden.Plots[
|
SaveData.Garden.Plots[
|
||||||
PlotIndex
|
PlotIndex
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
let Plants = {};
|
let Plants = {};
|
||||||
|
|
||||||
|
const PlantDirectionCodes = {
|
||||||
|
North: "N",
|
||||||
|
East: "E",
|
||||||
|
South: "S",
|
||||||
|
West: "W"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async function FetchPlantsFromApi() {
|
async function FetchPlantsFromApi() {
|
||||||
const Response =
|
const Response =
|
||||||
@@ -50,7 +58,8 @@ async function FetchPlantsFromApi() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function GetPlantImageSources(
|
function GetPlantImageSources(
|
||||||
PlantOrKey
|
PlantOrKey,
|
||||||
|
Direction = null
|
||||||
) {
|
) {
|
||||||
const PlantKey =
|
const PlantKey =
|
||||||
typeof PlantOrKey === "string"
|
typeof PlantOrKey === "string"
|
||||||
@@ -86,10 +95,43 @@ function GetPlantImageSources(
|
|||||||
? Plant.ImageStages
|
? Plant.ImageStages
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
|
const DirectionCode =
|
||||||
|
typeof Direction === "string"
|
||||||
|
? (
|
||||||
|
PlantDirectionCodes[
|
||||||
|
Direction
|
||||||
|
] ??
|
||||||
|
Direction.toUpperCase()
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
const DirectionalStages =
|
||||||
|
Plant?.DirectionalSprites === true &&
|
||||||
|
DirectionCode !== null &&
|
||||||
|
Array.isArray(
|
||||||
|
Plant?.DirectionalImageStages
|
||||||
|
)
|
||||||
|
? Plant.DirectionalImageStages
|
||||||
|
.filter(
|
||||||
|
ImageStage =>
|
||||||
|
String(
|
||||||
|
ImageStage?.Direction ??
|
||||||
|
""
|
||||||
|
).toUpperCase() ===
|
||||||
|
DirectionCode
|
||||||
|
)
|
||||||
|
: [];
|
||||||
|
|
||||||
let HighestStage =
|
let HighestStage =
|
||||||
StaticImages.length;
|
StaticImages.length;
|
||||||
|
|
||||||
for (const ImageStage of ApiStages) {
|
for (
|
||||||
|
const ImageStage
|
||||||
|
of [
|
||||||
|
...ApiStages,
|
||||||
|
...DirectionalStages
|
||||||
|
]
|
||||||
|
) {
|
||||||
const Stage = Number(
|
const Stage = Number(
|
||||||
typeof ImageStage === "object" &&
|
typeof ImageStage === "object" &&
|
||||||
ImageStage !== null
|
ImageStage !== null
|
||||||
@@ -156,9 +198,45 @@ function GetPlantImageSources(
|
|||||||
Query.toString();
|
Query.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Images;
|
for (
|
||||||
|
const ImageStage
|
||||||
|
of DirectionalStages
|
||||||
|
) {
|
||||||
|
const Stage = Number(
|
||||||
|
ImageStage?.Stage
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!Number.isInteger(Stage) ||
|
||||||
|
Stage < 1
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Revision = Number(
|
||||||
|
ImageStage?.Revision ?? 0
|
||||||
|
);
|
||||||
|
|
||||||
|
const Query =
|
||||||
|
new URLSearchParams({
|
||||||
|
PlantId: String(Plant.Id),
|
||||||
|
Stage: String(Stage),
|
||||||
|
Direction: DirectionCode,
|
||||||
|
v: String(
|
||||||
|
Number.isFinite(Revision)
|
||||||
|
? Revision
|
||||||
|
: 0
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
Images[Stage - 1] =
|
||||||
|
ApiUrl +
|
||||||
|
"/PlantImage.php?" +
|
||||||
|
Query.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Images;
|
||||||
|
}
|
||||||
|
|
||||||
function GetPlantMatureImageSource(
|
function GetPlantMatureImageSource(
|
||||||
PlantOrKey
|
PlantOrKey
|
||||||
|
|||||||
@@ -92,6 +92,10 @@ function BindGardenDisplayPreferences() {
|
|||||||
"ToggleGrowthTimersButton",
|
"ToggleGrowthTimersButton",
|
||||||
"ShowGrowthTimers"
|
"ShowGrowthTimers"
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"TogglePlotRotationButton",
|
||||||
|
"ShowPlotRotation"
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"ToggleNextHarvestButton",
|
"ToggleNextHarvestButton",
|
||||||
"ShowNextHarvest"
|
"ShowNextHarvest"
|
||||||
@@ -150,6 +154,7 @@ function BindGardenDisplayPreferences() {
|
|||||||
function RenderGardenDisplayPreferences() {
|
function RenderGardenDisplayPreferences() {
|
||||||
RenderToolSelectionPreferences();
|
RenderToolSelectionPreferences();
|
||||||
RenderPlantInformationPreferences();
|
RenderPlantInformationPreferences();
|
||||||
|
RenderPlotRotationPreference();
|
||||||
RenderGardenOverviewPreferences();
|
RenderGardenOverviewPreferences();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,6 +267,44 @@ function RenderPlantInformationPreferences() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function RenderPlotRotationPreference() {
|
||||||
|
const Button =
|
||||||
|
document.getElementById(
|
||||||
|
"TogglePlotRotationButton"
|
||||||
|
);
|
||||||
|
|
||||||
|
const Message =
|
||||||
|
document.getElementById(
|
||||||
|
"PlotRotationDisplayMessage"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
Button === null ||
|
||||||
|
Message === null
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const IsOwned =
|
||||||
|
HasRotationUpgrade(
|
||||||
|
ProfileSave
|
||||||
|
);
|
||||||
|
|
||||||
|
SetPreferenceButtonState(
|
||||||
|
Button,
|
||||||
|
"Plot rotation",
|
||||||
|
ProfileSave.Preferences
|
||||||
|
.ShowPlotRotation !== false,
|
||||||
|
!IsOwned
|
||||||
|
);
|
||||||
|
|
||||||
|
Message.textContent =
|
||||||
|
IsOwned
|
||||||
|
? "Plot directions can be hidden without changing their saved rotation."
|
||||||
|
: "Unlock Plot rotation in the Shop to use this setting.";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function RenderGardenOverviewPreferences() {
|
function RenderGardenOverviewPreferences() {
|
||||||
const Settings = [
|
const Settings = [
|
||||||
[
|
[
|
||||||
@@ -378,6 +421,10 @@ async function ToggleGardenDisplayPreference(
|
|||||||
"ShowGrowthTimers"
|
"ShowGrowthTimers"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const RotationPreferences = [
|
||||||
|
"ShowPlotRotation"
|
||||||
|
];
|
||||||
|
|
||||||
const GardenOverviewPreferences = [
|
const GardenOverviewPreferences = [
|
||||||
"ShowNextHarvest",
|
"ShowNextHarvest",
|
||||||
"ShowGardenSize",
|
"ShowGardenSize",
|
||||||
@@ -398,6 +445,11 @@ async function ToggleGardenDisplayPreference(
|
|||||||
PreferenceName
|
PreferenceName
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const IsRotationPreference =
|
||||||
|
RotationPreferences.includes(
|
||||||
|
PreferenceName
|
||||||
|
);
|
||||||
|
|
||||||
const IsGardenOverviewPreference =
|
const IsGardenOverviewPreference =
|
||||||
GardenOverviewPreferences.includes(
|
GardenOverviewPreferences.includes(
|
||||||
PreferenceName
|
PreferenceName
|
||||||
@@ -407,6 +459,7 @@ async function ToggleGardenDisplayPreference(
|
|||||||
if (
|
if (
|
||||||
!IsToolSelectionPreference &&
|
!IsToolSelectionPreference &&
|
||||||
!IsPlantInformationPreference &&
|
!IsPlantInformationPreference &&
|
||||||
|
!IsRotationPreference &&
|
||||||
!IsGardenOverviewPreference
|
!IsGardenOverviewPreference
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
@@ -421,6 +474,15 @@ async function ToggleGardenDisplayPreference(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
IsRotationPreference &&
|
||||||
|
!HasRotationUpgrade(
|
||||||
|
ProfileSave
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
IsGardenOverviewPreference &&
|
IsGardenOverviewPreference &&
|
||||||
!HasGardenOverviewUpgrade(
|
!HasGardenOverviewUpgrade(
|
||||||
|
|||||||
+26
-3
@@ -15,7 +15,7 @@ const MaximumGardenNameLength = 32;
|
|||||||
const StartingGardenWidth = 4;
|
const StartingGardenWidth = 4;
|
||||||
const StartingGardenHeight = 4;
|
const StartingGardenHeight = 4;
|
||||||
|
|
||||||
const CurrentSaveVersion = 6;
|
const CurrentSaveVersion = 7;
|
||||||
|
|
||||||
|
|
||||||
function CreateSimulationRandomState() {
|
function CreateSimulationRandomState() {
|
||||||
@@ -274,6 +274,20 @@ function NormalizeGardenData(
|
|||||||
Date.now()
|
Date.now()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const ValidRotations = [
|
||||||
|
"North",
|
||||||
|
"East",
|
||||||
|
"South",
|
||||||
|
"West"
|
||||||
|
];
|
||||||
|
|
||||||
|
Plot.Rotation =
|
||||||
|
ValidRotations.includes(
|
||||||
|
Plot.Rotation
|
||||||
|
)
|
||||||
|
? Plot.Rotation
|
||||||
|
: "East";
|
||||||
|
|
||||||
delete Plot.VisualVariant;
|
delete Plot.VisualVariant;
|
||||||
delete Plot.AddedTags;
|
delete Plot.AddedTags;
|
||||||
}
|
}
|
||||||
@@ -571,7 +585,8 @@ function CreateNewSave() {
|
|||||||
GardenOverview: false,
|
GardenOverview: false,
|
||||||
GardenEconomy: false,
|
GardenEconomy: false,
|
||||||
MutationHints: false,
|
MutationHints: false,
|
||||||
MutationHintsLevel: 0
|
MutationHintsLevel: 0,
|
||||||
|
Rotation: false
|
||||||
},
|
},
|
||||||
|
|
||||||
Preferences: {
|
Preferences: {
|
||||||
@@ -584,7 +599,8 @@ function CreateNewSave() {
|
|||||||
ShowGrowingPlots: true,
|
ShowGrowingPlots: true,
|
||||||
ShowReadyPlots: true,
|
ShowReadyPlots: true,
|
||||||
SelectQuickBoughtPlant: true,
|
SelectQuickBoughtPlant: true,
|
||||||
SelectTrowelWithInventoryPlant: true
|
SelectTrowelWithInventoryPlant: true,
|
||||||
|
ShowPlotRotation: true
|
||||||
},
|
},
|
||||||
|
|
||||||
Gardens: [
|
Gardens: [
|
||||||
@@ -831,6 +847,9 @@ function NormalizeSaveData(
|
|||||||
SaveData.Upgrades.MutationHints ===
|
SaveData.Upgrades.MutationHints ===
|
||||||
true;
|
true;
|
||||||
|
|
||||||
|
SaveData.Upgrades.Rotation =
|
||||||
|
SaveData.Upgrades.Rotation === true;
|
||||||
|
|
||||||
SaveData.Upgrades.MutationHintsLevel =
|
SaveData.Upgrades.MutationHintsLevel =
|
||||||
Math.max(
|
Math.max(
|
||||||
0,
|
0,
|
||||||
@@ -888,6 +907,10 @@ function NormalizeSaveData(
|
|||||||
SaveData.Preferences.SelectTrowelWithInventoryPlant !==
|
SaveData.Preferences.SelectTrowelWithInventoryPlant !==
|
||||||
false;
|
false;
|
||||||
|
|
||||||
|
SaveData.Preferences.ShowPlotRotation =
|
||||||
|
SaveData.Preferences.ShowPlotRotation !==
|
||||||
|
false;
|
||||||
|
|
||||||
|
|
||||||
const LegacyGarden =
|
const LegacyGarden =
|
||||||
SaveData.Garden ??
|
SaveData.Garden ??
|
||||||
|
|||||||
@@ -1114,6 +1114,7 @@ function RenderGardenUpgrades() {
|
|||||||
"Row"
|
"Row"
|
||||||
),
|
),
|
||||||
CreateNewGardenCard(),
|
CreateNewGardenCard(),
|
||||||
|
CreateRotationUpgradeCard(),
|
||||||
CreatePlantInformationUpgradeCard(),
|
CreatePlantInformationUpgradeCard(),
|
||||||
CreateGardenOverviewUpgradeCard(),
|
CreateGardenOverviewUpgradeCard(),
|
||||||
CreateGardenEconomyUpgradeCard(),
|
CreateGardenEconomyUpgradeCard(),
|
||||||
@@ -1377,6 +1378,117 @@ function CreateNewGardenCard() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function CreateRotationUpgradeCard() {
|
||||||
|
const Cost =
|
||||||
|
GetRotationUpgradeCost();
|
||||||
|
|
||||||
|
const IsOwned =
|
||||||
|
HasRotationUpgrade(
|
||||||
|
ShopSave
|
||||||
|
);
|
||||||
|
|
||||||
|
const Card =
|
||||||
|
document.createElement(
|
||||||
|
"article"
|
||||||
|
);
|
||||||
|
|
||||||
|
Card.className =
|
||||||
|
"Panel ShopItem";
|
||||||
|
|
||||||
|
const Header =
|
||||||
|
document.createElement(
|
||||||
|
"div"
|
||||||
|
);
|
||||||
|
|
||||||
|
Header.className =
|
||||||
|
"PanelHeader PanelHeaderInset ShopItemHeader" +
|
||||||
|
(
|
||||||
|
IsOwned
|
||||||
|
? " ShopItemHeaderOwned"
|
||||||
|
: ""
|
||||||
|
);
|
||||||
|
|
||||||
|
const Name =
|
||||||
|
document.createElement(
|
||||||
|
"h3"
|
||||||
|
);
|
||||||
|
|
||||||
|
Name.textContent =
|
||||||
|
"Plot rotation";
|
||||||
|
|
||||||
|
Header.appendChild(Name);
|
||||||
|
|
||||||
|
const Description =
|
||||||
|
document.createElement(
|
||||||
|
"p"
|
||||||
|
);
|
||||||
|
|
||||||
|
Description.textContent =
|
||||||
|
"Rotate planted plots clockwise. Direction is stored per plot and can be shown beside the plot timer.";
|
||||||
|
|
||||||
|
const Details =
|
||||||
|
document.createElement(
|
||||||
|
"div"
|
||||||
|
);
|
||||||
|
|
||||||
|
Details.className =
|
||||||
|
"ShopItemDetails";
|
||||||
|
|
||||||
|
Details.append(
|
||||||
|
CreateShopStat(
|
||||||
|
"Current",
|
||||||
|
IsOwned
|
||||||
|
? "Rotation unlocked"
|
||||||
|
: "Rotation locked"
|
||||||
|
),
|
||||||
|
CreateShopStat(
|
||||||
|
"Next",
|
||||||
|
IsOwned
|
||||||
|
? "Purchased"
|
||||||
|
: "Rotation controls"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const BuyButton =
|
||||||
|
document.createElement(
|
||||||
|
"button"
|
||||||
|
);
|
||||||
|
|
||||||
|
BuyButton.className =
|
||||||
|
"ActionButton ShopBuyButton";
|
||||||
|
BuyButton.type = "button";
|
||||||
|
|
||||||
|
if (IsOwned) {
|
||||||
|
BuyButton.textContent =
|
||||||
|
"Purchased";
|
||||||
|
BuyButton.disabled = true;
|
||||||
|
} else {
|
||||||
|
BuyButton.textContent =
|
||||||
|
"Buy - " +
|
||||||
|
Cost.toLocaleString() +
|
||||||
|
" Dew";
|
||||||
|
|
||||||
|
BuyButton.disabled =
|
||||||
|
ShopSave.Currency.Dew < Cost ||
|
||||||
|
ShopPurchasePending;
|
||||||
|
|
||||||
|
BuyButton.addEventListener(
|
||||||
|
"click",
|
||||||
|
BuyRotationUpgrade
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Card.append(
|
||||||
|
Header,
|
||||||
|
Description,
|
||||||
|
Details,
|
||||||
|
BuyButton
|
||||||
|
);
|
||||||
|
|
||||||
|
return Card;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function CreatePlantInformationUpgradeCard() {
|
function CreatePlantInformationUpgradeCard() {
|
||||||
const Cost =
|
const Cost =
|
||||||
GetPlantInformationUpgradeCost();
|
GetPlantInformationUpgradeCost();
|
||||||
@@ -2854,6 +2966,55 @@ async function BuyNewGarden() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function BuyRotationUpgrade() {
|
||||||
|
if (
|
||||||
|
ShopPurchasePending ||
|
||||||
|
HasRotationUpgrade(
|
||||||
|
ShopSave
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Cost =
|
||||||
|
GetRotationUpgradeCost();
|
||||||
|
|
||||||
|
if (ShopSave.Currency.Dew < Cost) {
|
||||||
|
SetShopMessage(
|
||||||
|
"You don't have enough Dew for Plot rotation."
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShopPurchasePending = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
ShopSave.Currency.Dew -= Cost;
|
||||||
|
ShopSave.Statistics.CurrencySpent.Dew +=
|
||||||
|
Cost;
|
||||||
|
|
||||||
|
UnlockRotation(
|
||||||
|
ShopSave
|
||||||
|
);
|
||||||
|
|
||||||
|
SetShopMessage(
|
||||||
|
"Bought Plot rotation for " +
|
||||||
|
Cost.toLocaleString() +
|
||||||
|
" Dew. Rotation controls are now visible on planted plots."
|
||||||
|
);
|
||||||
|
|
||||||
|
RenderShop();
|
||||||
|
|
||||||
|
await SaveGame(
|
||||||
|
ShopSave
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
ShopPurchasePending = false;
|
||||||
|
RenderShop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async function BuyPlantInformationUpgrade() {
|
async function BuyPlantInformationUpgrade() {
|
||||||
if (
|
if (
|
||||||
ShopPurchasePending ||
|
ShopPurchasePending ||
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ const MutationHintsUnlockCost = 1500;
|
|||||||
const MutationHintsUpgradeCostMultiplier = 2;
|
const MutationHintsUpgradeCostMultiplier = 2;
|
||||||
const MutationHintsMaximumLevel = 1;
|
const MutationHintsMaximumLevel = 1;
|
||||||
const MutationHintsMaximumVisible = 10;
|
const MutationHintsMaximumVisible = 10;
|
||||||
|
const RotationUnlockCost = 1200;
|
||||||
const NewGardenBaseCost = 4000;
|
const NewGardenBaseCost = 4000;
|
||||||
const NewGardenCostMultiplier = 1.5;
|
const NewGardenCostMultiplier = 1.5;
|
||||||
|
|
||||||
@@ -175,6 +176,34 @@ function AddNewGarden(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function HasRotationUpgrade(
|
||||||
|
SaveData
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
SaveData
|
||||||
|
?.Upgrades
|
||||||
|
?.Rotation === true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function GetRotationUpgradeCost() {
|
||||||
|
return RotationUnlockCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function UnlockRotation(
|
||||||
|
SaveData
|
||||||
|
) {
|
||||||
|
SaveData.Upgrades ??= {};
|
||||||
|
SaveData.Preferences ??= {};
|
||||||
|
|
||||||
|
SaveData.Upgrades.Rotation = true;
|
||||||
|
SaveData.Preferences.ShowPlotRotation =
|
||||||
|
true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function HasPlantInformationUpgrade(
|
function HasPlantInformationUpgrade(
|
||||||
SaveData
|
SaveData
|
||||||
) {
|
) {
|
||||||
|
|||||||
+74
-8
@@ -634,10 +634,30 @@ input, button, textarea, select {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.GardenPlotWithName,
|
.GardenPlotWithName,
|
||||||
.GardenPlotWithTimer {
|
.GardenPlotWithFooter {
|
||||||
aspect-ratio: auto;
|
aspect-ratio: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.GardenPlotMain {
|
||||||
|
display: grid;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
cursor: inherit;
|
||||||
|
color: inherit;
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
font: inherit;
|
||||||
|
appearance: none;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.GardenPlotMain:disabled {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
.GardenPlotVisual {
|
.GardenPlotVisual {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -650,7 +670,8 @@ input, button, textarea, select {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.GardenPlotName,
|
.GardenPlotName,
|
||||||
.GardenPlotTimer {
|
.GardenPlotTimer,
|
||||||
|
.GardenPlotRotationButton {
|
||||||
display: flex;
|
display: flex;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
min-height: 1.5rem;
|
min-height: 1.5rem;
|
||||||
@@ -663,6 +684,10 @@ input, button, textarea, select {
|
|||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.GardenPlotName,
|
||||||
|
.GardenPlotTimer {
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
@@ -671,10 +696,41 @@ input, button, textarea, select {
|
|||||||
border-bottom: 2px solid var(--Surface2);
|
border-bottom: 2px solid var(--Surface2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.GardenPlotTimer {
|
.GardenPlotFooter {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
min-width: 0;
|
||||||
|
background-color: var(--Mantle);
|
||||||
border-top: 2px solid var(--Surface2);
|
border-top: 2px solid var(--Surface2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.GardenPlotFooterSplit {
|
||||||
|
grid-template-columns: minmax(0, 1fr) auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.GardenPlotRotationButton {
|
||||||
|
padding-inline: 0.45rem;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.GardenPlotFooterSplit .GardenPlotRotationButton {
|
||||||
|
border-left: 2px solid var(--Surface2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.GardenPlotRotationButton:hover {
|
||||||
|
color: var(--Sky);
|
||||||
|
background-color: var(--Surface0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.GardenPlotRotationButton:focus-visible,
|
||||||
|
.GardenPlotMain:focus-visible {
|
||||||
|
outline: 3px solid var(--Yellow);
|
||||||
|
outline-offset: -3px;
|
||||||
|
}
|
||||||
|
|
||||||
.GardenPlotMature .GardenPlotTimer {
|
.GardenPlotMature .GardenPlotTimer {
|
||||||
color: var(--Green);
|
color: var(--Green);
|
||||||
}
|
}
|
||||||
@@ -686,11 +742,6 @@ input, button, textarea, select {
|
|||||||
box-shadow: 2px 2px 0 var(--Crust);
|
box-shadow: 2px 2px 0 var(--Crust);
|
||||||
}
|
}
|
||||||
|
|
||||||
.GardenPlot:focus-visible {
|
|
||||||
outline: 3px solid var(--Yellow);
|
|
||||||
outline-offset: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.GardenPlotEmpty {
|
.GardenPlotEmpty {
|
||||||
--TileBackground: var(--Mantle);
|
--TileBackground: var(--Mantle);
|
||||||
}
|
}
|
||||||
@@ -2304,6 +2355,17 @@ input, button, textarea, select {
|
|||||||
flex: 1 1 18rem;
|
flex: 1 1 18rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.AdminPlantDirectionalImageUpload {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat( 2, minmax(0, 1fr) );
|
||||||
|
gap: 0.75rem;
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.AdminPlantDirectionalImageUpload .AdminEditorField {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.AdminPlantImageNote {
|
.AdminPlantImageNote {
|
||||||
color: var(--Overlay2);
|
color: var(--Overlay2);
|
||||||
}
|
}
|
||||||
@@ -2350,6 +2412,10 @@ input, button, textarea, select {
|
|||||||
grid-template-columns: auto minmax(0, 1fr);
|
grid-template-columns: auto minmax(0, 1fr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.AdminPlantDirectionalImageUpload {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
.AdminPlantImageRemoveButton {
|
.AdminPlantImageRemoveButton {
|
||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
Reference in new issue
Block a user