This commit is contained in:
Renan LE CARO 2025-03-20 21:02:51 +01:00
parent 3eca148fb8
commit 760fa5715b
16 changed files with 289 additions and 152 deletions

View file

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

View file

@ -46,7 +46,10 @@ export async function asyncAlert<t>({
closeModaleButton.style.display = allowClose ? "" : "none";
const popup = document.createElement("div");
let closed = false;
function closeWithResult(value: t | undefined) {
if (closed) return;
closed = true;
document.body.style.minHeight = document.body.scrollHeight + "px";
setTimeout(() => (document.body.style.minHeight = ""), 100);
popup.remove();
@ -137,7 +140,7 @@ ${icon}
function updateAlertsOpen(delta: number) {
alertsOpen += delta;
if (alertsOpen > 1) {
throw new Error("Cannot open two alerts at once");
alert("Two alerts where opened at once");
}
document.body.classList[alertsOpen ? "add" : "remove"]("has-alert-open");
}

View file

@ -939,5 +939,12 @@
"bricks": "WWW_____WWW_y___WWW____y__y_y____y____y_____y_____y____y___y_y__",
"svg": null,
"color": ""
},
{
"name": "icon:reach",
"size": 8,
"bricks": "_________yyyyyy__yyyyyy__yyyyyy__rrrrrr_______W____________WWW__",
"svg": null,
"color": ""
}
]

View file

@ -1 +1 @@
"29041544"
"29041682"

View file

@ -897,8 +897,3 @@ export function restart(params: RunParams) {
restart({});
fitSize();
tick();
// @ts-ignore
// window.stressTest= ()=>restart({level:'Shark',perks:{base_combo:100, pierce:10, multiball:8}})
window.stressTest = () =>
restart({ level: "Bird", perks: { sapper: 2, pierce: 10, multiball: 3 } });

View file

@ -15,6 +15,8 @@ import {
brickCenterX,
brickCenterY,
clamp,
countBricksAbove,
countBricksBelow,
currentLevelInfo,
distance2,
distanceBetween,
@ -367,6 +369,17 @@ export function explodeBrick(
gameState.perks.zen +
gameState.perks.unbounded;
if (gameState.perks.reach) {
if (
countBricksAbove(gameState, index) &&
!countBricksBelow(gameState, index)
) {
resetCombo(gameState, x, y);
} else {
gameState.combo += gameState.perks.reach;
}
}
if (!isExplosion) {
// color change
if (
@ -503,7 +516,7 @@ export async function setLevel(gameState: GameState, l: number) {
// Reset combo silently
const finalCombo = gameState.combo;
gameState.combo = baseCombo(gameState);
if (!gameState.perks.shunt) {
if (gameState.perks.shunt) {
gameState.combo += Math.round(
Math.max(
0,

View file

@ -148,3 +148,26 @@ export function shouldPierceByColor(
}
return true;
}
export function countBricksAbove(gameState: GameState, index: number) {
const col = index % gameState.gridSize;
const row = Math.floor(index / gameState.gridSize);
let count = 0;
for (let y = 0; y < row; y++) {
if (gameState.bricks[col + y * gameState.gridSize]) {
count++;
}
}
return count;
}
export function countBricksBelow(gameState: GameState, index: number) {
const col = index % gameState.gridSize;
const row = Math.floor(index / gameState.gridSize);
let count = 0;
for (let y = row + 1; y < gameState.gridSize; y++) {
if (gameState.bricks[col + y * gameState.gridSize]) {
count++;
}
}
return count;
}

View file

@ -2942,6 +2942,56 @@
</concept_node>
</children>
</folder_node>
<folder_node>
<name>reach</name>
<children>
<concept_node>
<name>fullHelp</name>
<description/>
<comment/>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-FR</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>help</name>
<description/>
<comment/>
<translations>
<translation>
<language>en-US</language>
<approved>true</approved>
</translation>
<translation>
<language>fr-FR</language>
<approved>true</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>name</name>
<description/>
<comment/>
<translations>
<translation>
<language>en-US</language>
<approved>true</approved>
</translation>
<translation>
<language>fr-FR</language>
<approved>true</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
<folder_node>
<name>respawn</name>
<children>

View file

@ -181,6 +181,9 @@
"upgrades.puck_repulse_ball.help": "Puck repulses balls",
"upgrades.puck_repulse_ball.help_plural": "Stronger repulsion force",
"upgrades.puck_repulse_ball.name": "Soft landing",
"upgrades.reach.fullHelp": "Try to lock the ball up to earn more combo",
"upgrades.reach.help": "+{{lvl}} combo / bricks , lowest brick of a pile resets combo",
"upgrades.reach.name": "Top down",
"upgrades.respawn.fullHelp": "After breaking two or more bricks, when the ball hits the puck, the first brick will be put back in place, provided that space is free and the brick wasn't a bomb.\n\nSome particle effect will let you know where bricks will appear. Leveling this up lets you re-spawn up to 4 bricks at a time, but there should always be at least one destroyed.",
"upgrades.respawn.help": "The first brick hit of two+ will re-spawn",
"upgrades.respawn.help_plural": "More bricks can re-spawn",

View file

@ -181,6 +181,9 @@
"upgrades.puck_repulse_ball.help": "Le palet repousse les balles",
"upgrades.puck_repulse_ball.help_plural": "La force de répulsion est plus grande",
"upgrades.puck_repulse_ball.name": "Atterrissage en douceur",
"upgrades.reach.fullHelp": "Essayez de bloquer la balle au dessus des briques pour plus de combo",
"upgrades.reach.help": "+{{lvl}} combo / brique, la plus basse d'une colonne RAZ le combo",
"upgrades.reach.name": "Attaque aérienne",
"upgrades.respawn.fullHelp": "Après avoir cassé deux briques ou plus, lorsque la balle touche le palet, la première brique est remise en place, à condition que l'espace soit libre et que la brique ne soit pas une bombe.\n\nDes effets de particules vous indiqueront où les briques apparaîtront. \n\nEn montant en niveau, vous pouvez faire réapparaître jusqu'à 4 briques à la fois, mais il doit toujours y en avoir au moins une qui reste détruite.",
"upgrades.respawn.help": "Certaines briques réapparaissent après avoir été détruites.",
"upgrades.respawn.help_plural": "Plus de briques peuvent réapparaître",

View file

@ -2,6 +2,8 @@ import { baseCombo, forEachLiveOne, liveCount } from "./gameStateMutators";
import {
brickCenterX,
brickCenterY,
countBricksAbove,
countBricksBelow,
currentLevelInfo,
isTelekinesisActive,
isYoyoActive,
@ -17,7 +19,6 @@ export const ctx = gameCanvas.getContext("2d", {
alpha: false,
}) as CanvasRenderingContext2D;
export const bombSVG = document.createElement("img");
bombSVG.src =
"data:image/svg+xml;base64," +
btoa(`<svg width="144" height="144" viewBox="0 0 38.101 38.099" xmlns="http://www.w3.org/2000/svg">
@ -150,13 +151,11 @@ export function render(gameState: GameState) {
Math.sin(Date.now() + 36) * amplitude,
);
}
if (gameState.perks.bigger_explosions && !isOptionOn("basic")) {
if (shaked) {
gameCanvas.style.filter =
"brightness(" + (1 + 100 / (1 + lastExplosionDelay)) + ")";
} else {
gameCanvas.style.filter = "";
}
if (gameState.perks.bigger_explosions && !isOptionOn("basic") && shaked) {
gameCanvas.style.filter =
"brightness(" + (1 + 100 / (1 + lastExplosionDelay)) + ")";
} else {
gameCanvas.style.filter = "";
}
// Coins
ctx.globalAlpha = 1;
@ -417,14 +416,18 @@ export function renderAllBricks() {
if (!color) return;
const borderColor =
let redBecauseOfReach =
gameState.perks.reach &&
countBricksAbove(gameState, index) &&
!countBricksBelow(gameState, index);
let redBorder =
(gameState.ballsColor !== color &&
color !== "black" &&
redBorderOnBricksWithWrongColor &&
"red") ||
color;
redBorderOnBricksWithWrongColor) ||
redBecauseOfReach;
drawBrick(canctx, color, (redBorder && "red") || color, x, y);
drawBrick(canctx, color, borderColor, x, y);
if (color === "black") {
canctx.globalCompositeOperation = "source-over";
drawIMG(canctx, bombSVG, gameState.brickWidth, x, y);

View file

@ -553,4 +553,15 @@ export const rawUpgrades = [
help: (lvl: number) => t("upgrades.ball_attracts_coins.help"),
fullHelp: t("upgrades.ball_attracts_coins.fullHelp"),
},
{
requires: "",
rejects: "",
threshold: 135000,
giftable: false,
id: "reach",
max: 3,
name: t("upgrades.reach.name"),
help: (lvl: number) => t("upgrades.reach.help", { lvl }),
fullHelp: t("upgrades.reach.fullHelp"),
},
] as const;