mirror of
https://git.srhtnin.garden/sarah/srhtnin.github.io.git
synced 2026-10-13 18:38:11 +02:00
3288 lines
58 KiB
JavaScript
3288 lines
58 KiB
JavaScript
let ShopSave;
|
||
let ShopPurchasePending = false;
|
||
let ShopSeedSearchQuery = "";
|
||
let ShopSeedSortMode = "IdAsc";
|
||
|
||
|
||
async function StartShop() {
|
||
try {
|
||
await LoadGameContent();
|
||
} catch (Error) {
|
||
console.error(
|
||
"Couldn't load Shop content:",
|
||
Error
|
||
);
|
||
|
||
SetShopMessage(
|
||
"Couldn't load plant or mutation data."
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
ShopSave = await LoadGame();
|
||
|
||
BindShopSectionToggles();
|
||
BindShopSeedControls();
|
||
RenderShop();
|
||
}
|
||
|
||
|
||
function BindShopSectionToggles() {
|
||
BindShopSectionToggle(
|
||
"ToolsToggle",
|
||
"ToolsContent"
|
||
);
|
||
|
||
BindShopSectionToggle(
|
||
"PermanentUpgradesToggle",
|
||
"PermanentUpgradesContent"
|
||
);
|
||
|
||
BindShopSectionToggle(
|
||
"SeedsToggle",
|
||
"SeedsContent"
|
||
);
|
||
}
|
||
|
||
|
||
function BindShopSectionToggle(
|
||
ToggleId,
|
||
ContentId
|
||
) {
|
||
const Toggle =
|
||
document.getElementById(
|
||
ToggleId
|
||
);
|
||
|
||
const Content =
|
||
document.getElementById(
|
||
ContentId
|
||
);
|
||
|
||
if (
|
||
Toggle === null ||
|
||
Content === null
|
||
) {
|
||
return;
|
||
}
|
||
|
||
Toggle.addEventListener(
|
||
"click",
|
||
() => {
|
||
const IsExpanded =
|
||
Toggle.getAttribute(
|
||
"aria-expanded"
|
||
) === "true";
|
||
|
||
const NewExpanded =
|
||
!IsExpanded;
|
||
|
||
Toggle.setAttribute(
|
||
"aria-expanded",
|
||
String(NewExpanded)
|
||
);
|
||
|
||
Content.hidden =
|
||
!NewExpanded;
|
||
|
||
}
|
||
);
|
||
}
|
||
|
||
|
||
function BindShopSeedControls() {
|
||
const SearchInput =
|
||
document.getElementById(
|
||
"ShopSeedSearchInput"
|
||
);
|
||
|
||
const SortSelect =
|
||
document.getElementById(
|
||
"ShopSeedSortSelect"
|
||
);
|
||
|
||
|
||
if (SearchInput !== null) {
|
||
SearchInput.value =
|
||
ShopSeedSearchQuery;
|
||
|
||
SearchInput.addEventListener(
|
||
"input",
|
||
() => {
|
||
ShopSeedSearchQuery =
|
||
SearchInput.value;
|
||
|
||
RenderShopSeeds();
|
||
}
|
||
);
|
||
}
|
||
|
||
|
||
if (SortSelect !== null) {
|
||
SortSelect.value =
|
||
ShopSeedSortMode;
|
||
|
||
SortSelect.addEventListener(
|
||
"change",
|
||
() => {
|
||
ShopSeedSortMode =
|
||
SortSelect.value;
|
||
|
||
RenderShopSeeds();
|
||
}
|
||
);
|
||
}
|
||
}
|
||
|
||
|
||
function RenderShop() {
|
||
RenderShopCurrency();
|
||
RenderToolShop();
|
||
RenderShopSeeds();
|
||
RenderGardenUpgrades();
|
||
}
|
||
|
||
|
||
function RenderShopCurrency() {
|
||
const DewAmount =
|
||
document.getElementById(
|
||
"ShopDewAmount"
|
||
);
|
||
|
||
if (DewAmount === null) {
|
||
return;
|
||
}
|
||
|
||
DewAmount.textContent =
|
||
ShopSave.Currency.Dew
|
||
.toLocaleString();
|
||
}
|
||
|
||
|
||
function RenderShopSeeds() {
|
||
const SeedList =
|
||
document.getElementById(
|
||
"ShopSeedList"
|
||
);
|
||
|
||
SeedList.replaceChildren();
|
||
|
||
|
||
const AvailablePlants =
|
||
Object.values(Plants)
|
||
.filter(
|
||
Plant =>
|
||
IsPlantAvailableInShop(
|
||
ShopSave,
|
||
Plant
|
||
)
|
||
);
|
||
|
||
const SearchQuery =
|
||
ShopSeedSearchQuery
|
||
.trim()
|
||
.toLocaleLowerCase();
|
||
|
||
const VisiblePlants =
|
||
AvailablePlants
|
||
.filter(
|
||
Plant =>
|
||
DoesShopPlantMatchSearch(
|
||
Plant,
|
||
SearchQuery
|
||
)
|
||
)
|
||
.sort(
|
||
CompareShopPlants
|
||
);
|
||
|
||
|
||
if (AvailablePlants.length === 0) {
|
||
AppendShopSeedEmptyMessage(
|
||
SeedList,
|
||
"No seeds are available yet."
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
if (VisiblePlants.length === 0) {
|
||
AppendShopSeedEmptyMessage(
|
||
SeedList,
|
||
"No seeds match your search."
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
for (
|
||
const Plant
|
||
of VisiblePlants
|
||
) {
|
||
SeedList.appendChild(
|
||
CreateShopSeedCard(
|
||
Plant
|
||
)
|
||
);
|
||
}
|
||
}
|
||
|
||
|
||
function AppendShopSeedEmptyMessage(
|
||
SeedList,
|
||
Message
|
||
) {
|
||
const EmptyMessage =
|
||
document.createElement(
|
||
"p"
|
||
);
|
||
|
||
EmptyMessage.className =
|
||
"ShopEmpty";
|
||
|
||
EmptyMessage.textContent =
|
||
Message;
|
||
|
||
SeedList.appendChild(
|
||
EmptyMessage
|
||
);
|
||
}
|
||
|
||
|
||
function DoesShopPlantMatchSearch(
|
||
Plant,
|
||
SearchQuery
|
||
) {
|
||
if (SearchQuery.length === 0) {
|
||
return true;
|
||
}
|
||
|
||
const SearchParts = [
|
||
Plant.Id,
|
||
Plant.Name,
|
||
Plant.Description,
|
||
...(Array.isArray(Plant.Tags)
|
||
? Plant.Tags
|
||
: [])
|
||
];
|
||
|
||
return SearchParts
|
||
.filter(
|
||
Value =>
|
||
Value !== null &&
|
||
Value !== undefined
|
||
)
|
||
.join(" ")
|
||
.toLocaleLowerCase()
|
||
.includes(
|
||
SearchQuery
|
||
);
|
||
}
|
||
|
||
|
||
function CompareShopPlants(
|
||
A,
|
||
B
|
||
) {
|
||
switch (ShopSeedSortMode) {
|
||
case "NameAsc":
|
||
return CompareShopText(
|
||
A.Name,
|
||
B.Name
|
||
) || A.Id - B.Id;
|
||
|
||
case "PriceAsc":
|
||
return CompareShopNumbers(
|
||
GetPlantShopCost(ShopSave, A.Id),
|
||
GetPlantShopCost(ShopSave, B.Id),
|
||
1
|
||
) || A.Id - B.Id;
|
||
|
||
case "PriceDesc":
|
||
return CompareShopNumbers(
|
||
GetPlantShopCost(ShopSave, A.Id),
|
||
GetPlantShopCost(ShopSave, B.Id),
|
||
-1
|
||
) || A.Id - B.Id;
|
||
|
||
case "GrowthAsc":
|
||
return CompareShopNumbers(
|
||
A.GrowthTime,
|
||
B.GrowthTime,
|
||
1
|
||
) || A.Id - B.Id;
|
||
|
||
case "GrowthDesc":
|
||
return CompareShopNumbers(
|
||
A.GrowthTime,
|
||
B.GrowthTime,
|
||
-1
|
||
) || A.Id - B.Id;
|
||
|
||
case "RewardAsc":
|
||
return CompareShopNumbers(
|
||
GetPlantHarvestReward(ShopSave, A.Id),
|
||
GetPlantHarvestReward(ShopSave, B.Id),
|
||
1
|
||
) || A.Id - B.Id;
|
||
|
||
case "RewardDesc":
|
||
return CompareShopNumbers(
|
||
GetPlantHarvestReward(ShopSave, A.Id),
|
||
GetPlantHarvestReward(ShopSave, B.Id),
|
||
-1
|
||
) || A.Id - B.Id;
|
||
|
||
case "DphAsc":
|
||
return CompareShopNumbers(
|
||
GetPlantDewPerHour(ShopSave, A.Id),
|
||
GetPlantDewPerHour(ShopSave, B.Id),
|
||
1
|
||
) || A.Id - B.Id;
|
||
|
||
case "DphDesc":
|
||
return CompareShopNumbers(
|
||
GetPlantDewPerHour(ShopSave, A.Id),
|
||
GetPlantDewPerHour(ShopSave, B.Id),
|
||
-1
|
||
) || A.Id - B.Id;
|
||
|
||
case "InventoryAsc":
|
||
return CompareShopNumbers(
|
||
GetSeedCount(ShopSave, A.Id),
|
||
GetSeedCount(ShopSave, B.Id),
|
||
1
|
||
) || A.Id - B.Id;
|
||
|
||
case "InventoryDesc":
|
||
return CompareShopNumbers(
|
||
GetSeedCount(ShopSave, A.Id),
|
||
GetSeedCount(ShopSave, B.Id),
|
||
-1
|
||
) || A.Id - B.Id;
|
||
|
||
case "IdAsc":
|
||
default:
|
||
return A.Id - B.Id;
|
||
}
|
||
}
|
||
|
||
|
||
function CompareShopText(
|
||
A,
|
||
B
|
||
) {
|
||
return String(A ?? "")
|
||
.localeCompare(
|
||
String(B ?? ""),
|
||
undefined,
|
||
{sensitivity: "base"}
|
||
);
|
||
}
|
||
|
||
|
||
function CompareShopNumbers(
|
||
A,
|
||
B,
|
||
Direction
|
||
) {
|
||
const MissingA =
|
||
A === null ||
|
||
A === undefined ||
|
||
A === "";
|
||
|
||
const MissingB =
|
||
B === null ||
|
||
B === undefined ||
|
||
B === "";
|
||
|
||
const NumberA = Number(A);
|
||
const NumberB = Number(B);
|
||
|
||
const ValidA =
|
||
!MissingA &&
|
||
Number.isFinite(NumberA);
|
||
|
||
const ValidB =
|
||
!MissingB &&
|
||
Number.isFinite(NumberB);
|
||
|
||
if (!ValidA && !ValidB) {
|
||
return 0;
|
||
}
|
||
|
||
if (!ValidA) {
|
||
return 1;
|
||
}
|
||
|
||
if (!ValidB) {
|
||
return -1;
|
||
}
|
||
|
||
return (NumberA - NumberB) *
|
||
Direction;
|
||
}
|
||
|
||
|
||
function RenderToolShop() {
|
||
const ToolList =
|
||
document.getElementById(
|
||
"ShopToolList"
|
||
);
|
||
|
||
if (ToolList === null) {
|
||
return;
|
||
}
|
||
|
||
|
||
ToolList.replaceChildren(
|
||
CreateTrowelToolCard(),
|
||
CreateToolUnlockCard(
|
||
"MagicTrowel",
|
||
"Magic trowel",
|
||
"Plant the selected seed into as many empty plots as possible in one use.",
|
||
[
|
||
[
|
||
"Planting",
|
||
"All empty plots"
|
||
]
|
||
]
|
||
),
|
||
CreateShovelToolCard(),
|
||
CreateFertilizerToolCard(),
|
||
CreateToolUnlockCard(
|
||
"FutureSight",
|
||
"Future Sight",
|
||
"Preview what the Garden would look like if its next eligible mutation succeeded. Future Sight has a two-hour cooldown.",
|
||
[
|
||
[
|
||
"Cooldown",
|
||
"2 hours"
|
||
]
|
||
]
|
||
)
|
||
);
|
||
}
|
||
|
||
|
||
function CreateTrowelToolCard() {
|
||
const Card =
|
||
document.createElement(
|
||
"article"
|
||
);
|
||
|
||
Card.className =
|
||
"Panel ShopItem";
|
||
|
||
|
||
const Header =
|
||
document.createElement(
|
||
"div"
|
||
);
|
||
|
||
Header.className =
|
||
"PanelHeader PanelHeaderInset ShopItemHeader ShopItemHeaderOwned";
|
||
|
||
|
||
const Name =
|
||
document.createElement(
|
||
"h3"
|
||
);
|
||
|
||
Name.textContent = "Trowel";
|
||
|
||
Header.appendChild(Name);
|
||
|
||
|
||
const Description =
|
||
document.createElement(
|
||
"p"
|
||
);
|
||
|
||
Description.textContent =
|
||
"Your default planting tool. Select a seed, then use the Trowel on an empty plot.";
|
||
|
||
|
||
const Details =
|
||
document.createElement(
|
||
"div"
|
||
);
|
||
|
||
Details.className =
|
||
"ShopItemDetails";
|
||
|
||
Details.append(
|
||
CreateShopStat(
|
||
"Status",
|
||
"Unlocked"
|
||
),
|
||
CreateShopStat(
|
||
"Cost",
|
||
"Free"
|
||
)
|
||
);
|
||
|
||
|
||
const Button =
|
||
document.createElement(
|
||
"button"
|
||
);
|
||
|
||
Button.className =
|
||
"ActionButton ShopBuyButton";
|
||
|
||
Button.type = "button";
|
||
Button.textContent = "Default tool";
|
||
Button.disabled = true;
|
||
|
||
|
||
Card.append(
|
||
Header,
|
||
Description,
|
||
Details,
|
||
Button
|
||
);
|
||
|
||
return Card;
|
||
}
|
||
|
||
|
||
function CreateToolUnlockCard(
|
||
Tool,
|
||
NameText,
|
||
DescriptionText,
|
||
ExtraStats = []
|
||
) {
|
||
const IsOwned =
|
||
IsGardenToolUnlocked(
|
||
ShopSave,
|
||
Tool
|
||
);
|
||
|
||
const Cost =
|
||
GetGardenToolUnlockCost(
|
||
Tool
|
||
);
|
||
|
||
|
||
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 = NameText;
|
||
|
||
Header.appendChild(Name);
|
||
|
||
|
||
const Description =
|
||
document.createElement(
|
||
"p"
|
||
);
|
||
|
||
Description.textContent =
|
||
DescriptionText;
|
||
|
||
|
||
const Details =
|
||
document.createElement(
|
||
"div"
|
||
);
|
||
|
||
Details.className =
|
||
"ShopItemDetails";
|
||
|
||
Details.appendChild(
|
||
CreateShopStat(
|
||
"Status",
|
||
IsOwned
|
||
? "Unlocked"
|
||
: "Locked"
|
||
)
|
||
);
|
||
|
||
for (
|
||
const [Label, Value]
|
||
of ExtraStats
|
||
) {
|
||
Details.appendChild(
|
||
CreateShopStat(
|
||
Label,
|
||
Value
|
||
)
|
||
);
|
||
}
|
||
|
||
|
||
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",
|
||
() => {
|
||
BuyGardenTool(
|
||
Tool,
|
||
NameText
|
||
);
|
||
}
|
||
);
|
||
}
|
||
|
||
|
||
Card.append(
|
||
Header,
|
||
Description,
|
||
Details,
|
||
BuyButton
|
||
);
|
||
|
||
return Card;
|
||
}
|
||
|
||
|
||
function CreateShovelToolCard() {
|
||
const IsOwned =
|
||
IsGardenToolUnlocked(
|
||
ShopSave,
|
||
"Shovel"
|
||
);
|
||
|
||
const Level =
|
||
GetShovelLevel(
|
||
ShopSave
|
||
);
|
||
|
||
const UpgradeCost =
|
||
IsOwned
|
||
? GetShovelUpgradeCost(
|
||
ShopSave
|
||
)
|
||
: null;
|
||
|
||
|
||
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 = "Shovel";
|
||
|
||
Header.appendChild(Name);
|
||
|
||
|
||
const Description =
|
||
document.createElement(
|
||
"p"
|
||
);
|
||
|
||
Description.textContent =
|
||
"Remove planted crops. Upgrades recover more of the seed value instead of wasting it.";
|
||
|
||
|
||
const Details =
|
||
document.createElement(
|
||
"div"
|
||
);
|
||
|
||
Details.className =
|
||
"ShopItemDetails";
|
||
|
||
Details.append(
|
||
CreateShopStat(
|
||
"Current",
|
||
IsOwned
|
||
? GetShovelLevelDescription(
|
||
Level
|
||
)
|
||
: "Locked"
|
||
),
|
||
CreateShopStat(
|
||
"Next",
|
||
IsOwned &&
|
||
Level >= ShovelMaximumLevel
|
||
? "Maximum level"
|
||
: GetShovelLevelDescription(
|
||
IsOwned
|
||
? Level + 1
|
||
: 0
|
||
)
|
||
)
|
||
);
|
||
|
||
|
||
const ActionButton =
|
||
document.createElement(
|
||
"button"
|
||
);
|
||
|
||
ActionButton.className =
|
||
"ActionButton ShopBuyButton";
|
||
|
||
ActionButton.type = "button";
|
||
|
||
if (!IsOwned) {
|
||
const UnlockCost =
|
||
GetGardenToolUnlockCost(
|
||
"Shovel"
|
||
);
|
||
|
||
ActionButton.textContent =
|
||
"Buy - " +
|
||
UnlockCost.toLocaleString() +
|
||
" Dew";
|
||
|
||
ActionButton.disabled =
|
||
ShopSave.Currency.Dew <
|
||
UnlockCost ||
|
||
ShopPurchasePending;
|
||
|
||
ActionButton.addEventListener(
|
||
"click",
|
||
() => {
|
||
BuyGardenTool(
|
||
"Shovel",
|
||
"Shovel"
|
||
);
|
||
}
|
||
);
|
||
} else if (UpgradeCost === null) {
|
||
ActionButton.textContent =
|
||
"Maximum level";
|
||
|
||
ActionButton.disabled = true;
|
||
} else {
|
||
ActionButton.textContent =
|
||
"Upgrade - " +
|
||
UpgradeCost.toLocaleString() +
|
||
" Dew";
|
||
|
||
ActionButton.disabled =
|
||
ShopSave.Currency.Dew <
|
||
UpgradeCost ||
|
||
ShopPurchasePending;
|
||
|
||
ActionButton.addEventListener(
|
||
"click",
|
||
BuyShovelUpgrade
|
||
);
|
||
}
|
||
|
||
|
||
Card.append(
|
||
Header,
|
||
Description,
|
||
Details,
|
||
ActionButton
|
||
);
|
||
|
||
return Card;
|
||
}
|
||
|
||
|
||
function GetShovelLevelDescription(
|
||
Level
|
||
) {
|
||
if (Level <= 0) {
|
||
return "Returns nothing";
|
||
}
|
||
|
||
if (Level === 1) {
|
||
return "Returns 33% of seed cost";
|
||
}
|
||
|
||
if (Level === 2) {
|
||
return "Returns 66% of seed cost";
|
||
}
|
||
|
||
return "Returns the planted seed";
|
||
}
|
||
|
||
|
||
function CreateFertilizerToolCard() {
|
||
const IsOwned =
|
||
IsGardenToolUnlocked(
|
||
ShopSave,
|
||
"Fertilizer"
|
||
);
|
||
|
||
const Level =
|
||
GetFertilizerLevel(
|
||
ShopSave
|
||
);
|
||
|
||
const UpgradeCost =
|
||
IsOwned
|
||
? GetFertilizerUpgradeCost(
|
||
ShopSave
|
||
)
|
||
: null;
|
||
|
||
|
||
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 = "Fertilizer";
|
||
|
||
Header.appendChild(Name);
|
||
|
||
|
||
const Description =
|
||
document.createElement(
|
||
"p"
|
||
);
|
||
|
||
Description.textContent =
|
||
"Spend Fertilizer uses to advance a growing plant. Stronger levels advance more growth per use.";
|
||
|
||
|
||
const Details =
|
||
document.createElement(
|
||
"div"
|
||
);
|
||
|
||
Details.className =
|
||
"ShopItemDetails";
|
||
|
||
Details.append(
|
||
CreateShopStat(
|
||
"Current uses",
|
||
Number(
|
||
ShopSave.Inventory
|
||
.Fertilizer ?? 0
|
||
).toLocaleString()
|
||
),
|
||
CreateShopStat(
|
||
"Current",
|
||
IsOwned
|
||
? FertilizerGrowthMinutes[
|
||
Level
|
||
] + " minutes"
|
||
: "Locked"
|
||
),
|
||
CreateShopStat(
|
||
"Next",
|
||
IsOwned &&
|
||
Level >= FertilizerMaximumLevel
|
||
? "Maximum level"
|
||
: FertilizerGrowthMinutes[
|
||
IsOwned
|
||
? Level + 1
|
||
: 0
|
||
] + " minutes"
|
||
)
|
||
);
|
||
|
||
|
||
const Actions =
|
||
document.createElement(
|
||
"div"
|
||
);
|
||
|
||
Actions.className =
|
||
"ShopItemActions";
|
||
|
||
|
||
const ActionButton =
|
||
document.createElement(
|
||
"button"
|
||
);
|
||
|
||
ActionButton.className =
|
||
"ActionButton ShopBuyButton";
|
||
|
||
ActionButton.type = "button";
|
||
|
||
if (!IsOwned) {
|
||
const UnlockCost =
|
||
GetGardenToolUnlockCost(
|
||
"Fertilizer"
|
||
);
|
||
|
||
ActionButton.textContent =
|
||
"Buy - " +
|
||
UnlockCost.toLocaleString() +
|
||
" Dew";
|
||
|
||
ActionButton.disabled =
|
||
ShopSave.Currency.Dew <
|
||
UnlockCost ||
|
||
ShopPurchasePending;
|
||
|
||
ActionButton.addEventListener(
|
||
"click",
|
||
() => {
|
||
BuyGardenTool(
|
||
"Fertilizer",
|
||
"Fertilizer"
|
||
);
|
||
}
|
||
);
|
||
} else if (UpgradeCost === null) {
|
||
ActionButton.textContent =
|
||
"Maximum level";
|
||
|
||
ActionButton.disabled = true;
|
||
} else {
|
||
ActionButton.textContent =
|
||
"Upgrade - " +
|
||
UpgradeCost.toLocaleString() +
|
||
" Dew";
|
||
|
||
ActionButton.disabled =
|
||
ShopSave.Currency.Dew <
|
||
UpgradeCost ||
|
||
ShopPurchasePending;
|
||
|
||
ActionButton.addEventListener(
|
||
"click",
|
||
BuyFertilizerUpgrade
|
||
);
|
||
}
|
||
|
||
Actions.appendChild(
|
||
ActionButton
|
||
);
|
||
|
||
|
||
if (IsOwned) {
|
||
for (const Amount of [1, 10]) {
|
||
const Cost =
|
||
GetFertilizerUseCost(
|
||
Amount
|
||
);
|
||
|
||
const Button =
|
||
document.createElement(
|
||
"button"
|
||
);
|
||
|
||
Button.className =
|
||
"ActionButton ShopBuyButton";
|
||
|
||
Button.type = "button";
|
||
|
||
Button.textContent =
|
||
"Buy uses ×" +
|
||
Amount +
|
||
" - " +
|
||
Cost.toLocaleString() +
|
||
" Dew";
|
||
|
||
Button.disabled =
|
||
ShopSave.Currency.Dew < Cost ||
|
||
ShopPurchasePending;
|
||
|
||
Button.addEventListener(
|
||
"click",
|
||
() => {
|
||
BuyFertilizerUses(
|
||
Amount
|
||
);
|
||
}
|
||
);
|
||
|
||
Actions.appendChild(
|
||
Button
|
||
);
|
||
}
|
||
}
|
||
|
||
|
||
Card.append(
|
||
Header,
|
||
Description,
|
||
Details,
|
||
Actions
|
||
);
|
||
|
||
return Card;
|
||
}
|
||
|
||
|
||
function RenderGardenUpgrades() {
|
||
const UpgradeList =
|
||
document.getElementById(
|
||
"ShopGardenUpgradeList"
|
||
);
|
||
|
||
if (UpgradeList === null) {
|
||
return;
|
||
}
|
||
|
||
UpgradeList.replaceChildren(
|
||
CreateGardenExpansionCard(
|
||
"Column"
|
||
),
|
||
CreateGardenExpansionCard(
|
||
"Row"
|
||
),
|
||
CreateNewGardenCard(),
|
||
CreateRotationUpgradeCard(),
|
||
CreatePlantInformationUpgradeCard(),
|
||
CreateGardenOverviewUpgradeCard(),
|
||
CreateGardenEconomyUpgradeCard(),
|
||
CreateMutationHintsUpgradeCard()
|
||
);
|
||
}
|
||
|
||
|
||
function CreateGardenExpansionCard(
|
||
Direction
|
||
) {
|
||
const IsColumn =
|
||
Direction === "Column";
|
||
|
||
const AddedPlots =
|
||
IsColumn
|
||
? ShopSave.Garden.Height
|
||
: ShopSave.Garden.Width;
|
||
|
||
const Cost =
|
||
IsColumn
|
||
? GetGardenColumnUpgradeCost(
|
||
ShopSave
|
||
)
|
||
: GetGardenRowUpgradeCost(
|
||
ShopSave
|
||
);
|
||
|
||
const NewWidth =
|
||
ShopSave.Garden.Width +
|
||
(IsColumn ? 1 : 0);
|
||
|
||
const NewHeight =
|
||
ShopSave.Garden.Height +
|
||
(IsColumn ? 0 : 1);
|
||
|
||
|
||
const Card =
|
||
document.createElement(
|
||
"article"
|
||
);
|
||
|
||
Card.className =
|
||
"Panel ShopItem";
|
||
|
||
|
||
const Header =
|
||
document.createElement(
|
||
"div"
|
||
);
|
||
|
||
Header.className =
|
||
"PanelHeader PanelHeaderInset ShopItemHeader";
|
||
|
||
|
||
const Name =
|
||
document.createElement(
|
||
"h3"
|
||
);
|
||
|
||
Name.textContent =
|
||
"Add " +
|
||
Direction.toLowerCase();
|
||
|
||
Header.appendChild(Name);
|
||
|
||
|
||
const Description =
|
||
document.createElement(
|
||
"p"
|
||
);
|
||
|
||
Description.textContent =
|
||
IsColumn
|
||
? "Add one column to the right side of your Garden."
|
||
: "Add one row to the bottom of your Garden.";
|
||
|
||
|
||
const Details =
|
||
document.createElement(
|
||
"div"
|
||
);
|
||
|
||
Details.className =
|
||
"ShopItemDetails";
|
||
|
||
Details.append(
|
||
CreateShopStat(
|
||
"Garden",
|
||
ShopSave.Garden.Name
|
||
),
|
||
CreateShopStat(
|
||
"Current size",
|
||
ShopSave.Garden.Width +
|
||
"×" +
|
||
ShopSave.Garden.Height
|
||
),
|
||
CreateShopStat(
|
||
"Adds",
|
||
AddedPlots.toLocaleString() +
|
||
(AddedPlots === 1
|
||
? " plot"
|
||
: " plots")
|
||
),
|
||
CreateShopStat(
|
||
"New size",
|
||
NewWidth +
|
||
"×" +
|
||
NewHeight
|
||
)
|
||
);
|
||
|
||
|
||
const BuyButton =
|
||
document.createElement(
|
||
"button"
|
||
);
|
||
|
||
BuyButton.className =
|
||
"ActionButton ShopBuyButton";
|
||
|
||
BuyButton.type = "button";
|
||
|
||
BuyButton.textContent =
|
||
"Buy - " +
|
||
Cost.toLocaleString() +
|
||
" Dew";
|
||
|
||
BuyButton.disabled =
|
||
ShopSave.Currency.Dew < Cost ||
|
||
ShopPurchasePending;
|
||
|
||
BuyButton.addEventListener(
|
||
"click",
|
||
() => {
|
||
BuyGardenExpansion(
|
||
Direction
|
||
);
|
||
}
|
||
);
|
||
|
||
|
||
Card.append(
|
||
Header,
|
||
Description,
|
||
Details,
|
||
BuyButton
|
||
);
|
||
|
||
|
||
return Card;
|
||
}
|
||
|
||
|
||
function CreateNewGardenCard() {
|
||
const Cost =
|
||
GetNewGardenCost(
|
||
ShopSave
|
||
);
|
||
|
||
const GardensOwned =
|
||
ShopSave.Gardens.length;
|
||
|
||
|
||
const Card =
|
||
document.createElement(
|
||
"article"
|
||
);
|
||
|
||
Card.className =
|
||
"Panel ShopItem";
|
||
|
||
|
||
const Header =
|
||
document.createElement(
|
||
"div"
|
||
);
|
||
|
||
Header.className =
|
||
"PanelHeader PanelHeaderInset ShopItemHeader";
|
||
|
||
|
||
const Name =
|
||
document.createElement(
|
||
"h3"
|
||
);
|
||
|
||
Name.textContent =
|
||
"Buy new Garden";
|
||
|
||
Header.appendChild(Name);
|
||
|
||
|
||
const Description =
|
||
document.createElement(
|
||
"p"
|
||
);
|
||
|
||
Description.textContent =
|
||
"Buy another independent 3×3 Garden. New Gardens can be named and expanded separately.";
|
||
|
||
|
||
const Details =
|
||
document.createElement(
|
||
"div"
|
||
);
|
||
|
||
Details.className =
|
||
"ShopItemDetails";
|
||
|
||
Details.append(
|
||
CreateShopStat(
|
||
"Gardens owned",
|
||
GardensOwned.toLocaleString()
|
||
),
|
||
CreateShopStat(
|
||
"New Garden size",
|
||
"3×3 (9 plots)"
|
||
),
|
||
CreateShopStat(
|
||
"Price scaling",
|
||
"+50% per Garden"
|
||
)
|
||
);
|
||
|
||
|
||
const BuyButton =
|
||
document.createElement(
|
||
"button"
|
||
);
|
||
|
||
BuyButton.className =
|
||
"ActionButton ShopBuyButton";
|
||
|
||
BuyButton.type = "button";
|
||
|
||
BuyButton.textContent =
|
||
"Buy - " +
|
||
Cost.toLocaleString() +
|
||
" Dew";
|
||
|
||
BuyButton.disabled =
|
||
ShopSave.Currency.Dew < Cost ||
|
||
ShopPurchasePending;
|
||
|
||
BuyButton.addEventListener(
|
||
"click",
|
||
BuyNewGarden
|
||
);
|
||
|
||
|
||
Card.append(
|
||
Header,
|
||
Description,
|
||
Details,
|
||
BuyButton
|
||
);
|
||
|
||
|
||
return Card;
|
||
}
|
||
|
||
|
||
function 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() {
|
||
const Cost =
|
||
GetPlantInformationUpgradeCost();
|
||
|
||
const IsOwned =
|
||
HasPlantInformationUpgrade(
|
||
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 =
|
||
"Plant information";
|
||
|
||
Header.appendChild(Name);
|
||
|
||
|
||
const Description =
|
||
document.createElement(
|
||
"p"
|
||
);
|
||
|
||
Description.textContent =
|
||
"Show each plant's name above its sprite and exact time remaining below it. Both can be toggled on/off from the profile page.";
|
||
|
||
|
||
const Details =
|
||
document.createElement(
|
||
"div"
|
||
);
|
||
|
||
Details.className =
|
||
"ShopItemDetails";
|
||
|
||
Details.append(
|
||
CreateShopStat(
|
||
"Plant names",
|
||
IsOwned
|
||
? "Unlocked"
|
||
: "Locked"
|
||
),
|
||
CreateShopStat(
|
||
"Growth timers",
|
||
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",
|
||
BuyPlantInformationUpgrade
|
||
);
|
||
}
|
||
|
||
|
||
Card.append(
|
||
Header,
|
||
Description,
|
||
Details,
|
||
BuyButton
|
||
);
|
||
|
||
|
||
return Card;
|
||
}
|
||
|
||
|
||
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 =
|
||
"PanelHeader PanelHeaderInset ShopItemHeader" +
|
||
(
|
||
IsOwned
|
||
? " ShopItemHeaderOwned"
|
||
: ""
|
||
);
|
||
|
||
|
||
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 CreateGardenEconomyUpgradeCard() {
|
||
const Cost =
|
||
GetGardenEconomyUpgradeCost();
|
||
|
||
const IsOwned =
|
||
HasGardenEconomyUpgrade(
|
||
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 =
|
||
"Garden economy";
|
||
|
||
Header.appendChild(Name);
|
||
|
||
|
||
const Description =
|
||
document.createElement(
|
||
"p"
|
||
);
|
||
|
||
Description.textContent =
|
||
"Add live economy information for the active Garden: Dew invested, total harvest value, net profit after replanting, and Farm DPH.";
|
||
|
||
|
||
const Details =
|
||
document.createElement(
|
||
"div"
|
||
);
|
||
|
||
Details.className =
|
||
"ShopItemDetails";
|
||
|
||
Details.append(
|
||
CreateShopStat(
|
||
"Garden economics",
|
||
IsOwned
|
||
? "Unlocked"
|
||
: "Locked"
|
||
),
|
||
CreateShopStat(
|
||
"Scope",
|
||
"Active Garden"
|
||
)
|
||
);
|
||
|
||
|
||
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",
|
||
BuyGardenEconomyUpgrade
|
||
);
|
||
}
|
||
|
||
|
||
Card.append(
|
||
Header,
|
||
Description,
|
||
Details,
|
||
BuyButton
|
||
);
|
||
|
||
|
||
return Card;
|
||
}
|
||
|
||
|
||
function CreateMutationHintsUpgradeCard() {
|
||
const IsUnlocked =
|
||
HasMutationHintsUpgrade(
|
||
ShopSave
|
||
);
|
||
|
||
const Level =
|
||
GetMutationHintsLevel(
|
||
ShopSave
|
||
);
|
||
|
||
const Cost =
|
||
GetMutationHintsUpgradeCost(
|
||
ShopSave
|
||
);
|
||
|
||
const IsMaximumLevel =
|
||
IsUnlocked &&
|
||
Level >= MutationHintsMaximumLevel;
|
||
|
||
|
||
const Card =
|
||
document.createElement(
|
||
"article"
|
||
);
|
||
|
||
Card.className =
|
||
"Panel ShopItem";
|
||
|
||
|
||
const Header =
|
||
document.createElement(
|
||
"div"
|
||
);
|
||
|
||
Header.className =
|
||
"PanelHeader PanelHeaderInset ShopItemHeader" +
|
||
(
|
||
IsMaximumLevel
|
||
? " ShopItemHeaderOwned"
|
||
: ""
|
||
);
|
||
|
||
|
||
const Name =
|
||
document.createElement(
|
||
"h3"
|
||
);
|
||
|
||
Name.textContent =
|
||
"Mutation hints";
|
||
|
||
Header.appendChild(Name);
|
||
|
||
|
||
const Description =
|
||
document.createElement(
|
||
"p"
|
||
);
|
||
|
||
Description.textContent =
|
||
"Show subtle hints for undiscovered mutations once you've discovered the plants needed to attempt them. The first level shows one hint; the upgrade shows every available hint, up to 10.";
|
||
|
||
|
||
const Details =
|
||
document.createElement(
|
||
"div"
|
||
);
|
||
|
||
Details.className =
|
||
"ShopItemDetails";
|
||
|
||
Details.append(
|
||
CreateShopStat(
|
||
"Current",
|
||
!IsUnlocked
|
||
? "Locked"
|
||
: Level >= MutationHintsMaximumLevel
|
||
? "All hints (max 10)"
|
||
: "1 hint at a time"
|
||
),
|
||
CreateShopStat(
|
||
"Next",
|
||
!IsUnlocked
|
||
? "1 hint at a time"
|
||
: IsMaximumLevel
|
||
? "Maximum level"
|
||
: "All hints (max 10)"
|
||
)
|
||
);
|
||
|
||
|
||
const ActionButton =
|
||
document.createElement(
|
||
"button"
|
||
);
|
||
|
||
ActionButton.className =
|
||
"ActionButton ShopBuyButton";
|
||
|
||
ActionButton.type = "button";
|
||
|
||
if (Cost === null) {
|
||
ActionButton.textContent =
|
||
"Maximum level";
|
||
|
||
ActionButton.disabled = true;
|
||
} else {
|
||
ActionButton.textContent =
|
||
(IsUnlocked
|
||
? "Upgrade - "
|
||
: "Buy - ") +
|
||
Cost.toLocaleString() +
|
||
" Dew";
|
||
|
||
ActionButton.disabled =
|
||
ShopSave.Currency.Dew < Cost ||
|
||
ShopPurchasePending;
|
||
|
||
ActionButton.addEventListener(
|
||
"click",
|
||
BuyMutationHintsUpgrade
|
||
);
|
||
}
|
||
|
||
|
||
Card.append(
|
||
Header,
|
||
Description,
|
||
Details,
|
||
ActionButton
|
||
);
|
||
|
||
|
||
return Card;
|
||
}
|
||
|
||
|
||
function CreateShopSeedCard(
|
||
Plant
|
||
) {
|
||
const Card =
|
||
document.createElement(
|
||
"article"
|
||
);
|
||
|
||
Card.className =
|
||
"Panel ShopItem";
|
||
|
||
|
||
const Header =
|
||
document.createElement(
|
||
"div"
|
||
);
|
||
|
||
Header.className =
|
||
"PanelHeader PanelHeaderInset ShopItemHeader";
|
||
|
||
|
||
const Name =
|
||
document.createElement(
|
||
"h3"
|
||
);
|
||
|
||
Name.textContent =
|
||
Plant.Name;
|
||
|
||
|
||
Header.append(
|
||
Name
|
||
);
|
||
|
||
|
||
const Body =
|
||
document.createElement(
|
||
"div"
|
||
);
|
||
|
||
Body.className =
|
||
"ShopItemBody";
|
||
|
||
|
||
const Visual =
|
||
CreateShopPlantVisual(
|
||
Plant
|
||
);
|
||
|
||
|
||
const Details =
|
||
document.createElement(
|
||
"div"
|
||
);
|
||
|
||
Details.className =
|
||
"ShopItemDetails";
|
||
|
||
|
||
if (
|
||
typeof Plant.Description ===
|
||
"string" &&
|
||
Plant.Description.length > 0
|
||
) {
|
||
const Description =
|
||
document.createElement(
|
||
"p"
|
||
);
|
||
|
||
Description.textContent =
|
||
Plant.Description;
|
||
|
||
Details.appendChild(
|
||
Description
|
||
);
|
||
}
|
||
|
||
|
||
Details.appendChild(
|
||
CreateShopStat(
|
||
"Growth time",
|
||
FormatShopGrowthTime(
|
||
Plant.GrowthTime
|
||
)
|
||
)
|
||
);
|
||
|
||
|
||
const Cost =
|
||
GetPlantShopCost(
|
||
ShopSave,
|
||
Plant.Id
|
||
);
|
||
|
||
const Reward =
|
||
GetPlantHarvestReward(
|
||
ShopSave,
|
||
Plant.Id
|
||
);
|
||
|
||
const DewPerHour =
|
||
GetPlantDewPerHour(
|
||
ShopSave,
|
||
Plant.Id
|
||
);
|
||
|
||
|
||
Details.appendChild(
|
||
CreateShopStat(
|
||
"Seed cost",
|
||
Cost === null
|
||
? "Unavailable"
|
||
: Cost.toLocaleString() +
|
||
" Dew"
|
||
)
|
||
);
|
||
|
||
Details.appendChild(
|
||
CreateShopStat(
|
||
"Harvest reward",
|
||
Reward === null
|
||
? "Unavailable"
|
||
: Reward.toLocaleString() +
|
||
" Dew"
|
||
)
|
||
);
|
||
|
||
Details.appendChild(
|
||
CreateShopStat(
|
||
"Dew / hour",
|
||
FormatDewPerHour(
|
||
DewPerHour
|
||
)
|
||
)
|
||
);
|
||
|
||
Details.appendChild(
|
||
CreateShopStat(
|
||
"Inventory",
|
||
GetSeedCount(
|
||
ShopSave,
|
||
Plant.Id
|
||
).toLocaleString()
|
||
)
|
||
);
|
||
|
||
|
||
Body.append(
|
||
Visual,
|
||
Details
|
||
);
|
||
|
||
|
||
const BuyOptions =
|
||
document.createElement(
|
||
"div"
|
||
);
|
||
|
||
BuyOptions.className =
|
||
"ShopSeedBuyOptions";
|
||
|
||
|
||
const GardenSize =
|
||
Math.max(
|
||
1,
|
||
ShopSave.Garden.Width *
|
||
ShopSave.Garden.Height
|
||
);
|
||
|
||
const PurchaseOptions = [
|
||
{
|
||
Amount: 1,
|
||
Label: "Buy seed"
|
||
},
|
||
{
|
||
Amount: 10,
|
||
Label: "Buy 10 seeds"
|
||
},
|
||
{
|
||
Amount: GardenSize,
|
||
Label:
|
||
"Buy " +
|
||
GardenSize.toLocaleString() +
|
||
" seeds"
|
||
}
|
||
];
|
||
|
||
|
||
for (
|
||
const Option
|
||
of PurchaseOptions
|
||
) {
|
||
const BuyButton =
|
||
document.createElement(
|
||
"button"
|
||
);
|
||
|
||
BuyButton.className =
|
||
"ActionButton ShopBuyButton";
|
||
|
||
BuyButton.type = "button";
|
||
|
||
|
||
const TotalCost =
|
||
Cost === null
|
||
? null
|
||
: Cost * Option.Amount;
|
||
|
||
BuyButton.textContent =
|
||
TotalCost === null
|
||
? "Unavailable"
|
||
: Option.Label +
|
||
" - " +
|
||
TotalCost.toLocaleString() +
|
||
" Dew";
|
||
|
||
BuyButton.disabled =
|
||
TotalCost === null ||
|
||
ShopSave.Currency.Dew <
|
||
TotalCost ||
|
||
ShopPurchasePending;
|
||
|
||
BuyButton.addEventListener(
|
||
"click",
|
||
() => {
|
||
BuyPlantSeed(
|
||
Plant.Id,
|
||
Option.Amount
|
||
);
|
||
}
|
||
);
|
||
|
||
BuyOptions.appendChild(
|
||
BuyButton
|
||
);
|
||
}
|
||
|
||
|
||
Card.append(
|
||
Header,
|
||
Body,
|
||
BuyOptions
|
||
);
|
||
|
||
|
||
return Card;
|
||
}
|
||
|
||
|
||
function CreateShopPlantVisual(
|
||
Plant
|
||
) {
|
||
const Visual =
|
||
document.createElement(
|
||
"div"
|
||
);
|
||
|
||
Visual.className =
|
||
"ShopPlantVisual";
|
||
|
||
|
||
const ImageFrame =
|
||
document.createElement(
|
||
"div"
|
||
);
|
||
|
||
ImageFrame.className =
|
||
"PlantTile ShopPlantImageFrame";
|
||
|
||
|
||
const MatureImage =
|
||
GetPlantMatureImageSource(
|
||
Plant
|
||
);
|
||
|
||
|
||
if (MatureImage === null) {
|
||
const Missing =
|
||
document.createElement(
|
||
"span"
|
||
);
|
||
|
||
Missing.className =
|
||
"ShopPlantMissing";
|
||
|
||
Missing.textContent =
|
||
"No image";
|
||
|
||
ImageFrame.appendChild(
|
||
Missing
|
||
);
|
||
} else {
|
||
const Image =
|
||
document.createElement(
|
||
"img"
|
||
);
|
||
|
||
Image.className =
|
||
"PlantSprite";
|
||
|
||
Image.src =
|
||
MatureImage;
|
||
|
||
Image.alt =
|
||
Plant.Name;
|
||
|
||
ImageFrame.appendChild(
|
||
Image
|
||
);
|
||
}
|
||
|
||
|
||
const Number =
|
||
document.createElement(
|
||
"span"
|
||
);
|
||
|
||
Number.className =
|
||
"ShopItemNumber";
|
||
|
||
Number.textContent =
|
||
String(
|
||
Plant.Id
|
||
).padStart(
|
||
3,
|
||
"0"
|
||
);
|
||
|
||
|
||
Visual.append(
|
||
ImageFrame,
|
||
Number
|
||
);
|
||
|
||
|
||
return Visual;
|
||
}
|
||
|
||
|
||
function FormatShopGrowthTime(
|
||
Milliseconds
|
||
) {
|
||
const TotalMinutes =
|
||
Math.max(
|
||
1,
|
||
Math.ceil(
|
||
Number(
|
||
Milliseconds
|
||
) /
|
||
60000
|
||
)
|
||
);
|
||
|
||
const Hours =
|
||
Math.floor(
|
||
TotalMinutes /
|
||
60
|
||
);
|
||
|
||
const Minutes =
|
||
TotalMinutes %
|
||
60;
|
||
|
||
|
||
if (
|
||
Hours > 0 &&
|
||
Minutes > 0
|
||
) {
|
||
return (
|
||
Hours +
|
||
"h " +
|
||
Minutes +
|
||
"m"
|
||
);
|
||
}
|
||
|
||
if (Hours > 0) {
|
||
return Hours + "h";
|
||
}
|
||
|
||
return Minutes + "m";
|
||
}
|
||
|
||
|
||
function CreateShopStat(
|
||
Name,
|
||
Value
|
||
) {
|
||
const Row =
|
||
document.createElement(
|
||
"p"
|
||
);
|
||
|
||
Row.className =
|
||
"ShopStat";
|
||
|
||
|
||
const Label =
|
||
document.createElement(
|
||
"span"
|
||
);
|
||
|
||
Label.className =
|
||
"ShopStatName";
|
||
|
||
Label.textContent =
|
||
Name + ":";
|
||
|
||
|
||
const Amount =
|
||
document.createElement(
|
||
"strong"
|
||
);
|
||
|
||
Amount.textContent =
|
||
Value;
|
||
|
||
|
||
Row.append(
|
||
Label,
|
||
Amount
|
||
);
|
||
|
||
|
||
return Row;
|
||
}
|
||
|
||
|
||
async function BuyPlantSeed(
|
||
PlantId,
|
||
Amount = 1
|
||
) {
|
||
if (ShopPurchasePending) {
|
||
return;
|
||
}
|
||
|
||
|
||
Amount = Math.max(
|
||
1,
|
||
Math.floor(
|
||
Number(Amount) || 1
|
||
)
|
||
);
|
||
|
||
|
||
const Plant =
|
||
GetPlantById(
|
||
PlantId
|
||
);
|
||
|
||
if (
|
||
Plant === null ||
|
||
!IsPlantAvailableInShop(
|
||
ShopSave,
|
||
Plant
|
||
)
|
||
) {
|
||
return;
|
||
}
|
||
|
||
|
||
const UnitCost =
|
||
GetPlantShopCost(
|
||
ShopSave,
|
||
PlantId
|
||
);
|
||
|
||
if (UnitCost === null) {
|
||
SetShopMessage(
|
||
"That seed doesn't have a purchasable recipe yet."
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
const TotalCost =
|
||
UnitCost * Amount;
|
||
|
||
if (
|
||
ShopSave.Currency.Dew <
|
||
TotalCost
|
||
) {
|
||
SetShopMessage(
|
||
"You don't have enough Dew for " +
|
||
Amount.toLocaleString() +
|
||
(Amount === 1
|
||
? " seed of "
|
||
: " seeds of ") +
|
||
Plant.Name +
|
||
"."
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
ShopPurchasePending = true;
|
||
|
||
try {
|
||
ShopSave.Currency.Dew -=
|
||
TotalCost;
|
||
|
||
ShopSave.Statistics.CurrencySpent.Dew +=
|
||
TotalCost;
|
||
|
||
ShopSave.Statistics.SeedsPurchased +=
|
||
Amount;
|
||
|
||
AddSeed(
|
||
ShopSave,
|
||
PlantId,
|
||
Amount
|
||
);
|
||
|
||
DiscoverPlant(
|
||
ShopSave,
|
||
PlantId
|
||
);
|
||
|
||
|
||
SetShopMessage(
|
||
"Bought " +
|
||
Amount.toLocaleString() +
|
||
" " +
|
||
Plant.Name +
|
||
(Amount === 1
|
||
? " seed for "
|
||
: " seeds for ") +
|
||
TotalCost.toLocaleString() +
|
||
" Dew."
|
||
);
|
||
|
||
RenderShop();
|
||
|
||
await SaveGame(
|
||
ShopSave
|
||
);
|
||
} finally {
|
||
ShopPurchasePending = false;
|
||
RenderShop();
|
||
}
|
||
}
|
||
|
||
async function BuyGardenTool(
|
||
Tool,
|
||
Name
|
||
) {
|
||
if (
|
||
ShopPurchasePending ||
|
||
IsGardenToolUnlocked(
|
||
ShopSave,
|
||
Tool
|
||
)
|
||
) {
|
||
return;
|
||
}
|
||
|
||
|
||
const Cost =
|
||
GetGardenToolUnlockCost(
|
||
Tool
|
||
);
|
||
|
||
if (Cost === null) {
|
||
return;
|
||
}
|
||
|
||
if (
|
||
ShopSave.Currency.Dew <
|
||
Cost
|
||
) {
|
||
SetShopMessage(
|
||
"You don't have enough Dew for " +
|
||
Name +
|
||
"."
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
ShopPurchasePending = true;
|
||
|
||
try {
|
||
ShopSave.Currency.Dew -=
|
||
Cost;
|
||
|
||
ShopSave.Statistics.CurrencySpent.Dew +=
|
||
Cost;
|
||
|
||
UnlockGardenTool(
|
||
ShopSave,
|
||
Tool
|
||
);
|
||
|
||
|
||
SetShopMessage(
|
||
"Unlocked " +
|
||
Name +
|
||
" for " +
|
||
Cost.toLocaleString() +
|
||
" Dew."
|
||
);
|
||
|
||
RenderShop();
|
||
|
||
await SaveGame(
|
||
ShopSave
|
||
);
|
||
} finally {
|
||
ShopPurchasePending = false;
|
||
RenderShop();
|
||
}
|
||
}
|
||
|
||
|
||
async function BuyShovelUpgrade() {
|
||
if (
|
||
ShopPurchasePending ||
|
||
!IsGardenToolUnlocked(
|
||
ShopSave,
|
||
"Shovel"
|
||
)
|
||
) {
|
||
return;
|
||
}
|
||
|
||
|
||
const Cost =
|
||
GetShovelUpgradeCost(
|
||
ShopSave
|
||
);
|
||
|
||
if (Cost === null) {
|
||
return;
|
||
}
|
||
|
||
if (
|
||
ShopSave.Currency.Dew <
|
||
Cost
|
||
) {
|
||
SetShopMessage(
|
||
"You don't have enough Dew for the next Shovel upgrade."
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
ShopPurchasePending = true;
|
||
|
||
try {
|
||
ShopSave.Currency.Dew -=
|
||
Cost;
|
||
|
||
ShopSave.Statistics.CurrencySpent.Dew +=
|
||
Cost;
|
||
|
||
if (!UpgradeShovel(ShopSave)) {
|
||
return;
|
||
}
|
||
|
||
|
||
SetShopMessage(
|
||
"Upgraded Shovel to level " +
|
||
GetShovelLevel(
|
||
ShopSave
|
||
) +
|
||
" for " +
|
||
Cost.toLocaleString() +
|
||
" Dew."
|
||
);
|
||
|
||
RenderShop();
|
||
|
||
await SaveGame(
|
||
ShopSave
|
||
);
|
||
} finally {
|
||
ShopPurchasePending = false;
|
||
RenderShop();
|
||
}
|
||
}
|
||
|
||
|
||
async function BuyFertilizerUpgrade() {
|
||
if (
|
||
ShopPurchasePending ||
|
||
!IsGardenToolUnlocked(
|
||
ShopSave,
|
||
"Fertilizer"
|
||
)
|
||
) {
|
||
return;
|
||
}
|
||
|
||
|
||
const Cost =
|
||
GetFertilizerUpgradeCost(
|
||
ShopSave
|
||
);
|
||
|
||
if (Cost === null) {
|
||
return;
|
||
}
|
||
|
||
if (
|
||
ShopSave.Currency.Dew <
|
||
Cost
|
||
) {
|
||
SetShopMessage(
|
||
"You don't have enough Dew for the next Fertilizer upgrade."
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
ShopPurchasePending = true;
|
||
|
||
try {
|
||
ShopSave.Currency.Dew -=
|
||
Cost;
|
||
|
||
ShopSave.Statistics.CurrencySpent.Dew +=
|
||
Cost;
|
||
|
||
if (!UpgradeFertilizer(ShopSave)) {
|
||
return;
|
||
}
|
||
|
||
|
||
SetShopMessage(
|
||
"Upgraded Fertilizer to level " +
|
||
GetFertilizerLevel(
|
||
ShopSave
|
||
) +
|
||
" for " +
|
||
Cost.toLocaleString() +
|
||
" Dew. Each use now advances " +
|
||
GetFertilizerGrowthMinutes(
|
||
ShopSave
|
||
) +
|
||
" minutes."
|
||
);
|
||
|
||
RenderShop();
|
||
|
||
await SaveGame(
|
||
ShopSave
|
||
);
|
||
} finally {
|
||
ShopPurchasePending = false;
|
||
RenderShop();
|
||
}
|
||
}
|
||
|
||
|
||
async function BuyFertilizerUses(
|
||
Amount
|
||
) {
|
||
if (
|
||
ShopPurchasePending ||
|
||
!IsGardenToolUnlocked(
|
||
ShopSave,
|
||
"Fertilizer"
|
||
)
|
||
) {
|
||
return;
|
||
}
|
||
|
||
|
||
Amount = Math.max(
|
||
1,
|
||
Math.floor(
|
||
Number(Amount) || 1
|
||
)
|
||
);
|
||
|
||
const Cost =
|
||
GetFertilizerUseCost(
|
||
Amount
|
||
);
|
||
|
||
if (
|
||
ShopSave.Currency.Dew <
|
||
Cost
|
||
) {
|
||
SetShopMessage(
|
||
"You don't have enough Dew for that much Fertilizer."
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
ShopPurchasePending = true;
|
||
|
||
try {
|
||
ShopSave.Currency.Dew -=
|
||
Cost;
|
||
|
||
ShopSave.Statistics.CurrencySpent.Dew +=
|
||
Cost;
|
||
|
||
AddFertilizerUses(
|
||
ShopSave,
|
||
Amount
|
||
);
|
||
|
||
|
||
SetShopMessage(
|
||
"Bought " +
|
||
Amount.toLocaleString() +
|
||
(Amount === 1
|
||
? " Fertilizer use for "
|
||
: " Fertilizer uses for ") +
|
||
Cost.toLocaleString() +
|
||
" Dew."
|
||
);
|
||
|
||
RenderShop();
|
||
|
||
await SaveGame(
|
||
ShopSave
|
||
);
|
||
} finally {
|
||
ShopPurchasePending = false;
|
||
RenderShop();
|
||
}
|
||
}
|
||
|
||
|
||
async function BuyGardenExpansion(
|
||
Direction
|
||
) {
|
||
if (ShopPurchasePending) {
|
||
return;
|
||
}
|
||
|
||
|
||
const IsColumn =
|
||
Direction === "Column";
|
||
|
||
const IsRow =
|
||
Direction === "Row";
|
||
|
||
if (
|
||
!IsColumn &&
|
||
!IsRow
|
||
) {
|
||
return;
|
||
}
|
||
|
||
|
||
const Cost =
|
||
IsColumn
|
||
? GetGardenColumnUpgradeCost(
|
||
ShopSave
|
||
)
|
||
: GetGardenRowUpgradeCost(
|
||
ShopSave
|
||
);
|
||
|
||
if (
|
||
ShopSave.Currency.Dew <
|
||
Cost
|
||
) {
|
||
SetShopMessage(
|
||
"You don't have enough Dew to add a " +
|
||
Direction.toLowerCase() +
|
||
"."
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
ShopPurchasePending = true;
|
||
|
||
try {
|
||
ShopSave.Currency.Dew -=
|
||
Cost;
|
||
|
||
ShopSave.Statistics.CurrencySpent.Dew +=
|
||
Cost;
|
||
|
||
|
||
if (IsColumn) {
|
||
AddGardenColumn(
|
||
ShopSave
|
||
);
|
||
} else {
|
||
AddGardenRow(
|
||
ShopSave
|
||
);
|
||
}
|
||
|
||
|
||
SetShopMessage(
|
||
"Added a Garden " +
|
||
Direction.toLowerCase() +
|
||
" for " +
|
||
Cost.toLocaleString() +
|
||
" Dew. Garden size is now " +
|
||
ShopSave.Garden.Width +
|
||
"×" +
|
||
ShopSave.Garden.Height +
|
||
"."
|
||
);
|
||
|
||
RenderShop();
|
||
|
||
await SaveGame(
|
||
ShopSave
|
||
);
|
||
} finally {
|
||
ShopPurchasePending = false;
|
||
RenderShop();
|
||
}
|
||
}
|
||
|
||
|
||
async function BuyNewGarden() {
|
||
if (ShopPurchasePending) {
|
||
return;
|
||
}
|
||
|
||
|
||
const Cost =
|
||
GetNewGardenCost(
|
||
ShopSave
|
||
);
|
||
|
||
if (
|
||
ShopSave.Currency.Dew <
|
||
Cost
|
||
) {
|
||
SetShopMessage(
|
||
"You don't have enough Dew for a new Garden."
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
ShopPurchasePending = true;
|
||
|
||
try {
|
||
ShopSave.Currency.Dew -=
|
||
Cost;
|
||
|
||
ShopSave.Statistics.CurrencySpent.Dew +=
|
||
Cost;
|
||
|
||
AddNewGarden(
|
||
ShopSave
|
||
);
|
||
|
||
SetShopMessage(
|
||
"Bought a new 3×3 Garden for " +
|
||
Cost.toLocaleString() +
|
||
" Dew. It is now your active Garden."
|
||
);
|
||
|
||
RenderShop();
|
||
|
||
await SaveGame(
|
||
ShopSave
|
||
);
|
||
} finally {
|
||
ShopPurchasePending = false;
|
||
RenderShop();
|
||
}
|
||
}
|
||
|
||
|
||
async function 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() {
|
||
if (
|
||
ShopPurchasePending ||
|
||
HasPlantInformationUpgrade(
|
||
ShopSave
|
||
)
|
||
) {
|
||
return;
|
||
}
|
||
|
||
|
||
const Cost =
|
||
GetPlantInformationUpgradeCost();
|
||
|
||
if (
|
||
ShopSave.Currency.Dew <
|
||
Cost
|
||
) {
|
||
SetShopMessage(
|
||
"You don't have enough Dew for Plant information."
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
ShopPurchasePending = true;
|
||
|
||
try {
|
||
ShopSave.Currency.Dew -=
|
||
Cost;
|
||
|
||
ShopSave.Statistics.CurrencySpent.Dew +=
|
||
Cost;
|
||
|
||
UnlockPlantInformation(
|
||
ShopSave
|
||
);
|
||
|
||
|
||
SetShopMessage(
|
||
"Bought Plant information for " +
|
||
Cost.toLocaleString() +
|
||
" Dew. Plant names and growth timers are now visible."
|
||
);
|
||
|
||
RenderShop();
|
||
|
||
await SaveGame(
|
||
ShopSave
|
||
);
|
||
} finally {
|
||
ShopPurchasePending = false;
|
||
RenderShop();
|
||
}
|
||
}
|
||
|
||
|
||
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();
|
||
}
|
||
}
|
||
|
||
|
||
async function BuyGardenEconomyUpgrade() {
|
||
if (
|
||
ShopPurchasePending ||
|
||
HasGardenEconomyUpgrade(
|
||
ShopSave
|
||
)
|
||
) {
|
||
return;
|
||
}
|
||
|
||
|
||
const Cost =
|
||
GetGardenEconomyUpgradeCost();
|
||
|
||
if (
|
||
ShopSave.Currency.Dew <
|
||
Cost
|
||
) {
|
||
SetShopMessage(
|
||
"You don't have enough Dew for Garden economy."
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
ShopPurchasePending = true;
|
||
|
||
try {
|
||
ShopSave.Currency.Dew -=
|
||
Cost;
|
||
|
||
ShopSave.Statistics.CurrencySpent.Dew +=
|
||
Cost;
|
||
|
||
UnlockGardenEconomy(
|
||
ShopSave
|
||
);
|
||
|
||
|
||
SetShopMessage(
|
||
"Bought Garden economy for " +
|
||
Cost.toLocaleString() +
|
||
" Dew. Economy information is now visible on the Garden page."
|
||
);
|
||
|
||
RenderShop();
|
||
|
||
await SaveGame(
|
||
ShopSave
|
||
);
|
||
} finally {
|
||
ShopPurchasePending = false;
|
||
RenderShop();
|
||
}
|
||
}
|
||
|
||
|
||
async function BuyMutationHintsUpgrade() {
|
||
if (ShopPurchasePending) {
|
||
return;
|
||
}
|
||
|
||
|
||
const IsUnlocked =
|
||
HasMutationHintsUpgrade(
|
||
ShopSave
|
||
);
|
||
|
||
const Cost =
|
||
GetMutationHintsUpgradeCost(
|
||
ShopSave
|
||
);
|
||
|
||
if (Cost === null) {
|
||
return;
|
||
}
|
||
|
||
if (
|
||
ShopSave.Currency.Dew <
|
||
Cost
|
||
) {
|
||
SetShopMessage(
|
||
IsUnlocked
|
||
? "You don't have enough Dew to upgrade Mutation hints."
|
||
: "You don't have enough Dew for Mutation hints."
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
ShopPurchasePending = true;
|
||
|
||
try {
|
||
ShopSave.Currency.Dew -=
|
||
Cost;
|
||
|
||
ShopSave.Statistics.CurrencySpent.Dew +=
|
||
Cost;
|
||
|
||
if (IsUnlocked) {
|
||
UpgradeMutationHints(
|
||
ShopSave
|
||
);
|
||
|
||
SetShopMessage(
|
||
"Upgraded Mutation hints for " +
|
||
Cost.toLocaleString() +
|
||
" Dew. Up to 10 eligible hints are now shown at once."
|
||
);
|
||
} else {
|
||
UnlockMutationHints(
|
||
ShopSave
|
||
);
|
||
|
||
SetShopMessage(
|
||
"Bought Mutation hints for " +
|
||
Cost.toLocaleString() +
|
||
" Dew. The lowest-ID eligible hint is now visible in the Mutation encyclopedia."
|
||
);
|
||
}
|
||
|
||
RenderShop();
|
||
|
||
await SaveGame(
|
||
ShopSave
|
||
);
|
||
} finally {
|
||
ShopPurchasePending = false;
|
||
RenderShop();
|
||
}
|
||
}
|
||
|
||
|
||
function SetShopMessage(
|
||
Message
|
||
) {
|
||
const Element =
|
||
document.getElementById(
|
||
"ShopMessage"
|
||
);
|
||
|
||
if (Element !== null) {
|
||
Element.textContent =
|
||
Message;
|
||
}
|
||
}
|
||
|
||
|
||
document.addEventListener(
|
||
"DOMContentLoaded",
|
||
StartShop
|
||
);
|