breakout71/src/openScorePanel.ts

115 lines
3.1 KiB
TypeScript
Raw Normal View History

2025-05-03 08:20:00 +02:00
import { GameState, PerkId } from "./types";
2025-04-30 09:44:14 +02:00
import { asyncAlert } from "./asyncAlert";
import { t } from "./i18n/i18n";
import { levelsListHTMl, max_levels, pickedUpgradesHTMl } from "./game_utils";
import { getCreativeModeWarning, getHistory } from "./gameOver";
import { pause } from "./game";
2025-05-03 08:20:00 +02:00
import { allLevels, icons, upgrades } from "./loadGameData";
2025-04-30 09:44:14 +02:00
import { firstWhere } from "./pure_functions";
import { getSettingValue, getTotalScore } from "./settings";
import {
getLevelUnlockCondition,
reasonLevelIsLocked,
upgradeName,
} from "./get_level_unlock_condition";
2025-05-03 08:20:00 +02:00
import { isOptionOn } from "./options";
2025-04-07 14:08:48 +02:00
export async function openScorePanel(gameState: GameState) {
pause(true);
await asyncAlert({
title: t("score_panel.title", {
score: gameState.score,
level: gameState.currentLevel + 1,
max: max_levels(gameState),
}),
content: [
getCreativeModeWarning(gameState),
pickedUpgradesHTMl(gameState),
levelsListHTMl(gameState, gameState.currentLevel),
getNearestUnlockHTML(gameState),
2025-05-03 08:20:00 +02:00
gameState.rerolls
2025-04-30 16:29:49 +02:00
? t("score_panel.upgrade_point_count", {
2025-05-03 08:20:00 +02:00
count: gameState.rerolls,
2025-04-30 16:29:49 +02:00
})
2025-04-07 14:08:48 +02:00
: "",
],
allowClose: true,
});
}
2025-05-03 08:20:00 +02:00
export function getFirstUnlockable(gameState: GameState) {
if (gameState.creative) return undefined;
2025-04-08 14:03:38 +02:00
const unlocked = new Set(getSettingValue("breakout_71_unlocked_levels", []));
2025-05-03 08:20:00 +02:00
return firstWhere(allLevels, (l, li) => {
2025-04-08 14:03:38 +02:00
if (unlocked.has(l.name)) return;
2025-04-26 22:40:32 +02:00
const reason = reasonLevelIsLocked(li, l.name, getHistory(), false);
2025-04-08 14:03:38 +02:00
if (!reason) return;
2025-04-07 14:08:48 +02:00
2025-04-26 22:40:32 +02:00
const { minScore, forbidden, required } = getLevelUnlockCondition(
li,
l.name,
);
2025-05-03 08:20:00 +02:00
const missing: PerkId[] = required.filter((id) => !gameState?.perks?.[id]);
2025-04-08 14:03:38 +02:00
// we can't have a forbidden perk
2025-04-26 20:07:01 +02:00
if (forbidden.find((id) => gameState?.perks?.[id])) {
2025-04-08 14:03:38 +02:00
return;
}
// All required upgrades need to be unlocked
2025-05-03 08:20:00 +02:00
if (
missing.find(
(id) => upgrades.find((u) => u.id === id)!.threshold > getTotalScore(),
)
) {
2025-04-08 14:03:38 +02:00
return;
}
return {
l,
li,
minScore,
forbidden,
required,
missing,
reason,
};
});
2025-05-03 08:20:00 +02:00
}
export function getNearestUnlockHTML(gameState: GameState) {
if (!isOptionOn("level_unlocks_hints")) return "";
const firstUnlockable = getFirstUnlockable(gameState);
2025-04-07 14:08:48 +02:00
if (!firstUnlockable) return "";
2025-04-11 20:34:51 +02:00
let missingPoints = Math.max(0, firstUnlockable.minScore - gameState.score);
2025-04-26 22:40:32 +02:00
let missingUpgrades = firstUnlockable.missing
.map((id) => upgradeName(id))
.join(", ");
2025-04-07 14:08:48 +02:00
const title =
(missingUpgrades &&
t("score_panel.get_upgrades_to_unlock", {
missingUpgrades,
points: missingPoints,
level: firstUnlockable.l.name,
})) ||
2025-04-08 14:03:38 +02:00
t("score_panel.score_to_unlock", {
points: missingPoints,
2025-04-07 14:08:48 +02:00
level: firstUnlockable.l.name,
});
return `
2025-04-11 08:15:58 +02:00
<p>${t("score_panel.close_to_unlock")}</p>
2025-04-30 16:29:49 +02:00
<div class="upgrade">
2025-04-07 14:08:48 +02:00
${icons[firstUnlockable.l.name]}
<p>
<strong>${title}</strong>
${firstUnlockable.reason?.text}
</p>
</div>
`;
}