This commit is contained in:
Renan LE CARO 2025-03-20 18:44:46 +01:00
parent e8621614ee
commit 5e4faf2878
14 changed files with 423 additions and 274 deletions

View file

@ -1,5 +1,5 @@
// The version of the cache.
const VERSION = "29040298";
const VERSION = "29041544";
// The name of the cache
const CACHE_NAME = `breakout-71-${VERSION}`;

View file

@ -12,7 +12,20 @@ export type AsyncAlertAction<t> = {
className?: string;
};
export function asyncAlert<t>({
const popupWrap = document.getElementById("popup") as HTMLDivElement;
const closeModaleButton = document.getElementById(
"close-modale",
) as HTMLButtonElement;
closeModaleButton.addEventListener("click", (e) => {
e.preventDefault();
if (closeModal) closeModal();
});
closeModaleButton.title = t("play.close_modale_window_tooltip");
let lastClickedItemIndex = -1;
export async function asyncAlert<t>({
title,
text,
actions,
@ -27,36 +40,27 @@ export function asyncAlert<t>({
allowClose?: boolean;
actionsAsGrid?: boolean;
}): Promise<t | void> {
alertsOpen++;
updateAlertsOpen(+1);
return new Promise((resolve) => {
const popupWrap = document.createElement("div");
document.body.appendChild(popupWrap);
popupWrap.className = "popup " + (actionsAsGrid ? "actionsAsGrid " : "");
popupWrap.className = actionsAsGrid ? " " : "";
closeModaleButton.style.display = allowClose ? "" : "none";
const popup = document.createElement("div");
function closeWithResult(value: t | undefined) {
document.body.style.minHeight = document.body.scrollHeight + "px";
setTimeout(() => (document.body.style.minHeight = ""), 100);
popup.remove();
resolve(value);
// Doing this async lets the menu scroll persist if it's shown a second time
setTimeout(() => {
document.body.removeChild(popupWrap);
});
}
if (allowClose) {
const closeButton = document.createElement("button");
closeButton.title = t("play.close_modale_window_tooltip");
closeButton.className = "close-modale";
closeButton.addEventListener("click", (e) => {
e.preventDefault();
closeWithResult(undefined);
});
closeModal = () => {
closeWithResult(undefined);
};
popupWrap.appendChild(closeButton);
} else {
closeModal = null;
}
const popup = document.createElement("div");
if (title) {
const p = document.createElement("h2");
p.innerHTML = title;
@ -70,32 +74,39 @@ export function asyncAlert<t>({
}
const buttons = document.createElement("section");
buttons.className = "actions";
popup.appendChild(buttons);
actions
?.filter((i) => i)
.forEach(({ text, value, help, disabled, className = "", icon = "" }) => {
const button = document.createElement("button");
.forEach(
({ text, value, help, disabled, className = "", icon = "" }, index) => {
const button = document.createElement("button");
button.innerHTML = `
button.innerHTML = `
${icon}
<div>
<strong>${text}</strong>
<em>${help || ""}</em>
</div>`;
if (disabled) {
button.setAttribute("disabled", "disabled");
} else {
button.addEventListener("click", (e) => {
e.preventDefault();
closeWithResult(value);
});
}
button.className = className;
buttons.appendChild(button);
});
if (disabled) {
button.setAttribute("disabled", "disabled");
} else {
button.addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
closeWithResult(value);
// Focus "same" button if it's still there
lastClickedItemIndex = index;
});
}
button.className =
className + (lastClickedItemIndex === index ? " needs-focus" : "");
buttons.appendChild(button);
},
);
if (textAfterButtons) {
const p = document.createElement("div");
p.className = "textAfterButtons";
@ -105,17 +116,28 @@ ${icon}
popupWrap.appendChild(popup);
(
popup.querySelector("button:not([disabled])") as HTMLButtonElement
popupWrap.querySelector(
`section.actions > button.needs-focus`,
) as HTMLButtonElement
)?.focus();
lastClickedItemIndex = -1;
}).then(
(v: unknown) => {
alertsOpen--;
updateAlertsOpen(-1);
closeModal = null;
return v as t | undefined;
},
() => {
closeModal = null;
alertsOpen--;
updateAlertsOpen(-1);
},
);
}
function updateAlertsOpen(delta: number) {
alertsOpen += delta;
if (alertsOpen > 1) {
throw new Error("Cannot open two alerts at once");
}
document.body.classList[alertsOpen ? "add" : "remove"]("has-alert-open");
}

View file

@ -1 +1 @@
"29040298"
"29041544"

View file

@ -23,7 +23,7 @@ body {
}
#game {
position: absolute;
position: fixed;
top: 0;
left: 0;
height: 100vh;
@ -66,16 +66,29 @@ body {
#menu {
left: 0;
}
body.has-alert-open {
height: auto;
overflow: visible;
}
body:not(.has-alert-open) #popup {
display: none;
}
#popup {
&::before {
z-index: 10;
content: "";
display: block;
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.9);
}
.popup {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.9);
z-index: 10;
display: flex;
overflow: auto;
& > div {
z-index: 11;
position: relative;
margin: auto;
padding: 20px 10px;
transform-origin: center;
@ -157,7 +170,7 @@ body {
}
}
button.close-modale {
button#close-modale {
color: white;
position: absolute;
top: 0;
@ -168,6 +181,7 @@ body {
border: none;
cursor: pointer;
overflow: hidden;
z-index: 11;
&:before {
content: "+";
@ -259,13 +273,6 @@ body {
margin: 20px auto;
}
}
@media (min-width: 1200px) {
position: absolute;
top: 40px;
left: 40px;
max-width: calc((100vw - 450px) / 2 - 80px);
}
}
.histogram {

View file

@ -61,7 +61,8 @@ export function play() {
startRecordingGame(gameState);
getAudioContext()?.resume();
resumeRecording();
document.body.className = gameState.running ? " running " : " paused ";
// document.body.classList[gameState.running ? 'add' : 'remove']('running')
}
export function pause(playerAskedForPause: boolean) {
@ -78,7 +79,7 @@ export function pause(playerAskedForPause: boolean) {
pauseRecording();
gameState.pauseTimeout = null;
document.body.className = gameState.running ? " running " : " paused ";
// document.body.className = gameState.running ? " running " : " paused ";
scoreDisplay.className = "";
gameState.needsRender = true;
},
@ -373,7 +374,9 @@ window.addEventListener("visibilitychange", () => {
scoreDisplay.addEventListener("click", (e) => {
e.preventDefault();
openScorePanel();
if (!alertsOpen) {
openScorePanel();
}
});
document.addEventListener("visibilitychange", () => {
@ -420,7 +423,9 @@ async function openScorePanel() {
"click",
(e) => {
e.preventDefault();
openSettingsPanel();
if (!alertsOpen) {
openSettingsPanel();
}
},
);

View file

@ -501,10 +501,15 @@ export async function setLevel(gameState: GameState, l: number) {
gameState.runStatistics.levelsPlayed++;
// Reset combo silently
const finalCombo=gameState.combo
const finalCombo = gameState.combo;
gameState.combo = baseCombo(gameState);
if (!gameState.perks.shunt) {
gameState.combo += Math.round(Math.max(0,(finalCombo-gameState.combo)*25*gameState.perks.shunt/100))
gameState.combo += Math.round(
Math.max(
0,
((finalCombo - gameState.combo) * 25 * gameState.perks.shunt) / 100,
),
);
}
gameState.combo += gameState.perks.hot_start * 15;
@ -1225,6 +1230,14 @@ export function ballTick(gameState: GameState, ball: Ball, delta: number) {
if (gameState.perks.top_is_lava && borderHitCode >= 2) {
resetCombo(gameState, ball.x, ball.y + gameState.ballSize);
}
if (gameState.perks.trampoline && borderHitCode >= 2) {
decreaseCombo(
gameState,
gameState.perks.trampoline,
ball.x,
ball.y + gameState.ballSize,
);
}
schedulGameSound(gameState, "wallBeep", ball.x, 1);
gameState.levelWallBounces++;

View file

@ -230,7 +230,7 @@
"upgrades.top_is_lava.help": "More coins if you don't touch the top.",
"upgrades.top_is_lava.name": "Sky is the limit",
"upgrades.trampoline.fullHelp": "One of the rare combo upgrades that don't add a reset condition",
"upgrades.trampoline.help": "+{{lvl}} combo per puck bounce",
"upgrades.trampoline.help": "+{{lvl}} combo per puck bounce,-{{lvl}} combo per ceiling bounce",
"upgrades.trampoline.name": "Trampoline",
"upgrades.unbounded.fullHelp": "I hope you've found a way to keep your ball on screen",
"upgrades.unbounded.help": "+1 combo per brick, no more sides",

View file

@ -230,7 +230,7 @@
"upgrades.top_is_lava.help": "Plus de pièces si vous ne touchez pas le haut de la zone de jeu",
"upgrades.top_is_lava.name": "Icare ",
"upgrades.trampoline.fullHelp": "Une des rares améliorations à ne pas avoir de condition de remise à zéro",
"upgrades.trampoline.help": "+{{lvl}} combo à chaque rebond d'une balle sur le palet",
"upgrades.trampoline.help": "+{{lvl}} combo à chaque rebond d'une balle sur le palet,-{{lvl}} combo à chaque rebond au plafond",
"upgrades.trampoline.name": "Trampoline",
"upgrades.unbounded.fullHelp": "J'espère que vous avez prévu un moyen de récupérer vos balles",
"upgrades.unbounded.help": "+1 combo par brique, plus de cotés",

View file

@ -23,6 +23,9 @@
<button id="menu"><span id="menuLabel">menu</span></button>
<button id="score"></button>
<canvas id="game"></canvas>
<div id="popup">
<button id="close-modale"></button>
</div>
<script type="module">
import "./game.ts";
</script>

View file

@ -3,6 +3,7 @@ import { t } from "./i18n/i18n";
export const rawUpgrades = [
{
requires: "",
rejects: "",
threshold: 0,
giftable: false,
id: "extra_life",
@ -16,6 +17,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 0,
id: "streak_shots",
giftable: true,
@ -27,6 +29,7 @@ export const rawUpgrades = [
{
requires: "",
rejects: "",
threshold: 0,
id: "base_combo",
giftable: true,
@ -38,6 +41,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 0,
giftable: false,
id: "slow_down",
@ -48,6 +52,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 0,
giftable: false,
id: "bigger_puck",
@ -58,6 +63,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 0,
giftable: false,
id: "viscosity",
@ -69,6 +75,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 0,
id: "left_is_lava",
giftable: true,
@ -80,6 +87,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 0,
id: "right_is_lava",
giftable: true,
@ -90,6 +98,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 0,
id: "top_is_lava",
giftable: true,
@ -100,6 +109,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 0,
giftable: false,
id: "skip_last",
@ -113,6 +123,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 500,
id: "telekinesis",
giftable: true,
@ -126,6 +137,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 1000,
giftable: false,
id: "coin_magnet",
@ -139,6 +151,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 1500,
id: "multiball",
giftable: true,
@ -149,6 +162,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 2000,
giftable: false,
id: "smaller_puck",
@ -162,6 +176,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 3000,
id: "pierce",
giftable: true,
@ -172,6 +187,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 4000,
id: "picky_eater",
giftable: true,
@ -182,6 +198,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 5000,
giftable: false,
id: "metamorphosis",
@ -192,6 +209,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 6000,
id: "compound_interest",
giftable: true,
@ -202,6 +220,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 7000,
id: "hot_start",
giftable: true,
@ -216,6 +235,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 9000,
id: "sapper",
giftable: true,
@ -229,6 +249,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 11000,
id: "bigger_explosions",
giftable: false,
@ -239,6 +260,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 13000,
giftable: false,
id: "extra_levels",
@ -249,6 +271,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 15000,
giftable: false,
id: "pierce_color",
@ -259,6 +282,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 18000,
giftable: false,
id: "soft_reset",
@ -295,6 +319,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 30000,
giftable: false,
id: "puck_repulse_ball",
@ -308,6 +333,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 35000,
giftable: false,
id: "wind",
@ -319,6 +345,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 40000,
giftable: false,
id: "sturdy_bricks",
@ -332,6 +359,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 45000,
giftable: false,
id: "respawn",
@ -343,6 +371,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 50000,
giftable: false,
id: "one_more_choice",
@ -353,6 +382,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 55000,
giftable: false,
id: "instant_upgrade",
@ -363,6 +393,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 60000,
giftable: false,
id: "concave_puck",
@ -373,6 +404,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 65000,
giftable: false,
id: "helium",
@ -383,6 +415,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 70000,
giftable: false,
id: "asceticism",
@ -393,6 +426,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 75000,
giftable: false,
id: "unbounded",
@ -403,16 +437,18 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 80000,
giftable: false,
id: "shunt",
max: 3,
name: t("upgrades.shunt.name"),
help: (lvl: number) => t("upgrades.shunt.help",{percent:lvl*25}),
help: (lvl: number) => t("upgrades.shunt.help", { percent: lvl * 25 }),
fullHelp: t("upgrades.shunt.fullHelp"),
},
{
requires: "",
rejects: "",
threshold: 85000,
giftable: false,
id: "yoyo",
@ -423,6 +459,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 90000,
giftable: false,
id: "nbricks",
@ -433,6 +470,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 95000,
giftable: false,
id: "etherealcoins",
@ -453,6 +491,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 105000,
giftable: false,
id: "zen",
@ -484,6 +523,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 120000,
giftable: false,
id: "ghost_coins",
@ -504,6 +544,7 @@ export const rawUpgrades = [
},
{
requires: "",
rejects: "",
threshold: 130000,
giftable: false,
id: "ball_attracts_coins",