breakout71/src/creative.ts

109 lines
3.2 KiB
TypeScript
Raw Normal View History

2025-04-01 13:35:33 +02:00
import { GameState, Level, PerkId, Upgrade } from "./types";
import { allLevels, icons, upgrades } from "./loadGameData";
import { t } from "./i18n/i18n";
import { getSettingValue, getTotalScore, setSettingValue } from "./settings";
import { confirmRestart, creativeModeThreshold, restart } from "./game";
2025-04-01 16:37:34 +02:00
import { requiredAsyncAlert } from "./asyncAlert";
2025-04-01 21:43:36 +02:00
import { describeLevel, highScoreForMode, sumOfValues } from "./game_utils";
2025-04-01 13:35:33 +02:00
export function creativeMode(gameState: GameState) {
return {
icon: icons["icon:sandbox"],
text: t("lab.menu_entry"),
2025-04-01 13:39:09 +02:00
help:
highScoreForMode("creative") ||
(getTotalScore() < creativeModeThreshold &&
t("lab.unlocks_at", { score: creativeModeThreshold })) ||
t("lab.help"),
2025-04-01 13:35:33 +02:00
disabled: getTotalScore() < creativeModeThreshold,
async value() {
if (await confirmRestart(gameState)) {
restart({ mode: "creative" });
}
},
};
}
export async function openCreativeModePerksPicker(
gameState,
currentLevel: number,
) {
gameState.readyToRender = false;
let creativeModePerks: Partial<{ [id in PerkId]: number }> = getSettingValue(
"creativeModePerks_" + currentLevel,
{},
),
2025-04-01 21:43:36 +02:00
choice: Upgrade | Level | "reset" | void;
2025-04-01 13:35:33 +02:00
upgrades.forEach((u) => {
creativeModePerks[u.id] = Math.min(
creativeModePerks[u.id] || 0,
u.max - gameState.bannedPerks[u.id],
);
});
let noCreative: PerkId[] = [
"extra_levels",
"shunt",
"one_more_choice",
"instant_upgrade",
];
while (
2025-04-01 21:43:36 +02:00
(choice = await requiredAsyncAlert<Upgrade | Level | "reset">({
2025-04-01 13:35:33 +02:00
title: t("lab.title", { lvl: currentLevel + 1 }),
actionsAsGrid: true,
content: [
t("lab.instructions"),
2025-04-01 21:37:07 +02:00
{
2025-04-01 21:43:36 +02:00
value: "reset",
text: t("lab.reset"),
disabled: !sumOfValues(creativeModePerks),
2025-04-01 21:37:07 +02:00
},
2025-04-01 13:35:33 +02:00
...upgrades
.filter((u) => !noCreative.includes(u.id))
.map((u) => ({
icon: u.icon,
text: u.name,
help:
(creativeModePerks[u.id] || 0) +
"/" +
(u.max - gameState.bannedPerks[u.id]),
value: u,
disabled: u.max - gameState.bannedPerks[u.id] <= 0,
className: creativeModePerks[u.id]
? "sandbox"
: "sandbox grey-out-unless-hovered",
2025-04-01 13:39:09 +02:00
tooltip: u.help(creativeModePerks[u.id] || 1),
2025-04-01 13:35:33 +02:00
})),
t("lab.select_level"),
...allLevels.map((l) => ({
icon: icons[l.name],
text: l.name,
value: l,
2025-04-01 13:39:09 +02:00
tooltip: describeLevel(l),
2025-04-01 13:35:33 +02:00
})),
],
}))
) {
2025-04-01 21:43:36 +02:00
if (choice === "reset") {
upgrades.forEach((u) => {
creativeModePerks[u.id] = 0;
2025-04-01 21:37:07 +02:00
});
2025-04-01 21:43:36 +02:00
} else if ("bricks" in choice) {
2025-04-01 13:35:33 +02:00
setSettingValue("creativeModePerks_" + currentLevel, creativeModePerks);
upgrades.forEach((u) => {
gameState.perks[u.id] = creativeModePerks[u.id];
gameState.bannedPerks[u.id] += creativeModePerks[u.id];
});
gameState.runLevels[currentLevel] = choice;
break;
} else if (choice) {
creativeModePerks[choice.id] =
((creativeModePerks[choice.id] || 0) + 1) %
(choice.max - gameState.bannedPerks[choice.id] + 1);
}
}
}