Added better info display upgrade.

This commit is contained in:
sarah committed 2026-09-02 23:09:31 +02:00
1 parent 11be2c8a52
commit 64807f3c7a
9 files changed
+855 -96

No files matched your search

+58 -5
View File
@@ -18,11 +18,64 @@ $PageSection = "Garden";
<h1>Garden</h1> <h1>Garden</h1>
<div class="StatusPanel"> <div class="StatusPanel">
<strong>Dew:</strong> <div class="GardenStatusLine">
<span id="DewAmount">0</span> <strong>Dew:</strong>
<br> <span id="DewAmount">0</span>
<strong>Next harvest:</strong> </div>
<span id="NextHarvest">Nothing planted</span>
<div
id="NextHarvestLine"
class="GardenStatusLine"
>
<strong>Next harvest:</strong>
<span id="NextHarvest">Nothing planted</span>
</div>
<div
id="GardenOverviewDetails"
class="GardenOverviewDetails"
hidden
>
<div
id="GardenSizeOverviewLine"
class="GardenStatusLine"
>
<strong>Garden size:</strong>
<span id="GardenSizeOverview">3×3 (9)</span>
</div>
<div
id="EmptyPlotsOverviewLine"
class="GardenStatusLine"
>
<strong>Empty plots:</strong>
<span id="EmptyPlotsOverview">9/9</span>
</div>
<div
id="PlantedPlotsOverviewLine"
class="GardenStatusLine"
>
<strong>Planted plots:</strong>
<span id="PlantedPlotsOverview">0/9</span>
</div>
<div
id="GrowingPlotsOverviewLine"
class="GardenStatusLine"
>
<strong>Growing:</strong>
<span id="GrowingPlotsOverview">0/9</span>
</div>
<div
id="ReadyPlotsOverviewLine"
class="GardenStatusLine"
>
<strong>Ready to harvest:</strong>
<span id="ReadyPlotsOverview">0/9</span>
</div>
</div>
</div> </div>
<div class="GardenLayout"> <div class="GardenLayout">
+61
View File
@@ -105,6 +105,8 @@ $PageTitle = "Profile";
> >
<h2>Garden display</h2> <h2>Garden display</h2>
<h3>Plant information</h3>
<p> <p>
Choose which Plant information details are Choose which Plant information details are
shown on Garden plots. shown on Garden plots.
@@ -133,6 +135,65 @@ $PageTitle = "Profile";
Unlock Plant information in the Shop Unlock Plant information in the Shop
to use these settings. to use these settings.
</p> </p>
<h3>Garden overview</h3>
<p>
Choose which Garden overview lines are
shown in the Garden status box.
</p>
<div class="ProfileButtonRow">
<button
id="ToggleNextHarvestButton"
type="button"
>
Next harvest: Locked
</button>
<button
id="ToggleGardenSizeButton"
type="button"
>
Garden size: Locked
</button>
<button
id="ToggleEmptyPlotsButton"
type="button"
>
Empty plots: Locked
</button>
<button
id="TogglePlantedPlotsButton"
type="button"
>
Planted plots: Locked
</button>
<button
id="ToggleGrowingPlotsButton"
type="button"
>
Growing: Locked
</button>
<button
id="ToggleReadyPlotsButton"
type="button"
>
Ready to harvest: Locked
</button>
</div>
<p
id="GardenOverviewDisplayMessage"
class="ProfileMessage"
>
Unlock Garden overview in the Shop
to use these settings.
</p>
</section> </section>
<section <section
+2 -2
View File
@@ -47,8 +47,8 @@ $PageSection = "Shop";
<h2>Permanent upgrades</h2> <h2>Permanent upgrades</h2>
<p> <p>
Expand your Garden one row or column at a time. Permanently expand your Garden or unlock
Existing plants keep their positions. extra information and quality-of-life features.
</p> </p>
<div <div
+236 -25
View File
@@ -59,6 +59,7 @@ function RenderGame() {
RenderTools(); RenderTools();
RenderGarden(); RenderGarden();
RenderNextHarvest(); RenderNextHarvest();
RenderGardenOverview();
} }
@@ -940,6 +941,7 @@ async function RemovePlant(
async function GardenTick() { async function GardenTick() {
RenderGarden(); RenderGarden();
RenderNextHarvest(); RenderNextHarvest();
RenderGardenOverview();
if (MutationCheckPending) { if (MutationCheckPending) {
@@ -1113,8 +1115,8 @@ function SetGardenMessage(
} }
function GetNextHarvestTime() { function GetNextHarvestInfo() {
let NextHarvestTime = null; let NextHarvest = null;
for ( for (
@@ -1138,46 +1140,63 @@ function GetNextHarvestTime() {
Plot.PlantedAt + Plot.PlantedAt +
Plant.GrowthTime; Plant.GrowthTime;
if ( if (
HarvestTime <= NextHarvest === null ||
Date.now()
) {
return Date.now();
}
if (
NextHarvestTime === null ||
HarvestTime < HarvestTime <
NextHarvestTime NextHarvest.Time
) { ) {
NextHarvestTime = NextHarvest = {
HarvestTime; Time: HarvestTime,
Plant
};
} }
} }
return NextHarvestTime; return NextHarvest;
} }
function RenderNextHarvest() { function RenderNextHarvest() {
const Line =
document.getElementById(
"NextHarvestLine"
);
const Element = const Element =
document.getElementById( document.getElementById(
"NextHarvest" "NextHarvest"
); );
if (Element === null) { if (
Line === null ||
Element === null
) {
return; return;
} }
const HarvestTime = const HasOverview =
GetNextHarvestTime(); HasGardenOverviewUpgrade(
GameSave
);
const ShowNextHarvest =
!HasOverview ||
GameSave.Preferences
.ShowNextHarvest !== false;
Line.hidden = !ShowNextHarvest;
if (!ShowNextHarvest) {
return;
}
if (HarvestTime === null) { const Harvest =
GetNextHarvestInfo();
if (Harvest === null) {
Element.textContent = Element.textContent =
"Nothing planted"; "Nothing planted";
@@ -1190,13 +1209,19 @@ function RenderNextHarvest() {
const Remaining = const Remaining =
HarvestTime - Harvest.Time -
Date.now(); Date.now();
const IncludePlantName =
HasOverview;
if (Remaining <= 0) { if (Remaining <= 0) {
Element.textContent = Element.textContent =
"Ready now!"; IncludePlantName
? Harvest.Plant.Name +
" is ready!"
: "Ready now!";
Element.removeAttribute( Element.removeAttribute(
"title" "title"
@@ -1206,18 +1231,24 @@ function RenderNextHarvest() {
} }
Element.textContent = const RemainingText =
FormatRemainingTime( FormatRemainingTime(
Remaining Remaining
); );
Element.textContent =
IncludePlantName
? Harvest.Plant.Name +
" in " +
RemainingText
: RemainingText;
const HarvestDate = const HarvestDate =
new Date( new Date(
HarvestTime Harvest.Time
); );
Element.title = Element.title =
"Ready at " + "Ready at " +
HarvestDate.toLocaleTimeString( HarvestDate.toLocaleTimeString(
@@ -1230,6 +1261,186 @@ function RenderNextHarvest() {
} }
function RenderGardenOverview() {
const Overview =
document.getElementById(
"GardenOverviewDetails"
);
if (Overview === null) {
return;
}
if (
!HasGardenOverviewUpgrade(
GameSave
)
) {
Overview.hidden = true;
return;
}
const TotalPlots =
GameSave.Garden.Width *
GameSave.Garden.Height;
let PlantedPlots = 0;
let GrowingPlots = 0;
let ReadyPlots = 0;
for (
const Plot
of GameSave.Garden.Plots
) {
if (Plot === null) {
continue;
}
PlantedPlots++;
const Plant =
Plants[Plot.Plant];
if (Plant === undefined) {
continue;
}
if (
IsPlantMature(
Plot,
Plant
)
) {
ReadyPlots++;
} else {
GrowingPlots++;
}
}
const EmptyPlots =
Math.max(
0,
TotalPlots -
PlantedPlots
);
const Lines = [
{
LineId:
"GardenSizeOverviewLine",
ValueId:
"GardenSizeOverview",
Preference:
"ShowGardenSize",
Value:
GameSave.Garden.Width +
"×" +
GameSave.Garden.Height +
" (" +
TotalPlots.toLocaleString() +
")"
},
{
LineId:
"EmptyPlotsOverviewLine",
ValueId:
"EmptyPlotsOverview",
Preference:
"ShowEmptyPlots",
Value:
EmptyPlots.toLocaleString() +
"/" +
TotalPlots.toLocaleString()
},
{
LineId:
"PlantedPlotsOverviewLine",
ValueId:
"PlantedPlotsOverview",
Preference:
"ShowPlantedPlots",
Value:
PlantedPlots.toLocaleString() +
"/" +
TotalPlots.toLocaleString()
},
{
LineId:
"GrowingPlotsOverviewLine",
ValueId:
"GrowingPlotsOverview",
Preference:
"ShowGrowingPlots",
Value:
GrowingPlots.toLocaleString() +
"/" +
TotalPlots.toLocaleString()
},
{
LineId:
"ReadyPlotsOverviewLine",
ValueId:
"ReadyPlotsOverview",
Preference:
"ShowReadyPlots",
Value:
ReadyPlots.toLocaleString() +
"/" +
TotalPlots.toLocaleString()
}
];
let VisibleLines = 0;
for (
const Line
of Lines
) {
const LineElement =
document.getElementById(
Line.LineId
);
const ValueElement =
document.getElementById(
Line.ValueId
);
if (
LineElement === null ||
ValueElement === null
) {
continue;
}
const IsVisible =
GameSave.Preferences[
Line.Preference
] !== false;
LineElement.hidden =
!IsVisible;
ValueElement.textContent =
Line.Value;
if (IsVisible) {
VisibleLines++;
}
}
Overview.hidden =
VisibleLines === 0;
}
function FormatRemainingTime( function FormatRemainingTime(
Milliseconds Milliseconds
) { ) {
+226 -61
View File
@@ -75,45 +75,77 @@ async function StartProfile() {
function BindGardenDisplayPreferences() { function BindGardenDisplayPreferences() {
const PlantNamesButton = const PreferenceButtons = [
document.getElementById( [
"TogglePlantNamesButton" "TogglePlantNamesButton",
); "ShowPlantNames"
],
[
"ToggleGrowthTimersButton",
"ShowGrowthTimers"
],
[
"ToggleNextHarvestButton",
"ShowNextHarvest"
],
[
"ToggleGardenSizeButton",
"ShowGardenSize"
],
[
"ToggleEmptyPlotsButton",
"ShowEmptyPlots"
],
[
"TogglePlantedPlotsButton",
"ShowPlantedPlots"
],
[
"ToggleGrowingPlotsButton",
"ShowGrowingPlots"
],
[
"ToggleReadyPlotsButton",
"ShowReadyPlots"
]
];
const GrowthTimersButton =
document.getElementById(
"ToggleGrowthTimersButton"
);
if ( for (
PlantNamesButton === null || const [
GrowthTimersButton === null ButtonId,
PreferenceName
]
of PreferenceButtons
) { ) {
return; const Button =
document.getElementById(
ButtonId
);
if (Button === null) {
continue;
}
Button.addEventListener(
"click",
() => {
ToggleGardenDisplayPreference(
PreferenceName
);
}
);
} }
PlantNamesButton.addEventListener(
"click",
() => {
ToggleGardenDisplayPreference(
"ShowPlantNames"
);
}
);
GrowthTimersButton.addEventListener(
"click",
() => {
ToggleGardenDisplayPreference(
"ShowGrowthTimers"
);
}
);
} }
function RenderGardenDisplayPreferences() { function RenderGardenDisplayPreferences() {
RenderPlantInformationPreferences();
RenderGardenOverviewPreferences();
}
function RenderPlantInformationPreferences() {
const PlantNamesButton = const PlantNamesButton =
document.getElementById( document.getElementById(
"TogglePlantNamesButton" "TogglePlantNamesButton"
@@ -144,14 +176,19 @@ function RenderGardenDisplayPreferences() {
); );
if (!IsOwned) { if (!IsOwned) {
PlantNamesButton.textContent = SetPreferenceButtonState(
"Plant names: Locked"; PlantNamesButton,
"Plant names",
false,
true
);
GrowthTimersButton.textContent = SetPreferenceButtonState(
"Growth timers: Locked"; GrowthTimersButton,
"Growth timers",
PlantNamesButton.disabled = true; false,
GrowthTimersButton.disabled = true; true
);
Message.textContent = Message.textContent =
"Unlock Plant information in the Shop to use these settings."; "Unlock Plant information in the Shop to use these settings.";
@@ -160,38 +197,166 @@ function RenderGardenDisplayPreferences() {
} }
const ShowPlantNames = SetPreferenceButtonState(
PlantNamesButton,
"Plant names",
ProfileSave.Preferences ProfileSave.Preferences
.ShowPlantNames !== false; .ShowPlantNames !== false
);
const ShowGrowthTimers = SetPreferenceButtonState(
GrowthTimersButton,
"Growth timers",
ProfileSave.Preferences ProfileSave.Preferences
.ShowGrowthTimers !== false; .ShowGrowthTimers !== false
);
PlantNamesButton.disabled = false;
GrowthTimersButton.disabled = false;
PlantNamesButton.textContent =
"Plant names: " +
(ShowPlantNames
? "On"
: "Off");
GrowthTimersButton.textContent =
"Growth timers: " +
(ShowGrowthTimers
? "On"
: "Off");
Message.textContent = Message.textContent =
"Plant names and growth timers can be changed independently."; "Plant names and growth timers can be changed independently.";
} }
function RenderGardenOverviewPreferences() {
const Settings = [
[
"ToggleNextHarvestButton",
"Next harvest",
"ShowNextHarvest"
],
[
"ToggleGardenSizeButton",
"Garden size",
"ShowGardenSize"
],
[
"ToggleEmptyPlotsButton",
"Empty plots",
"ShowEmptyPlots"
],
[
"TogglePlantedPlotsButton",
"Planted plots",
"ShowPlantedPlots"
],
[
"ToggleGrowingPlotsButton",
"Growing",
"ShowGrowingPlots"
],
[
"ToggleReadyPlotsButton",
"Ready to harvest",
"ShowReadyPlots"
]
];
const Message =
document.getElementById(
"GardenOverviewDisplayMessage"
);
if (Message === null) {
return;
}
const IsOwned =
HasGardenOverviewUpgrade(
ProfileSave
);
for (
const [
ButtonId,
Label,
PreferenceName
]
of Settings
) {
const Button =
document.getElementById(
ButtonId
);
if (Button === null) {
continue;
}
SetPreferenceButtonState(
Button,
Label,
ProfileSave.Preferences[
PreferenceName
] !== false,
!IsOwned
);
}
Message.textContent =
IsOwned
? "Every Garden overview line can be changed independently."
: "Unlock Garden overview in the Shop to use these settings.";
}
function SetPreferenceButtonState(
Button,
Label,
IsEnabled,
IsLocked = false
) {
Button.disabled = IsLocked;
Button.textContent =
Label +
": " +
(IsLocked
? "Locked"
: IsEnabled
? "On"
: "Off");
}
async function ToggleGardenDisplayPreference( async function ToggleGardenDisplayPreference(
PreferenceName PreferenceName
) { ) {
const PlantInformationPreferences = [
"ShowPlantNames",
"ShowGrowthTimers"
];
const GardenOverviewPreferences = [
"ShowNextHarvest",
"ShowGardenSize",
"ShowEmptyPlots",
"ShowPlantedPlots",
"ShowGrowingPlots",
"ShowReadyPlots"
];
const IsPlantInformationPreference =
PlantInformationPreferences.includes(
PreferenceName
);
const IsGardenOverviewPreference =
GardenOverviewPreferences.includes(
PreferenceName
);
if ( if (
!IsPlantInformationPreference &&
!IsGardenOverviewPreference
) {
return;
}
if (
IsPlantInformationPreference &&
!HasPlantInformationUpgrade( !HasPlantInformationUpgrade(
ProfileSave ProfileSave
) )
@@ -200,10 +365,10 @@ async function ToggleGardenDisplayPreference(
} }
if ( if (
PreferenceName !== IsGardenOverviewPreference &&
"ShowPlantNames" && !HasGardenOverviewUpgrade(
PreferenceName !== ProfileSave
"ShowGrowthTimers" )
) { ) {
return; return;
} }
+37 -2
View File
@@ -67,12 +67,19 @@ function CreateNewSave() {
Upgrades: { Upgrades: {
PlotSize: 0, PlotSize: 0,
PlantInformation: false PlantInformation: false,
GardenOverview: false
}, },
Preferences: { Preferences: {
ShowPlantNames: true, ShowPlantNames: true,
ShowGrowthTimers: true ShowGrowthTimers: true,
ShowNextHarvest: true,
ShowGardenSize: true,
ShowEmptyPlots: true,
ShowPlantedPlots: true,
ShowGrowingPlots: true,
ShowReadyPlots: true
}, },
Garden: { Garden: {
@@ -249,6 +256,10 @@ function NormalizeSaveData(
SaveData.Upgrades.PlantInformation === SaveData.Upgrades.PlantInformation ===
true; true;
SaveData.Upgrades.GardenOverview =
SaveData.Upgrades.GardenOverview ===
true;
SaveData.Preferences ??= {}; SaveData.Preferences ??= {};
@@ -260,6 +271,30 @@ function NormalizeSaveData(
SaveData.Preferences.ShowGrowthTimers !== SaveData.Preferences.ShowGrowthTimers !==
false; false;
SaveData.Preferences.ShowNextHarvest =
SaveData.Preferences.ShowNextHarvest !==
false;
SaveData.Preferences.ShowGardenSize =
SaveData.Preferences.ShowGardenSize !==
false;
SaveData.Preferences.ShowEmptyPlots =
SaveData.Preferences.ShowEmptyPlots !==
false;
SaveData.Preferences.ShowPlantedPlots =
SaveData.Preferences.ShowPlantedPlots !==
false;
SaveData.Preferences.ShowGrowingPlots =
SaveData.Preferences.ShowGrowingPlots !==
false;
SaveData.Preferences.ShowReadyPlots =
SaveData.Preferences.ShowReadyPlots !==
false;
SaveData.Garden ??= { SaveData.Garden ??= {
Width: 3, Width: 3,
+176 -1
View File
@@ -124,7 +124,8 @@ function RenderGardenUpgrades() {
CreateGardenExpansionCard( CreateGardenExpansionCard(
"Row" "Row"
), ),
CreatePlantInformationUpgradeCard() CreatePlantInformationUpgradeCard(),
CreateGardenOverviewUpgradeCard()
); );
} }
@@ -387,6 +388,122 @@ function CreatePlantInformationUpgradeCard() {
} }
function CreateGardenOverviewUpgradeCard() {
const Cost =
GetGardenOverviewUpgradeCost();
const IsOwned =
HasGardenOverviewUpgrade(
ShopSave
);
const Card =
document.createElement(
"article"
);
Card.className =
"Panel ShopItem";
const Header =
document.createElement(
"div"
);
Header.className =
"ShopItemHeader";
const Name =
document.createElement(
"h3"
);
Name.textContent =
"Garden overview";
Header.appendChild(Name);
const Description =
document.createElement(
"p"
);
Description.textContent =
"Expand the Garden status box with detailed plot counts and the name of the next plant ready to harvest. Every overview line can be toggled on/off from the profile page.";
const Details =
document.createElement(
"div"
);
Details.className =
"ShopItemDetails";
Details.append(
CreateShopStat(
"Garden details",
IsOwned
? "Unlocked"
: "Locked"
),
CreateShopStat(
"Profile controls",
IsOwned
? "Unlocked"
: "Locked"
)
);
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",
BuyGardenOverviewUpgrade
);
}
Card.append(
Header,
Description,
Details,
BuyButton
);
return Card;
}
function CreateShopSeedCard( function CreateShopSeedCard(
Plant Plant
) { ) {
@@ -1014,6 +1131,64 @@ async function BuyPlantInformationUpgrade() {
} }
async function BuyGardenOverviewUpgrade() {
if (
ShopPurchasePending ||
HasGardenOverviewUpgrade(
ShopSave
)
) {
return;
}
const Cost =
GetGardenOverviewUpgradeCost();
if (
ShopSave.Currency.Dew <
Cost
) {
SetShopMessage(
"You don't have enough Dew for Garden overview."
);
return;
}
ShopPurchasePending = true;
try {
ShopSave.Currency.Dew -=
Cost;
ShopSave.Statistics.CurrencySpent.Dew +=
Cost;
UnlockGardenOverview(
ShopSave
);
SetShopMessage(
"Bought Garden overview for " +
Cost.toLocaleString() +
" Dew. All overview lines are now visible."
);
RenderShop();
await SaveGame(
ShopSave
);
} finally {
ShopPurchasePending = false;
RenderShop();
}
}
function SetShopMessage( function SetShopMessage(
Message Message
) { ) {
+47
View File
@@ -1,5 +1,6 @@
const GardenExpansionBaseCost = 1000; const GardenExpansionBaseCost = 1000;
const PlantInformationUpgradeCost = 500; const PlantInformationUpgradeCost = 500;
const GardenOverviewUpgradeCost = 1000;
function GetGardenColumnUpgradeCost( function GetGardenColumnUpgradeCost(
@@ -142,3 +143,49 @@ function UnlockPlantInformation(
SaveData.Preferences.ShowGrowthTimers = SaveData.Preferences.ShowGrowthTimers =
true; true;
} }
function HasGardenOverviewUpgrade(
SaveData
) {
return (
SaveData
?.Upgrades
?.GardenOverview ===
true
);
}
function GetGardenOverviewUpgradeCost() {
return GardenOverviewUpgradeCost;
}
function UnlockGardenOverview(
SaveData
) {
SaveData.Upgrades ??= {};
SaveData.Preferences ??= {};
SaveData.Upgrades.GardenOverview =
true;
SaveData.Preferences.ShowNextHarvest =
true;
SaveData.Preferences.ShowGardenSize =
true;
SaveData.Preferences.ShowEmptyPlots =
true;
SaveData.Preferences.ShowPlantedPlots =
true;
SaveData.Preferences.ShowGrowingPlots =
true;
SaveData.Preferences.ShowReadyPlots =
true;
}
+12
View File
@@ -84,6 +84,14 @@ body {
border: 3px solid var(--Surface2); border: 3px solid var(--Surface2);
} }
.GardenOverviewDetails {
margin-top: 0.5rem;
}
.GardenStatusLine + .GardenStatusLine {
margin-top: 0.1rem;
}
.PageMessage { .PageMessage {
margin-top: 1rem; margin-top: 1rem;
margin-bottom: 0; margin-bottom: 0;
@@ -623,6 +631,10 @@ input, button, textarea, select {
margin-bottom: 1rem; margin-bottom: 1rem;
} }
.ProfileSection h3 {
margin-top: 1.5rem;
}
.ProfileFormRow, .ProfileButtonRow { .ProfileFormRow, .ProfileButtonRow {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;