This commit is contained in:
Renan LE CARO 2025-03-29 21:28:05 +01:00
parent a4e24fd397
commit 27a2cd686e
16 changed files with 3396 additions and 3332 deletions

View file

@ -11,8 +11,8 @@ android {
applicationId = "me.lecaro.breakout"
minSdk = 21
targetSdk = 34
versionCode = 29053158
versionName = "29053158"
versionCode = 29054664
versionName = "29054664"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true

File diff suppressed because one or more lines are too long

36
dist/index.html vendored
View file

@ -899,10 +899,10 @@ async function openScorePanel() {
gameState.isCreativeModeRun ? `<p>${(0, _i18N.t)("score_panel.test_run")}</p>` : "",
(0, _gameUtils.pickedUpgradesHTMl)(gameState),
(0, _gameUtils.levelsListHTMl)(gameState),
gameState.rerolls ? (0, _i18N.t)('score_panel.rerolls_count', {
gameState.rerolls ? (0, _i18N.t)("score_panel.rerolls_count", {
rerolls: gameState.rerolls
}) : '',
banned && (0, _i18N.t)('score_panel.banned', {
}) : "",
banned && (0, _i18N.t)("score_panel.banned", {
banned
})
],
@ -1293,7 +1293,7 @@ function setKeyPressed(key, on) {
}
document.addEventListener("keydown", (e)=>{
if (e.key.toLowerCase() === "f" && !e.ctrlKey && !e.metaKey) {
(0, _options.toggleOption)('fullscreen');
(0, _options.toggleOption)("fullscreen");
applyFullScreenChoice();
} else if (e.key in pressed) setKeyPressed(e.key, 1);
if (e.key === " " && !(0, _asyncAlert.alertsOpen)) {
@ -1385,7 +1385,7 @@ const upgrades = (0, _upgrades.rawUpgrades).map((u)=>({
}));
},{"./data/palette.json":"ktRBU","./data/levels.json":"8JSUc","./data/version.json":"iyP6E","./upgrades":"1u3Dx","./getLevelBackground":"7OIPf","./levelIcon":"6rQoT","@parcel/transformer-js/src/esmodule-helpers.js":"gkKU3"}],"iyP6E":[function(require,module,exports,__globalThis) {
module.exports = JSON.parse("\"29053158\"");
module.exports = JSON.parse("\"29054664\"");
},{}],"1u3Dx":[function(require,module,exports,__globalThis) {
var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js");
@ -2901,7 +2901,7 @@ async function gotoNextLoop(gameState) {
content: [
(0, _i18N.t)("loop.instructions"),
comboText,
...userPerks.filter((u)=>u.id !== 'instant_upgrade').map((u)=>{
...userPerks.filter((u)=>u.id !== "instant_upgrade").map((u)=>{
return {
text: u.name + (0, _i18N.t)("level_up.upgrade_perk_to_level", {
level: gameState.perks[u.id] + 1
@ -3538,24 +3538,24 @@ function render(gameState) {
else menuLabel.innerText = (0, _i18N.t)("play.menu_label");
const catchRate = gameState.levelSpawnedCoins ? (gameState.levelSpawnedCoins - gameState.levelLostCoins) / gameState.levelSpawnedCoins : 1;
scoreDisplay.innerHTML = ((0, _options.isOptionOn)("show_fps") ? `
<span class="${Math.abs((0, _game.lastMeasuredFPS) - 60) < 2 && ' ' || Math.abs((0, _game.lastMeasuredFPS) - 60) < 10 && 'good' || 'bad'}">
<span class="${Math.abs((0, _game.lastMeasuredFPS) - 60) < 2 && " " || Math.abs((0, _game.lastMeasuredFPS) - 60) < 10 && "good" || "bad"}">
${0, _game.lastMeasuredFPS} FPS
</span><span> / </span>
` : '') + ((0, _options.isOptionOn)('show_stats') ? `
<span class="${catchRate == 1 && 'great' || catchRate > 0.9 && 'good' || ''}">
` : "") + ((0, _options.isOptionOn)("show_stats") ? `
<span class="${catchRate == 1 && "great" || catchRate > 0.9 && "good" || ""}">
${Math.floor(catchRate * 100)}%
</span><span> / </span>
<span class="${gameState.levelWallBounces == 0 && 'great' || gameState.levelWallBounces < 5 && 'good' || ''}">
<span class="${gameState.levelWallBounces == 0 && "great" || gameState.levelWallBounces < 5 && "good" || ""}">
${gameState.levelWallBounces} B
</span><span> / </span>
<span class="${gameState.levelTime < 30000 && 'great' || gameState.levelTime < 60000 && 'good' || ''}">
<span class="${gameState.levelTime < 30000 && "great" || gameState.levelTime < 60000 && "good" || ""}">
${Math.ceil(gameState.levelTime / 1000)}s
</span><span> / </span>
<span class="${gameState.levelMisses == 0 && 'great' || gameState.levelMisses <= 3 && 'good' || ''}">
<span class="${gameState.levelMisses == 0 && "great" || gameState.levelMisses <= 3 && "good" || ""}">
${gameState.levelMisses} M
</span><span> / </span>
` : '') + `$${gameState.score}`;
` : "") + `$${gameState.score}`;
scoreDisplay.className = gameState.lastScoreIncrease > gameState.levelTime - 500 ? "active" : "";
// Clear
if (!(0, _options.isOptionOn)("basic") && !level.color && level.svg) {
@ -3602,14 +3602,14 @@ function render(gameState) {
bgctx.fillStyle = level.color || "#000";
bgctx.fillRect(0, 0, gameState.canvasWidth, gameState.canvasHeight);
if (gameState.perks.clairvoyant >= 3) {
const pageSource = document.body.innerHTML.replace(/\s+/gi, '');
const pageSource = document.body.innerHTML.replace(/\s+/gi, "");
const lineWidth = Math.ceil(gameState.canvasWidth / 15);
const lines = Math.ceil(gameState.canvasHeight / 20);
const chars = lineWidth * lines;
let start = Math.ceil(Math.random() * (pageSource.length - chars));
for(let i = 0; i < lines; i++){
bgctx.fillStyle = 'white';
bgctx.font = '20px Courier';
bgctx.fillStyle = "white";
bgctx.font = "20px Courier";
bgctx.fillText(pageSource.slice(start + i * lineWidth, start + (i + 1) * lineWidth), 0, i * 20, gameState.canvasWidth);
}
} else {
@ -3654,7 +3654,7 @@ function render(gameState) {
ctx.globalCompositeOperation = "source-over";
// ctx.globalCompositeOperation =
// coin.color === "gold" || level.color ? "source-over" : "screen";
drawCoin(ctx, coin.color, coin.size, coin.x, coin.y, hasCombo && gameState.perks.asceticism && "red" || coin.color === 'gold' && 'gold' || gameState.puckColor, coin.a);
drawCoin(ctx, coin.color, coin.size, coin.x, coin.y, hasCombo && gameState.perks.asceticism && "red" || coin.color === "gold" && "gold" || gameState.puckColor, coin.a);
});
// Black shadow around balls
if (!(0, _options.isOptionOn)("basic")) {
@ -3928,7 +3928,7 @@ function drawBrick(ctx, color, x, y, offset = 0, borderOnly) {
const brx = Math.ceil(x + (0, _game.gameState).brickWidth / 2) - 1;
const bry = Math.ceil(y + (0, _game.gameState).brickWidth / 2) - 1;
const width = brx - tlx, height = bry - tly;
const key = "brick" + color + "_" + "_" + width + "_" + height + "_" + offset + '_' + borderOnly;
const key = "brick" + color + "_" + "_" + width + "_" + height + "_" + offset + "_" + borderOnly;
if (!cachedGraphics[key]) {
const can = document.createElement("canvas");
can.width = width;

View file

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

View file

@ -82,7 +82,7 @@ export async function asyncAlert<t>({
content
?.filter((i) => i)
.forEach((entry, index) => {
if(!entry) return;
if (!entry) return;
if (typeof entry == "string") {
const p = document.createElement("div");
p.innerHTML = entry;

View file

@ -1 +1 @@
"29053158"
"29054664"

View file

@ -1,9 +1,10 @@
* {
font-family: Courier New,
Courier,
Lucida Sans Typewriter,
Lucida Typewriter,
monospace;
font-family:
Courier New,
Courier,
Lucida Sans Typewriter,
Lucida Typewriter,
monospace;
box-sizing: border-box;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
import {Ball, GameState, PerkId, PerksMap} from "./types";
import {icons, upgrades} from "./loadGameData";
import {t} from "./i18n/i18n";
import { Ball, GameState, PerkId, PerksMap } from "./types";
import { icons, upgrades } from "./loadGameData";
import { t } from "./i18n/i18n";
export function getMajorityValue(arr: string[]): string {
const count: { [k: string]: number } = {};
@ -14,10 +14,8 @@ export function sample<T>(arr: T[]): T {
return arr[Math.floor(arr.length * Math.random())];
}
export function sampleN<T>(arr: T[],n:number): T[] {
return [...arr].sort(()=>Math.random()-0.5)
.slice(0,n)
export function sampleN<T>(arr: T[], n: number): T[] {
return [...arr].sort(() => Math.random() - 0.5).slice(0, n);
}
export function sumOfValues(obj: { [key: string]: number } | undefined | null) {
@ -55,7 +53,10 @@ export function getRowColIndex(gameState: GameState, row: number, col: number) {
export function getPossibleUpgrades(gameState: GameState) {
return upgrades
.filter((u) => gameState.totalScoreAtRunStart >= u.threshold || gameState.loop>0)
.filter(
(u) =>
gameState.totalScoreAtRunStart >= u.threshold || gameState.loop > 0,
)
.filter((u) => !u?.requires || gameState.perks[u?.requires]);
}
@ -186,4 +187,3 @@ export function countBricksBelow(gameState: GameState, index: number) {
}
return count;
}

View file

@ -1,4 +1,4 @@
import { GameState, RunParams } from "./types";
import { GameState, RunParams } from "./types";
import { getTotalScore } from "./settings";
import { allLevels, upgrades } from "./loadGameData";
import {
@ -129,5 +129,3 @@ export function newGameState(params: RunParams): GameState {
}
return gameState;
}

View file

@ -115,7 +115,6 @@ export function premiumMenuEntry(gameState: GameState) {
text = t("premium.per_hours", args);
help = t("premium.per_hours_help", args);
}
}
} catch (e) {
console.warn(e);

View file

@ -1,7 +1,7 @@
export function clamp(value: number, min: number, max: number) {
return Math.max(min, Math.min(value, max));
return Math.max(min, Math.min(value, max));
}
export function comboKeepingRate(level: number) {
return clamp(1 - 1 / (1 + level) * 1.5, 0, 1)
return clamp(1 - (1 / (1 + level)) * 1.5, 0, 1);
}

File diff suppressed because it is too large Load diff

14
src/types.d.ts vendored
View file

@ -83,7 +83,7 @@ export type Coin = {
weight: number;
destroyed?: boolean;
collidedLastFrame?: boolean;
metamorphosisPoints:number;
metamorphosisPoints: number;
};
export type Ball = {
x: number;
@ -238,8 +238,12 @@ export type GameState = {
coins: ReusableArray<Coin>;
// Bricks that should respawn destroyed
respawns: ReusableArray<{ index: number; color: string ; time:number;
destroyed?: boolean;}>;
respawns: ReusableArray<{
index: number;
color: string;
time: number;
destroyed?: boolean;
}>;
levelStartScore: number;
levelMisses: number;
@ -280,14 +284,14 @@ export type GameState = {
rerolls: number;
loop: number;
baseCombo: number;
levelsPerLoop:number;
levelsPerLoop: number;
};
export type RunParams = {
level?: string;
levelToAvoid?: string;
perks?: Partial<PerksMap>;
levelsPerLoop?:number;
levelsPerLoop?: number;
};
export type OptionDef = {
default: boolean;

View file

@ -1,6 +1,6 @@
import { t } from "./i18n/i18n";
import {comboKeepingRate} from "./pure_functions";
import { comboKeepingRate } from "./pure_functions";
export const rawUpgrades = [
{
@ -49,7 +49,7 @@ export const rawUpgrades = [
id: "slow_down",
max: 2,
name: t("upgrades.slow_down.name"),
help: (lvl:number) => t("upgrades.slow_down.help",{ lvl }),
help: (lvl: number) => t("upgrades.slow_down.help", { lvl }),
fullHelp: t("upgrades.slow_down.fullHelp"),
},
{
@ -84,7 +84,7 @@ export const rawUpgrades = [
max: 1,
name: t("upgrades.left_is_lava.name"),
help: (lvl:number) => t("upgrades.left_is_lava.help",{ lvl }),
help: (lvl: number) => t("upgrades.left_is_lava.help", { lvl }),
fullHelp: t("upgrades.left_is_lava.fullHelp"),
},
{
@ -95,7 +95,7 @@ export const rawUpgrades = [
giftable: true,
max: 1,
name: t("upgrades.right_is_lava.name"),
help: (lvl:number) => t("upgrades.right_is_lava.help",{ lvl }),
help: (lvl: number) => t("upgrades.right_is_lava.help", { lvl }),
fullHelp: t("upgrades.right_is_lava.fullHelp"),
},
{
@ -106,7 +106,7 @@ export const rawUpgrades = [
giftable: true,
max: 1,
name: t("upgrades.top_is_lava.name"),
help: (lvl:number) => t("upgrades.top_is_lava.help",{ lvl }),
help: (lvl: number) => t("upgrades.top_is_lava.help", { lvl }),
fullHelp: t("upgrades.top_is_lava.fullHelp"),
},
{
@ -195,7 +195,7 @@ export const rawUpgrades = [
giftable: true,
max: 1,
name: t("upgrades.picky_eater.name"),
help: (lvl: number) => t("upgrades.picky_eater.help",{lvl}),
help: (lvl: number) => t("upgrades.picky_eater.help", { lvl }),
fullHelp: t("upgrades.picky_eater.fullHelp"),
},
{
@ -206,7 +206,7 @@ export const rawUpgrades = [
id: "metamorphosis",
max: 1,
name: t("upgrades.metamorphosis.name"),
help: (lvl: number) => t("upgrades.metamorphosis.help",{lvl}),
help: (lvl: number) => t("upgrades.metamorphosis.help", { lvl }),
fullHelp: t("upgrades.metamorphosis.fullHelp"),
},
{
@ -217,7 +217,7 @@ export const rawUpgrades = [
giftable: true,
max: 1,
name: t("upgrades.compound_interest.name"),
help: (lvl: number) => t("upgrades.compound_interest.help",{lvl}),
help: (lvl: number) => t("upgrades.compound_interest.help", { lvl }),
fullHelp: t("upgrades.compound_interest.fullHelp"),
},
{
@ -289,7 +289,10 @@ export const rawUpgrades = [
id: "soft_reset",
max: 3,
name: t("upgrades.soft_reset.name"),
help: (lvl: number) => t("upgrades.soft_reset.help", { percent: Math.round(comboKeepingRate(lvl) * 100)}),
help: (lvl: number) =>
t("upgrades.soft_reset.help", {
percent: Math.round(comboKeepingRate(lvl) * 100),
}),
fullHelp: t("upgrades.soft_reset.fullHelp"),
},
{
@ -354,9 +357,9 @@ export const rawUpgrades = [
name: t("upgrades.sturdy_bricks.name"),
help: (lvl: number) =>
// lvl == 1
t("upgrades.sturdy_bricks.help",{lvl, percent:lvl*10}),
// ?
// : t("upgrades.sturdy_bricks.help_plural"),
t("upgrades.sturdy_bricks.help", { lvl, percent: lvl * 10 }),
// ?
// : t("upgrades.sturdy_bricks.help_plural"),
fullHelp: t("upgrades.sturdy_bricks.fullHelp"),
},
{
@ -368,7 +371,10 @@ export const rawUpgrades = [
max: 4,
name: t("upgrades.respawn.name"),
help: (lvl: number) =>
t("upgrades.respawn.help",{percent:Math.floor(100*comboKeepingRate(lvl)),delay:(3/lvl).toFixed(2)}),
t("upgrades.respawn.help", {
percent: Math.floor(100 * comboKeepingRate(lvl)),
delay: (3 / lvl).toFixed(2),
}),
fullHelp: t("upgrades.respawn.fullHelp"),
},
{
@ -378,7 +384,7 @@ export const rawUpgrades = [
id: "one_more_choice",
max: 3,
name: t("upgrades.one_more_choice.name"),
help: (lvl: number) => t("upgrades.one_more_choice.help", {lvl}),
help: (lvl: number) => t("upgrades.one_more_choice.help", { lvl }),
fullHelp: t("upgrades.one_more_choice.fullHelp"),
},
{
@ -390,7 +396,7 @@ export const rawUpgrades = [
max: 2,
adventure: false,
name: t("upgrades.instant_upgrade.name"),
help: (lvl: number) => t("upgrades.instant_upgrade.help",{lvl}),
help: (lvl: number) => t("upgrades.instant_upgrade.help", { lvl }),
fullHelp: t("upgrades.instant_upgrade.fullHelp"),
},
{
@ -422,7 +428,7 @@ export const rawUpgrades = [
id: "asceticism",
max: 1,
name: t("upgrades.asceticism.name"),
help: (lvl: number) => t("upgrades.asceticism.help",{combo:lvl*3}),
help: (lvl: number) => t("upgrades.asceticism.help", { combo: lvl * 3 }),
fullHelp: t("upgrades.asceticism.fullHelp"),
},
{
@ -433,9 +439,10 @@ export const rawUpgrades = [
id: "unbounded",
max: 1,
name: t("upgrades.unbounded.name"),
help: (lvl: number) => lvl > 1 ?
t("upgrades.unbounded.help_no_ceiling",{lvl}):
t("upgrades.unbounded.help",{lvl}),
help: (lvl: number) =>
lvl > 1
? t("upgrades.unbounded.help_no_ceiling", { lvl })
: t("upgrades.unbounded.help", { lvl }),
fullHelp: t("upgrades.unbounded.fullHelp"),
},
{
@ -446,7 +453,10 @@ export const rawUpgrades = [
id: "shunt",
max: 3,
name: t("upgrades.shunt.name"),
help: (lvl: number) => t("upgrades.shunt.help", { percent: Math.round(comboKeepingRate(lvl) * 100) }),
help: (lvl: number) =>
t("upgrades.shunt.help", {
percent: Math.round(comboKeepingRate(lvl) * 100),
}),
fullHelp: t("upgrades.shunt.fullHelp"),
},
{
@ -499,7 +509,7 @@ export const rawUpgrades = [
id: "zen",
max: 1,
name: t("upgrades.zen.name"),
help: (lvl: number) => t("upgrades.zen.help",{lvl}),
help: (lvl: number) => t("upgrades.zen.help", { lvl }),
fullHelp: t("upgrades.zen.fullHelp"),
},
{
@ -510,9 +520,9 @@ export const rawUpgrades = [
max: 1,
name: t("upgrades.sacrifice.name"),
help: (lvl: number) =>
lvl==1 ?
t("upgrades.sacrifice.help_l1"):
t("upgrades.sacrifice.help_over",{lvl}),
lvl == 1
? t("upgrades.sacrifice.help_l1")
: t("upgrades.sacrifice.help_over", { lvl }),
fullHelp: t("upgrades.sacrifice.fullHelp"),
},