Build 29058943

This commit is contained in:
Renan LE CARO 2025-04-01 21:43:36 +02:00
parent 9958717260
commit b7b4879e6d
15 changed files with 123 additions and 72 deletions

View file

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

View file

@ -4,7 +4,7 @@ import { t } from "./i18n/i18n";
import { getSettingValue, getTotalScore, setSettingValue } from "./settings";
import { confirmRestart, creativeModeThreshold, restart } from "./game";
import { requiredAsyncAlert } from "./asyncAlert";
import {describeLevel, highScoreForMode, sumOfValues} from "./game_utils";
import { describeLevel, highScoreForMode, sumOfValues } from "./game_utils";
export function creativeMode(gameState: GameState) {
return {
@ -34,7 +34,7 @@ export async function openCreativeModePerksPicker(
"creativeModePerks_" + currentLevel,
{},
),
choice: Upgrade | Level | 'reset'| void;
choice: Upgrade | Level | "reset" | void;
upgrades.forEach((u) => {
creativeModePerks[u.id] = Math.min(
@ -51,15 +51,15 @@ export async function openCreativeModePerksPicker(
];
while (
(choice = await requiredAsyncAlert<Upgrade | Level|'reset'>({
(choice = await requiredAsyncAlert<Upgrade | Level | "reset">({
title: t("lab.title", { lvl: currentLevel + 1 }),
actionsAsGrid: true,
content: [
t("lab.instructions"),
{
value:'reset',
text:t('lab.reset'),
disabled: !sumOfValues(creativeModePerks)
value: "reset",
text: t("lab.reset"),
disabled: !sumOfValues(creativeModePerks),
},
...upgrades
.filter((u) => !noCreative.includes(u.id))
@ -87,11 +87,11 @@ export async function openCreativeModePerksPicker(
],
}))
) {
if(choice==='reset'){
upgrades.forEach((u) => {
creativeModePerks[u.id]=0
if (choice === "reset") {
upgrades.forEach((u) => {
creativeModePerks[u.id] = 0;
});
}else if ("bricks" in choice) {
} else if ("bricks" in choice) {
setSettingValue("creativeModePerks_" + currentLevel, creativeModePerks);
upgrades.forEach((u) => {
gameState.perks[u.id] = creativeModePerks[u.id];

View file

@ -1122,4 +1122,4 @@
"svg": null,
"color": ""
}
]
]

View file

@ -1 +1 @@
"29058753"
"29058943"

View file

@ -21,11 +21,13 @@ import {
distanceBetween,
getMajorityValue,
getPossibleUpgrades,
getRowColIndex, isPickyEatingPossible,
getRowColIndex,
isPickyEatingPossible,
isTelekinesisActive,
isYoyoActive,
makeEmptyPerksMap,
max_levels, reachRedRowIndex,
max_levels,
reachRedRowIndex,
shouldPierceByColor,
} from "./game_utils";
import { t } from "./i18n/i18n";
@ -344,8 +346,9 @@ export function explodeBrick(
const color = gameState.bricks[index];
if (!color) return;
const wasPickyEaterPossible = gameState.perks.picky_eater&& isPickyEatingPossible(gameState)
const redRowReach=reachRedRowIndex(gameState)
const wasPickyEaterPossible =
gameState.perks.picky_eater && isPickyEatingPossible(gameState);
const redRowReach = reachRedRowIndex(gameState);
gameState.lastBrickBroken = gameState.levelTime;
@ -437,18 +440,17 @@ export function explodeBrick(
}
}
if(redRowReach!==-1){
if(Math.floor(index/gameState.level.size)===redRowReach ) {
if (redRowReach !== -1) {
if (Math.floor(index / gameState.level.size) === redRowReach) {
resetCombo(gameState, x, y);
}else{
for(let x=0;x<gameState.level.size;x++){
if(gameState.bricks[redRowReach * gameState.level.size+ x])gameState.combo++
} else {
for (let x = 0; x < gameState.level.size; x++) {
if (gameState.bricks[redRowReach * gameState.level.size + x])
gameState.combo++;
}
}
}
if (
gameState.lastPuckMove &&
gameState.perks.passive_income &&
@ -473,7 +475,7 @@ export function explodeBrick(
color !== gameState.ballsColor &&
color
) {
if ( wasPickyEaterPossible) {
if (wasPickyEaterPossible) {
resetCombo(gameState, ball.x, ball.y);
}
schedulGameSound(gameState, "colorChange", ball.x, 0.8);
@ -1675,17 +1677,19 @@ export function ballTick(gameState: GameState, ball: Ball, delta: number) {
if (!isOptionOn("basic")) {
const remainingPierce = ball.piercePoints;
const remainingSapper = ball.sapperUses < gameState.perks.sapper;
const willMiss =
isOptionOn("red_miss") && ball.vy > 0 && !ball.hitSinceBounce;
const extraCombo = gameState.combo - 1;
if (
willMiss ||
(extraCombo && Math.random() > 0.1 / (1 + extraCombo)) ||
(remainingSapper && Math.random() > 0.1 / (1 + remainingSapper)) ||
(extraCombo && Math.random() > 0.1 / (1 + extraCombo))
) {
const color = remainingSapper
? Math.random() > 0.5
? "orange"
: "red"
: gameState.ballsColor;
const color =
(remainingSapper && (Math.random() > 0.5 ? "orange" : "red")) ||
(willMiss && "red") ||
gameState.ballsColor;
makeParticle(
gameState,

View file

@ -1,7 +1,7 @@
import { Ball, GameState, Level, PerkId, PerksMap } from "./types";
import { icons, upgrades } from "./loadGameData";
import { t } from "./i18n/i18n";
import {brickAt} from "./level_editor/levels_editor_util";
import { brickAt } from "./level_editor/levels_editor_util";
export function describeLevel(level: Level) {
let bricks = 0,
@ -132,29 +132,31 @@ export function currentLevelInfo(gameState: GameState) {
return gameState.level;
}
export function isPickyEatingPossible(gameState: GameState){
return gameState.bricks.indexOf(gameState.ballsColor)!==-1
export function isPickyEatingPossible(gameState: GameState) {
return gameState.bricks.indexOf(gameState.ballsColor) !== -1;
}
export function reachRedRowIndex(gameState: GameState){
if(!gameState.perks.reach) return -1
const {size}=gameState.level
let minY=-1, maxY=-1, maxYCount=-1;
for(let y=0;y<size;y++)
for(let x=0;x<size;x++)
if(gameState.bricks[x+y*size]){
if(minY==-1) minY=y
if(maxY<y) {
maxY = y
maxYCount = 0
export function reachRedRowIndex(gameState: GameState) {
if (!gameState.perks.reach) return -1;
const { size } = gameState.level;
let minY = -1,
maxY = -1,
maxYCount = -1;
for (let y = 0; y < size; y++)
for (let x = 0; x < size; x++)
if (gameState.bricks[x + y * size]) {
if (minY == -1) minY = y;
if (maxY < y) {
maxY = y;
maxYCount = 0;
}
if (maxY == y) maxYCount++;
}
if(maxY==y) maxYCount++
}
if(maxY<1) return -1
if(maxY==minY) return -1
if(maxYCount===size) return -1
return maxY
if (maxY < 1) return -1;
if (maxY == minY) return -1;
if (maxYCount === size) return -1;
return maxY;
}
export function isTelekinesisActive(gameState: GameState, ball: Ball) {

View file

@ -1447,6 +1447,36 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>red_miss</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>red_miss_help</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>reset</name>
<description/>

View file

@ -91,6 +91,8 @@
"main_menu.record": "Record gameplay videos",
"main_menu.record_download": "Download video ({{size}} MB)",
"main_menu.record_help": "Get a video of each level.",
"main_menu.red_miss": "Miss warning",
"main_menu.red_miss_help": "Show red particles around balls going down without a hit.",
"main_menu.reset": "Reset Game",
"main_menu.reset_cancel": "No",
"main_menu.reset_confirm": "Yes",

View file

@ -91,6 +91,8 @@
"main_menu.record": "Enregistrer des vidéos de jeu",
"main_menu.record_download": "Télécharger la vidéo ({{size}} MB)",
"main_menu.record_help": "Obtenez une vidéo de chaque niveau.",
"main_menu.red_miss": "Balles ratées",
"main_menu.red_miss_help": "Afficher des particules rouges autours des balles qui redescendent sans avoir touché une brique.",
"main_menu.reset": "Réinitialiser le jeu",
"main_menu.reset_cancel": "Non",
"main_menu.reset_confirm": "Oui",

View file

@ -61,6 +61,11 @@ export const options = {
name: t("main_menu.donation_reminder"),
help: t("main_menu.donation_reminder_help"),
},
red_miss: {
default: false,
name: t("main_menu.red_miss"),
help: t("main_menu.red_miss_help"),
},
} as const satisfies { [k: string]: OptionDef };
export function isOptionOn(key: OptionId) {

View file

@ -4,10 +4,12 @@ import {
brickCenterY,
// countBricksAbove,
// countBricksBelow,
currentLevelInfo, isPickyEatingPossible,
currentLevelInfo,
isPickyEatingPossible,
isTelekinesisActive,
isYoyoActive,
max_levels, reachRedRowIndex,
max_levels,
reachRedRowIndex,
} from "./game_utils";
import { colorString, GameState } from "./types";
import { t } from "./i18n/i18n";
@ -547,9 +549,8 @@ export function renderAllBricks() {
const hasCombo = gameState.combo > baseCombo(gameState);
const redBorderOnBricksWithWrongColor =
hasCombo && gameState.perks.picky_eater && isPickyEatingPossible(gameState);
hasCombo && gameState.perks.picky_eater && isPickyEatingPossible(gameState);
console.log('redBorderOnBricksWithWrongColor '+redBorderOnBricksWithWrongColor)
const redColorOnAllBricks = !!(
gameState.lastPuckMove &&
gameState.perks.passive_income &&
@ -558,14 +559,14 @@ export function renderAllBricks() {
gameState.levelTime - 250 * gameState.perks.passive_income
);
const redRowReach= reachRedRowIndex(gameState)
const redRowReach = reachRedRowIndex(gameState);
let offset = getDashOffset(gameState);
if (
!(
redBorderOnBricksWithWrongColor ||
redColorOnAllBricks ||
redRowReach!==-1 ||
redRowReach !== -1 ||
gameState.perks.zen
)
) {
@ -575,14 +576,13 @@ export function renderAllBricks() {
const clairVoyance =
gameState.perks.clairvoyant && gameState.brickHP.reduce((a, b) => a + b, 0);
const newKey =
gameState.gameZoneWidth +
"_" +
gameState.bricks.join("_") +
bombSVG.complete +
"_" +
redRowReach+
redRowReach +
"_" +
redBorderOnBricksWithWrongColor +
"_" +
@ -614,7 +614,8 @@ export function renderAllBricks() {
if (!color) return;
let redBecauseOfReach = redRowReach===Math.floor(index/gameState.level.size) ;
let redBecauseOfReach =
redRowReach === Math.floor(index / gameState.level.size);
let redBorder =
(gameState.ballsColor !== color &&