breakout71/src/creative.ts

143 lines
4.1 KiB
TypeScript
Raw Normal View History

2025-04-14 13:39:30 +02:00
import { GameState, Level, PerkId, RawLevel, Upgrade } from "./types";
import { allLevels, icons, transformRawLevel, upgrades } from "./loadGameData";
2025-04-01 13:35:33 +02:00
import { t } from "./i18n/i18n";
import { getSettingValue, getTotalScore, setSettingValue } from "./settings";
2025-04-06 15:38:30 +02:00
import {
confirmRestart,
creativeModeThreshold,
gameState,
restart,
} from "./game";
import { asyncAlert, requiredAsyncAlert } from "./asyncAlert";
2025-04-06 18:21:53 +02:00
import {
describeLevel,
highScoreText,
reasonLevelIsLocked,
sumOfValues,
} from "./game_utils";
import { getHistory } from "./gameOver";
2025-04-11 20:34:51 +02:00
import { noCreative } from "./upgrades";
2025-04-14 13:39:30 +02:00
import { levelIconHTML } from "./levelIcon";
2025-04-01 13:35:33 +02:00
export function creativeMode(gameState: GameState) {
return {
2025-04-06 10:20:09 +02:00
icon: icons["icon:creative"],
2025-04-01 13:35:33 +02:00
text: t("lab.menu_entry"),
2025-04-01 13:39:09 +02:00
help:
(getTotalScore() < creativeModeThreshold &&
t("lab.unlocks_at", { score: creativeModeThreshold })) ||
t("lab.help"),
2025-04-01 13:35:33 +02:00
disabled: getTotalScore() < creativeModeThreshold,
async value() {
2025-04-06 15:38:30 +02:00
openCreativeModePerksPicker();
2025-04-01 13:35:33 +02:00
},
};
}
2025-04-06 10:13:10 +02:00
export async function openCreativeModePerksPicker() {
2025-04-01 13:35:33 +02:00
let creativeModePerks: Partial<{ [id in PerkId]: number }> = getSettingValue(
2025-04-21 13:25:06 +02:00
"creativeModePerks",
{},
);
2025-04-14 13:39:30 +02:00
const customLevels = (getSettingValue("custom_levels", []) as RawLevel[]).map(
transformRawLevel,
);
2025-04-18 21:17:32 +02:00
2025-04-21 13:25:06 +02:00
while (true) {
const levelOptions = [
...allLevels.map((l, li) => {
const problem = reasonLevelIsLocked(li, getHistory(), true)?.text || "";
return {
icon: icons[l.name],
text: l.name,
value: l,
disabled: !!problem,
tooltip: problem || describeLevel(l),
className: "",
};
}),
...customLevels.map((l) => ({
icon: levelIconHTML(l.bricks, l.size, l.color),
text: l.name,
value: l,
disabled: !l.bricks.filter((b) => b !== "_").length,
tooltip: describeLevel(l),
className: "",
})),
];
2025-04-20 18:40:41 +02:00
2025-04-21 13:25:06 +02:00
const selectedLeveOption =
levelOptions.find(
(l) => l.text === getSettingValue("creativeModeLevel", ""),
) || levelOptions[0];
selectedLeveOption.className = "highlight";
2025-04-20 18:40:41 +02:00
2025-04-21 13:25:06 +02:00
const choice = await asyncAlert<Upgrade | Level | "reset" | "play">({
2025-04-06 10:13:10 +02:00
title: t("lab.menu_entry"),
2025-04-04 12:07:51 +02:00
className: "actionsAsGrid",
2025-04-01 13:35:33 +02:00
content: [
2025-04-01 21:37:07 +02:00
{
2025-04-21 13:25:06 +02:00
icon: icons["icon:reset"],
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-21 13:25:06 +02:00
{
icon: icons["icon:new_run"],
2025-04-20 18:40:41 +02:00
value: "play",
text: t("lab.play"),
disabled: !sumOfValues(creativeModePerks),
},
t("lab.instructions"),
2025-04-01 13:35:33 +02:00
...upgrades
.filter((u) => !noCreative.includes(u.id))
.map((u) => ({
icon: u.icon,
text: u.name,
2025-04-06 18:21:53 +02:00
help:
(creativeModePerks[u.id] || 0) +
"/" +
(u.max + (creativeModePerks.limitless || 0)),
2025-04-01 13:35:33 +02:00
value: u,
className: creativeModePerks[u.id]
2025-04-18 21:17:32 +02:00
? "sandbox highlight"
2025-04-20 18:40:41 +02:00
: "sandbox not-highlighed",
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"),
2025-04-21 13:25:06 +02:00
...levelOptions,
2025-04-01 13:35:33 +02:00
],
2025-04-21 13:25:06 +02:00
});
if (!choice) return;
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-06 15:38:30 +02:00
setSettingValue("creativeModePerks", creativeModePerks);
2025-04-21 13:25:06 +02:00
setSettingValue("creativeModeLevel", "");
} else if (
choice === "play" ||
("bricks" in choice &&
choice.name == getSettingValue("creativeModeLevel", ""))
) {
2025-04-06 15:38:30 +02:00
if (await confirmRestart(gameState)) {
2025-04-18 17:15:47 +02:00
restart({
perks: creativeModePerks,
2025-04-20 18:40:41 +02:00
level: selectedLeveOption.value,
2025-04-18 17:15:47 +02:00
isCreativeRun: true,
});
2025-04-21 13:25:06 +02:00
return;
2025-04-06 10:13:10 +02:00
}
2025-04-20 18:40:41 +02:00
} else if ("bricks" in choice) {
setSettingValue("creativeModeLevel", choice.name);
2025-04-01 13:35:33 +02:00
} else if (choice) {
creativeModePerks[choice.id] =
2025-04-06 18:21:53 +02:00
((creativeModePerks[choice.id] || 0) + 1) %
(choice.max + 1 + (creativeModePerks.limitless || 0));
2025-04-20 21:14:35 +02:00
setSettingValue("creativeModePerks", creativeModePerks);
2025-04-01 13:35:33 +02:00
}
}
}