Build 29087440

This commit is contained in:
Renan LE CARO 2025-04-21 16:40:56 +02:00
parent 6b54fb82d6
commit dc66f69543
23 changed files with 424 additions and 183 deletions

View file

@ -14,8 +14,13 @@ Break colourful bricks, catch bouncing coins and select powerful upgrades !
# Changelog
## To do
## Done
- sticky coins : coins stay stuck when there's an explosion
- split level unlock and perks unlocks
- wrap_left
- wrap_right
- rework passive income
## 29087252

View file

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

File diff suppressed because one or more lines are too long

111
dist/index.html vendored

File diff suppressed because one or more lines are too long

View file

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

View file

@ -1053,12 +1053,6 @@
"bricks": "_ggg____gbgg___gbbgg__gbbbg__gbbgg__gbgg___ggg___",
"color": ""
},
{
"name": "icon:unlocks",
"size": 6,
"bricks": "_bbbb__b__b__b__b_gggggggggggggggggg",
"color": ""
},
{
"name": "icon:settings",
"size": 9,
@ -1393,5 +1387,19 @@
"bricks": "WWWWWWWWW___W__WW__v___WW_v____WWp____pWW____v_WW___v__W__WWW___",
"svg": null,
"color": ""
},
{
"name": "icon:unlocked_upgrades",
"size": 9,
"bricks": "___ggg_____ggbgg___ggbbbgg_ggbbgbbgggbbbgbbbggggbgbggg__gbgbg____gbgbg____ggggg__",
"svg": null,
"color": ""
},
{
"name": "icon:unlocked_levels",
"size": 9,
"bricks": "ggggggggggbbbgbbbggbgggggbggbgbgbgbgggggggggggbgbgbgbggbgggggbggbbbgbbbgggggggggg",
"svg": null,
"color": ""
}
]

View file

@ -1 +1 @@
"29087252"
"29087440"

View file

@ -194,6 +194,9 @@ body:not(.has-alert-open) #popup {
}
}
&.actionsAsGrid.large > div > section {
grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
}
&.actionsAsGrid > div {
max-width: none;

View file

@ -589,11 +589,19 @@ export async function openMainMenu() {
runHistoryViewerMenuEntry(),
levelEditorMenuEntry(),
{
icon: icons["icon:unlocks"],
text: t("main_menu.unlocks"),
icon: icons["icon:unlocked_upgrades"],
text: t("unlocks.upgrades"),
help: t("main_menu.unlocks_help"),
value() {
openUnlocksList();
openUnlockedUpgradesList();
},
},
{
icon: icons["icon:unlocked_levels"],
text: t("unlocks.levels"),
help: t("main_menu.unlocks_help"),
value() {
openUnlockedLevelsList();
},
},
@ -905,10 +913,9 @@ async function applyFullScreenChoice() {
return false;
}
async function openUnlocksList() {
async function openUnlockedUpgradesList() {
const ts = getTotalScore();
const hintField = isOptionOn("mobile-mode") ? "help" : "tooltip";
const upgradeActions = upgrades
.sort((a, b) => a.threshold - b.threshold)
.map(({ name, id, threshold, icon, help }) => ({
@ -925,6 +932,29 @@ async function openUnlocksList() {
: help(1),
}));
const tryOn = await asyncAlert<RunParams>({
title: t("unlocks.title_upgrades", {
unlocked: upgradeActions.filter((a) => !a.disabled).length,
out_of: upgradeActions.length,
}),
content: [
`<p>${t("unlocks.intro", { ts })}
${upgradeActions.find((u) => u.disabled) ? t("unlocks.greyed_out_help") : ""}</p> `,
...upgradeActions,
],
allowClose: true,
className: "actionsAsGrid large",
});
if (tryOn) {
if (await confirmRestart(gameState)) {
restart({ ...tryOn });
}
}
}
async function openUnlockedLevelsList() {
const hintField = isOptionOn("mobile-mode") ? "help" : "tooltip";
const unlockedBefore = new Set(
getSettingValue("breakout_71_unlocked_levels", []),
);
@ -946,22 +976,13 @@ async function openUnlocksList() {
});
const tryOn = await asyncAlert<RunParams>({
title: t("unlocks.title_upgrades", {
unlocked: upgradeActions.filter((a) => !a.disabled).length,
out_of: upgradeActions.length,
}),
content: [
`<p>${t("unlocks.intro", { ts })}
${upgradeActions.find((u) => u.disabled) ? t("unlocks.greyed_out_help") : ""}</p> `,
...upgradeActions,
t("unlocks.level", {
title: t("unlocks.level", {
unlocked: levelActions.filter((a) => !a.disabled).length,
out_of: levelActions.length,
}),
...levelActions,
],
content: [...levelActions],
allowClose: true,
className: isOptionOn("mobile-mode") ? "" : "actionsAsGrid",
className: "actionsAsGrid large",
});
if (tryOn) {
if (await confirmRestart(gameState)) {

View file

@ -54,7 +54,6 @@ import {
clamp,
coinsBoostedCombo,
comboKeepingRate,
shouldCoinsStick,
} from "./pure_functions";
import { addToTotalScore } from "./addToTotalScore";
import { hashCode } from "./getLevelBackground";
@ -232,15 +231,13 @@ export function resetCombo(
const prev = gameState.combo;
gameState.combo = baseCombo(gameState);
if(gameState.perks.double_or_nothing){
if (gameState.perks.double_or_nothing) {
gameState.score = Math.floor(
gameState.score *
clamp(1-gameState.perks.double_or_nothing/10 , 0,1)
gameState.score * clamp(1 - gameState.perks.double_or_nothing / 10, 0, 1),
);
schedulGameSound(gameState, "lifeLost", x,1)
schedulGameSound(gameState, "lifeLost", x, 1);
}
if (prev > gameState.combo && gameState.perks.soft_reset) {
gameState.combo += Math.floor(
(prev - gameState.combo) * comboKeepingRate(gameState.perks.soft_reset),
@ -278,7 +275,7 @@ export function increaseCombo(
if (by <= 0) {
return;
}
by*= (1+gameState.perks.double_or_nothing)
by *= 1 + gameState.perks.double_or_nothing;
gameState.combo += by;
if (
isOptionOn("comboIncreaseTexts") &&
@ -484,6 +481,13 @@ export function explodeBrick(
);
}
let zenBonus = 0;
if (gameState.perks.zen) {
gameState.bricks.forEach((b) => {
if (b === "black") zenBonus += gameState.perks.zen;
});
}
increaseCombo(
gameState,
gameState.perks.streak_shots +
@ -493,8 +497,8 @@ export function explodeBrick(
gameState.perks.top_is_lava +
gameState.perks.picky_eater +
gameState.perks.asceticism * 3 +
gameState.perks.zen +
gameState.perks.passive_income +
zenBonus +
gameState.perks.addiction,
ball.x,
ball.y,
@ -888,7 +892,7 @@ export function coinBrickHitCheck(gameState: GameState, coin: Coin) {
undefined;
if (typeof (vhit ?? hhit ?? chit) !== "undefined") {
if (shouldCoinsStick(gameState)) {
if (gameState.perks.sticky_coins) {
if (coin.collidedLastFrame) {
coin.x = previousX;
coin.y = previousY;
@ -1225,37 +1229,49 @@ export function gameStateTick(
const hitBorder = bordersHitCheck(gameState, coin, coin.size / 2, frames);
if (
gameState.perks.wrap_left >1&&
gameState.perks.wrap_left > 1 &&
hitBorder % 2 &&
coin.x < gameState.offsetX + gameState.gameZoneWidth / 2
) {
schedulGameSound(gameState, "plouf", coin.x, 1)
coin.x= gameState.offsetX + gameState.gameZoneWidth - gameState.coinSize/2
if(coin.vx>0){
coin.vx*=-1
schedulGameSound(gameState, "plouf", coin.x, 1);
coin.x =
gameState.offsetX + gameState.gameZoneWidth - gameState.coinSize / 2;
if (coin.vx > 0) {
coin.vx *= -1;
}
if(!isOptionOn('basic')){
spawnExplosion(gameState, 3 , coin.x, coin.y, "#6262EA");
spawnImplosion(gameState, 3 , coin.previousX, coin.previousY, "#6262EA");
if (!isOptionOn("basic")) {
spawnExplosion(gameState, 3, coin.x, coin.y, "#6262EA");
spawnImplosion(
gameState,
3,
coin.previousX,
coin.previousY,
"#6262EA",
);
}
}else if (
gameState.perks.wrap_right>1 &&
} else if (
gameState.perks.wrap_right > 1 &&
hitBorder % 2 &&
coin.x > gameState.offsetX + gameState.gameZoneWidth / 2
) {
schedulGameSound(gameState, "plouf", coin.x, 1)
coin.x= gameState.offsetX + gameState.coinSize/2
schedulGameSound(gameState, "plouf", coin.x, 1);
coin.x = gameState.offsetX + gameState.coinSize / 2;
if(coin.vx<0){
coin.vx*=-1
if (coin.vx < 0) {
coin.vx *= -1;
}
if(!isOptionOn('basic')){
spawnExplosion(gameState, 3 , coin.x, coin.y, "#6262EA");
spawnImplosion(gameState, 3 , coin.previousX, coin.previousY, "#6262EA");
if (!isOptionOn("basic")) {
spawnExplosion(gameState, 3, coin.x, coin.y, "#6262EA");
spawnImplosion(
gameState,
3,
coin.previousX,
coin.previousY,
"#6262EA",
);
}
}
if (
coin.previousY < gameState.gameZoneHeight &&
coin.y > gameState.gameZoneHeight &&
@ -1528,7 +1544,10 @@ export function gameStateTick(
100 * (Math.random() + 1),
);
}
if (gameState.perks.streak_shots && !isMovingWhilePassiveIncome(gameState)) {
if (
gameState.perks.streak_shots &&
!isMovingWhilePassiveIncome(gameState)
) {
const pos = 0.5 - Math.random();
makeParticle(
gameState,
@ -1700,31 +1719,31 @@ export function ballTick(gameState: GameState, ball: Ball, frames: number) {
borderHitCode % 2 &&
ball.x < gameState.offsetX + gameState.gameZoneWidth / 2
) {
schedulGameSound(gameState, "plouf", ball.x, 1)
ball.x= gameState.offsetX + gameState.gameZoneWidth - gameState.ballSize/2
if(ball.vx>0){
ball.vx*=-1
schedulGameSound(gameState, "plouf", ball.x, 1);
ball.x =
gameState.offsetX + gameState.gameZoneWidth - gameState.ballSize / 2;
if (ball.vx > 0) {
ball.vx *= -1;
}
if(!isOptionOn('basic')){
spawnExplosion(gameState, 7 , ball.x, ball.y, "#6262EA");
spawnImplosion(gameState, 7 , ball.previousX, ball.previousY, "#6262EA");
if (!isOptionOn("basic")) {
spawnExplosion(gameState, 7, ball.x, ball.y, "#6262EA");
spawnImplosion(gameState, 7, ball.previousX, ball.previousY, "#6262EA");
}
}else if (
} else if (
gameState.perks.wrap_right &&
borderHitCode % 2 &&
ball.x > gameState.offsetX + gameState.gameZoneWidth / 2
) {
schedulGameSound(gameState, "plouf", ball.x, 1)
ball.x= gameState.offsetX + gameState.ballSize/2
schedulGameSound(gameState, "plouf", ball.x, 1);
ball.x = gameState.offsetX + gameState.ballSize / 2;
if(ball.vx<0){
ball.vx*=-1
if (ball.vx < 0) {
ball.vx *= -1;
}
if(!isOptionOn('basic')){
spawnExplosion(gameState, 7 , ball.x, ball.y, "#6262EA");
spawnImplosion(gameState, 7 , ball.previousX, ball.previousY, "#6262EA");
if (!isOptionOn("basic")) {
spawnExplosion(gameState, 7, ball.x, ball.y, "#6262EA");
spawnImplosion(gameState, 7, ball.previousX, ball.previousY, "#6262EA");
}
}
@ -1758,7 +1777,8 @@ export function ballTick(gameState: GameState, ball: Ball, frames: number) {
gameState.gameZoneHeight - gameState.puckHeight - gameState.ballSize / 2;
const ballIsUnderPuck =
Math.abs(ball.x - gameState.puckPosition) <
gameState.ballSize / 2 + gameState.puckWidth / 2 && !isMovingWhilePassiveIncome(gameState, 150);
gameState.ballSize / 2 + gameState.puckWidth / 2 &&
!isMovingWhilePassiveIncome(gameState, 150);
if (
ball.y > ylimit &&
ball.vy > 0 &&

View file

@ -276,7 +276,10 @@ export function shouldPierceByColor(
return true;
}
export function isMovingWhilePassiveIncome(gameState: GameState, gracePeriod = 0) {
export function isMovingWhilePassiveIncome(
gameState: GameState,
gracePeriod = 0,
) {
return !!(
gameState.lastPuckMove &&
gameState.perks.passive_income &&

View file

@ -55,6 +55,7 @@
"history.columns.score": "نتيجة",
"history.columns.started": "تاريخ",
"history.help": "شاهد أفضل ألعابك {{count}} .",
"history.include_past_versions": "",
"history.locked": "العب عشر مباريات على الأقل لفتح القفل",
"history.title": "سجل التشغيل",
"lab.help": "جرب أي بناء تريده",
@ -227,16 +228,18 @@
"starting_perks.title": "امتيازات البداية",
"starting_perks.unchecked": "لا يتم تقديم الامتيازات المذكورة أدناه كامتيازات ابتدائية، ولكن يمكنك النقر عليها لإضافتها إلى المجموعة.",
"unlocks.greyed_out_help": "يمكن فتح الترقيات غير المفعّلة بزيادة مجموع نقاطك. يزداد مجموع النقاط مع كل نقطة تُسجّلها في اللعبة.",
"unlocks.intro": "مجموع نقاطك هو {{ts}}. تجد أدناه جميع الترقيات والمستويات التي تقدمها اللعبة. انقر على ترقية أو مستوى أدناه لبدء لعبة تجريبية بها.",
"unlocks.intro": "",
"unlocks.just_unlocked": "تم فتح المستوى",
"unlocks.just_unlocked_plural": "لقد قمت للتو بفتح {{count}} مستوى",
"unlocks.level": "<h2>لقد قمت بفتح {{unlocked}} مستوى من أصل {{out_of}}</h2>\n<p>إليك جميع مستويات اللعبة، انقر على أحدها لتجربته.</p> ",
"unlocks.level": "",
"unlocks.level_description": "مستوى {{size}}×{{size}} مع {{bricks}} طوبة و {{colors}} لون و {{bombs}} قنبلة.",
"unlocks.levels": "",
"unlocks.minScore": "احصل على ${{minScore}} في جولة لفتح القفل.",
"unlocks.minScoreWithPerks": "احصل على ${{minScore}} في جولة مع {{required}} ولكن بدون {{forbidden}} لفتح القفل.",
"unlocks.minTotalScore": "تجميع إجمالي قدره{{score}}دولار",
"unlocks.reached": "أفضل نتيجة حصلت عليها كانت {{reached}}.",
"unlocks.title_upgrades": "لقد قمت بفتح {{unlocked}} ترقيات من أصل {{out_of}}",
"unlocks.upgrades": "",
"upgrades.addiction.name": "مدمن",
"upgrades.addiction.tooltip": "+{{lvl}} مجموعة / لبنة، يتم إعادة تعيين المجموعة لمدة {{delay}}ثانية بعد كسر لبنة.",
"upgrades.addiction.verbose_description": "يبدأ العد التنازلي بعد كسر أول لبنة من كل مستوى، ويتوقف عند تدمير جميع الطوب.",
@ -411,7 +414,7 @@
"upgrades.soft_reset.tooltip": "إعادة تعيين المجموعة تحافظ على {{percent}}%",
"upgrades.soft_reset.verbose_description": "الحد من تأثير إعادة تعيين المجموعة.",
"upgrades.sticky_coins.name": "العملات المعدنية اللاصقة",
"upgrades.sticky_coins.tooltip": "تلتصق العملات المعدنية بالطوب، ويمكن أن تنفصل عن بعضها البعض بسبب الانفجارات",
"upgrades.sticky_coins.tooltip": "العملات المعدنية تلتصق بالطوب",
"upgrades.sticky_coins.verbose_description": "",
"upgrades.streak_shots.name": "سلسلة الضربات",
"upgrades.streak_shots.tooltip": "مزيد من العملات المعدنية إذا قمت بكسر العديد من الطوب قبل القفز على المجداف.",
@ -461,6 +464,6 @@
"upgrades.yoyo.tooltip": "الكرة تسقط نحو المضرب",
"upgrades.yoyo.verbose_description": "إنه عكس التحريك الذهني، أي التحكم بالكرة أثناء سقوطها مرة أخرى إلى الأسفل.",
"upgrades.zen.name": "زين",
"upgrades.zen.tooltip": "+{{lvl}} مجموعة لكل لبنة، يتم إعادة ضبطها عند حدوث انفجار",
"upgrades.zen.verbose_description": "في نهاية المطاف، هذه لعبة غير عنيفة."
"upgrades.zen.tooltip": "+{{lvl}} مجموعة لكل قنبلة على الشاشة عند كسر الطوب، يتم إعادة ضبطها عند حدوث انفجار",
"upgrades.zen.verbose_description": ""
}

View file

@ -2027,6 +2027,41 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>include_past_versions</name>
<description/>
<comment/>
<translations>
<translation>
<language>ar-LB</language>
<approved>false</approved>
</translation>
<translation>
<language>de-DE</language>
<approved>false</approved>
</translation>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-CL</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-FR</language>
<approved>false</approved>
</translation>
<translation>
<language>ru-RU</language>
<approved>false</approved>
</translation>
<translation>
<language>tr-TR</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>locked</name>
<description/>
@ -8267,6 +8302,41 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>levels</name>
<description/>
<comment/>
<translations>
<translation>
<language>ar-LB</language>
<approved>false</approved>
</translation>
<translation>
<language>de-DE</language>
<approved>false</approved>
</translation>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-CL</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-FR</language>
<approved>false</approved>
</translation>
<translation>
<language>ru-RU</language>
<approved>false</approved>
</translation>
<translation>
<language>tr-TR</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>minScore</name>
<description/>
@ -8442,6 +8512,41 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>upgrades</name>
<description/>
<comment/>
<translations>
<translation>
<language>ar-LB</language>
<approved>false</approved>
</translation>
<translation>
<language>de-DE</language>
<approved>false</approved>
</translation>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-CL</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-FR</language>
<approved>false</approved>
</translation>
<translation>
<language>ru-RU</language>
<approved>false</approved>
</translation>
<translation>
<language>tr-TR</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
<folder_node>
@ -16668,7 +16773,7 @@
</translation>
<translation>
<language>fr-FR</language>
<approved>true</approved>
<approved>false</approved>
</translation>
<translation>
<language>ru-RU</language>

View file

@ -55,6 +55,7 @@
"history.columns.score": "Ergebnis",
"history.columns.started": "Datum",
"history.help": "Sehen Sie Ihre {{count}} besten Spiele.",
"history.include_past_versions": "",
"history.locked": "Mindestens zehn Spiele spielen, um freizuschalten",
"history.title": "Läuft Geschichte",
"lab.help": "Versuchen Sie jede beliebige Konstruktion",
@ -227,16 +228,18 @@
"starting_perks.title": "Startvorteile",
"starting_perks.unchecked": "Die folgenden Vergünstigungen werden nicht als Startvergünstigungen angeboten, aber Sie können sie durch Anklicken zum Pool hinzufügen.",
"unlocks.greyed_out_help": "Die ausgegrauten Upgrades können freigeschaltet werden, indem Sie Ihre Gesamtpunktzahl erhöhen. Die Gesamtpunktzahl erhöht sich jedes Mal, wenn Sie im Spiel punkten.",
"unlocks.intro": "Deine Gesamtpunktzahl ist {{ts}}. Nachfolgend finden Sie alle Upgrades und Levels, die das Spiel zu bieten hat. Klicken Sie auf ein Upgrade oder eine Stufe, um ein Testspiel damit zu starten.",
"unlocks.intro": "",
"unlocks.just_unlocked": "Level freigeschaltet",
"unlocks.just_unlocked_plural": "Du hast soeben {{count}} Stufen freigeschaltet",
"unlocks.level": "<h2>Du hast {{unlocked}} Stufen von {{out_of}}freigeschaltet </h2>\n<p>Hier sind alle Spielstufen, klicke eine an, um sie auszuprobieren.</p> ",
"unlocks.level": "",
"unlocks.level_description": "Ein {{size}}x{{size}} Level mit {{bricks}} Steinen, {{colors}} Farben und {{bombs}} Bomben.",
"unlocks.levels": "",
"unlocks.minScore": "Erreiche ${{minScore}} in einem Lauf, um freizuschalten.",
"unlocks.minScoreWithPerks": "Erreiche ${{minScore}} in einem Durchgang mit {{required}} , aber ohne {{forbidden}} zu entsperren.",
"unlocks.minTotalScore": "Kumulieren Sie insgesamt ${{score}}",
"unlocks.reached": "Ihr bestes Ergebnis war {{reached}}.",
"unlocks.title_upgrades": "Du hast {{unlocked}} Upgrades von {{out_of}}freigeschaltet.",
"unlocks.upgrades": "",
"upgrades.addiction.name": "Sucht",
"upgrades.addiction.tooltip": "+{{lvl}} Combo / Stein, Combo wird {{delay}}s nach Zerbrechen eines Steins zurückgesetzt.",
"upgrades.addiction.verbose_description": "Der Countdown beginnt erst nach dem Zerbrechen des ersten Steins eines jeden Levels. Er stoppt, sobald alle Ziegel zerstört sind.",
@ -411,7 +414,7 @@
"upgrades.soft_reset.tooltip": "Combo-Rückstellungen halten {{percent}}%",
"upgrades.soft_reset.verbose_description": "Begrenzen Sie die Auswirkungen eines Combo-Resets.",
"upgrades.sticky_coins.name": "Klebrige Münzen",
"upgrades.sticky_coins.tooltip": "Münzen kleben an Ziegeln und können durch Explosionen herausgerissen werden",
"upgrades.sticky_coins.tooltip": "Münzen kleben an Ziegeln",
"upgrades.sticky_coins.verbose_description": "",
"upgrades.streak_shots.name": "Glückssträhne",
"upgrades.streak_shots.tooltip": "Mehr Münzen, wenn du viele Steine zerbrichst, bevor du auf das Paddel springst.",
@ -461,6 +464,6 @@
"upgrades.yoyo.tooltip": "Ball fällt in Richtung Paddel",
"upgrades.yoyo.verbose_description": "Es ist das Gegenteil von Telekinese, den Ball zu kontrollieren, während er wieder nach unten fällt.",
"upgrades.zen.name": "Zen",
"upgrades.zen.tooltip": "+{{lvl}} Combo pro Ziegel, wird bei einer Explosion zurückgesetzt",
"upgrades.zen.verbose_description": "Schließlich handelt es sich um ein gewaltfreies Spiel."
"upgrades.zen.tooltip": "+{{lvl}} Combo pro Bombe auf dem Bildschirm beim Zerbrechen eines Ziegels, zurückgesetzt, wenn es eine Explosion gibt",
"upgrades.zen.verbose_description": ""
}

View file

@ -55,6 +55,7 @@
"history.columns.score": "Score",
"history.columns.started": "Date",
"history.help": "See your {{count}} best games.",
"history.include_past_versions": "Show past versions too",
"history.locked": "Play at least ten games to unlock",
"history.title": "Runs history",
"lab.help": "Try any build you want",
@ -227,16 +228,18 @@
"starting_perks.title": "Starting perks",
"starting_perks.unchecked": "The perks below are not offered as starting perks, but you can click to add them to the pool. ",
"unlocks.greyed_out_help": "The grayed out upgrades can be unlocked by increasing your total score. The total score increases every time you score in game.",
"unlocks.intro": "Your total score is {{ts}}. Below are all the upgrades and levels the games has to offer. Click an upgrade or level below to start a test game with it.",
"unlocks.intro": "Your total score is {{ts}}.Click an upgrade below to start a test game with it.",
"unlocks.just_unlocked": "Level unlocked",
"unlocks.just_unlocked_plural": "You just unlocked {{count}} levels",
"unlocks.level": "<h2>You unlocked {{unlocked}} levels out of {{out_of}}</h2>\n<p>Here are all the game levels, click one to try it out.</p> ",
"unlocks.level": "You unlocked {{unlocked}} levels out of {{out_of}}",
"unlocks.level_description": "A {{size}}x{{size}} level with {{bricks}} bricks, {{colors}} colors and {{bombs}} bombs.",
"unlocks.levels": "Unlocked levels",
"unlocks.minScore": "Reach ${{minScore}} in a run to unlock.",
"unlocks.minScoreWithPerks": "Reach ${{minScore}} in a run with {{required}} but without {{forbidden}} to unlock.",
"unlocks.minTotalScore": "Accumulate a total of ${{score}}",
"unlocks.reached": "Your best score was {{reached}}.",
"unlocks.title_upgrades": "You unlocked {{unlocked}} upgrades out of {{out_of}}",
"unlocks.upgrades": "Unlocked upgrades",
"upgrades.addiction.name": "Addiction",
"upgrades.addiction.tooltip": "+{{lvl}} combo / brick, combo resets {{delay}}s after breaking a brick. ",
"upgrades.addiction.verbose_description": "The countdown only starts after breaking the first brick of each level. It stops as soon as all bricks are destroyed.",
@ -411,7 +414,7 @@
"upgrades.soft_reset.tooltip": "Combo resets keeps {{percent}}%",
"upgrades.soft_reset.verbose_description": "Limit the impact of a combo reset.",
"upgrades.sticky_coins.name": "Sticky coins",
"upgrades.sticky_coins.tooltip": "Coins stick to bricks, and can be dislodged by explosions",
"upgrades.sticky_coins.tooltip": "Coins stick to bricks",
"upgrades.sticky_coins.verbose_description": "",
"upgrades.streak_shots.name": "Hit streak",
"upgrades.streak_shots.tooltip": "More coins if you break many bricks before bouncing on the paddle.",
@ -461,6 +464,6 @@
"upgrades.yoyo.tooltip": "Ball falls toward paddle",
"upgrades.yoyo.verbose_description": "It's the opposite of telekinesis, control the ball while it's falling back down.",
"upgrades.zen.name": "Zen",
"upgrades.zen.tooltip": "+{{lvl}} combo per bricks, reset when there's an explosion",
"upgrades.zen.verbose_description": "After all, this is a non-violent game. "
"upgrades.zen.tooltip": "+{{lvl}} combo per bomb on screen when breaking a bricks, reset when there's an explosion",
"upgrades.zen.verbose_description": ""
}

View file

@ -55,6 +55,7 @@
"history.columns.score": "Puntuación",
"history.columns.started": "Fecha",
"history.help": "Enumera tus {{count}} mejores juegos.",
"history.include_past_versions": "",
"history.locked": "Juega primero al menos diez partidos",
"history.title": "Historia",
"lab.help": "Prueba cualquier combinación de mejoras y niveles.",
@ -227,16 +228,18 @@
"starting_perks.title": "Beneficios iniciales",
"starting_perks.unchecked": "Los beneficios a continuación no se ofrecen como beneficios iniciales, pero puedes hacer clic para agregarlos al grupo.",
"unlocks.greyed_out_help": "Los objetos en gris pueden desbloquearse aumentando tu puntuación total. La puntuación total aumenta cada vez que consigues puntos en el juego.",
"unlocks.intro": "Tu puntuación total es {{ts}}. A continuación encontrarás todas las mejoras y niveles que ofrece el juego. Haz clic en uno de ellos para probarlo en una partida de prueba.",
"unlocks.intro": "",
"unlocks.just_unlocked": "Nivel desbloqueado",
"unlocks.just_unlocked_plural": "Acabas de desbloquear {{count}} niveles",
"unlocks.level": "<h2>Has desbloqueado {{unlocked}} niveles en {{out_of}}</h2>\n<p>Aquí están todos los niveles del juego, haz clic en uno para probarlo. </p> ",
"unlocks.level": "",
"unlocks.level_description": "Un nivel {{size}}x{{size}} con {{bricks}} ladrillos, {{colors}} colores y {{bombs}} bombas.",
"unlocks.levels": "",
"unlocks.minScore": "Alcanza una puntuación de ${{minScore}} en una partida para desbloquearla.",
"unlocks.minScoreWithPerks": "Alcanzar ${{minScore}} en un juego con {{required}} pero sin {{forbidden}}.",
"unlocks.minTotalScore": "Acumula un total de ${{score}}",
"unlocks.reached": "Tu mejor puntuación hasta ahora es {{reached}}.",
"unlocks.title_upgrades": "Has desbloqueado {{unlocked}} mejoras en {{out_of}}.",
"unlocks.upgrades": "",
"upgrades.addiction.name": "Adicción",
"upgrades.addiction.tooltip": "+{{lvl}} combo / ladrillo, combo perdido después de {{delay}}s sin romper ningún ladrillo",
"upgrades.addiction.verbose_description": "La cuenta atrás sólo comienza una vez que se ha destruido el primer ladrillo del nivel, y se detiene en cuanto no hay más ladrillos.",
@ -411,7 +414,7 @@
"upgrades.soft_reset.tooltip": "Al reiniciar el combo se conserva el {{percent}}% de los puntos",
"upgrades.soft_reset.verbose_description": "Limita el impacto de un reinicio de combo.",
"upgrades.sticky_coins.name": "Monedas pegajosas",
"upgrades.sticky_coins.tooltip": "Las monedas se adhieren a los ladrillos y pueden desprenderse por las explosiones.",
"upgrades.sticky_coins.tooltip": "Las monedas se adhieren a los ladrillos",
"upgrades.sticky_coins.verbose_description": "",
"upgrades.streak_shots.name": "Secuencia de destrucción",
"upgrades.streak_shots.tooltip": "Más piezas si rompes varios ladrillos a la vez.",
@ -461,6 +464,6 @@
"upgrades.yoyo.tooltip": "La pelota desciende hacia la raqueta.",
"upgrades.yoyo.verbose_description": "Es lo contrario de la Telequinesis: controlar la pelota mientras cae hacia la raqueta.",
"upgrades.zen.name": "Zen",
"upgrades.zen.tooltip": "+{{lvl}} combo por ladrillo, hasta que haya una explosión",
"upgrades.zen.verbose_description": "Básicamente es un juego no violento."
"upgrades.zen.tooltip": "+{{lvl}} combo por bomba en pantalla al romper un ladrillo, se reinicia cuando hay una explosión",
"upgrades.zen.verbose_description": ""
}

View file

@ -55,6 +55,7 @@
"history.columns.score": "Score",
"history.columns.started": "Date",
"history.help": "Liste vos {{count}} meilleurs parties.",
"history.include_past_versions": "",
"history.locked": "Jouez d'abord au moins dix parties",
"history.title": "Historique",
"lab.help": "Essayez n'importe quel combinaison d'améliorations et de niveaux.",
@ -227,16 +228,18 @@
"starting_perks.title": "Avantages de départ",
"starting_perks.unchecked": "Les avantages ci-dessous ne sont pas proposés comme avantages de départ, mais vous pouvez cliquer pour les ajouter aux avantages de départ possibles.",
"unlocks.greyed_out_help": "Les éléments grisées peuvent être débloquées en augmentant votre score total. Le score total augmente à chaque fois que vous marquez des points dans le jeu.",
"unlocks.intro": "Votre score total est de {{ts}}. Vous trouverez ci-dessous toutes les améliorations et tous les niveaux que le jeu peut offrir. Cliquez sur l'un d'entre eux pour les essayer dans une partie de test. ",
"unlocks.intro": "",
"unlocks.just_unlocked": "Niveau débloqué",
"unlocks.just_unlocked_plural": "Vous venez de débloquer {{count}} niveaux",
"unlocks.level": "<h2>Vous avez débloqué {{unlocked}} niveaux sur {{out_of}}</h2>\n<p>Voici tous les niveaux du jeu, cliquez sur l'un d'eux pour l'essayer. </p> ",
"unlocks.level": "",
"unlocks.level_description": "Un niveau {{size}}x{{size}} avec {{bricks}} briques, {{colors}} couleurs et {{bombs}} bombes.",
"unlocks.levels": "",
"unlocks.minScore": "Atteignez un score de ${{minScore}} dans une partie pour débloquer.",
"unlocks.minScoreWithPerks": "Atteignez ${{minScore}} dans une partie avec {{required}} mais sans {{forbidden}}.",
"unlocks.minTotalScore": "Accumuler un total de ${{score}}",
"unlocks.reached": "Votre meilleur score pour l'instant est {{reached}}.",
"unlocks.title_upgrades": "Vous avez débloqué {{unlocked}} améliorations sur {{out_of}}",
"unlocks.upgrades": "",
"upgrades.addiction.name": "Addiction",
"upgrades.addiction.tooltip": "+{{lvl}} combo / brique, combo perdu après {{delay}}s sans casser de briques",
"upgrades.addiction.verbose_description": "Le décompte ne commence qu'à parti de la destruction de la première brique du niveau, et s'arrête dès qu'il n'y a plus de briques. ",
@ -411,7 +414,7 @@
"upgrades.soft_reset.tooltip": "La remise à zéro du combo conserve {{percent}}% des points",
"upgrades.soft_reset.verbose_description": "Limite l'impact d'une réinitialisation du combo.",
"upgrades.sticky_coins.name": "Pièces collantes",
"upgrades.sticky_coins.tooltip": "Les pièces collent aux briques et peuvent être délogées par des explosions",
"upgrades.sticky_coins.tooltip": "Les pièces collent aux briques",
"upgrades.sticky_coins.verbose_description": "",
"upgrades.streak_shots.name": "Séquence de destruction",
"upgrades.streak_shots.tooltip": "Plus de pièces si vous cassez plusieurs briques à la fois.",
@ -461,6 +464,6 @@
"upgrades.yoyo.tooltip": "La balle se dirige vers la raquette en descendant.",
"upgrades.yoyo.verbose_description": "C'est l'inverse de Télékinésie, contrôlez la balle alors qu'elle redescend vers la raquette.",
"upgrades.zen.name": "Zen",
"upgrades.zen.tooltip": "+{{lvl}} combo par brique, jusqu'à ce qu'il y ait une explosion",
"upgrades.zen.verbose_description": "C'est quand même un jeu non violent à la base."
"upgrades.zen.tooltip": "+{{lvl}} combo par bombe à l'écran lors de la rupture d'une brique, réinitialisé en cas d'explosion",
"upgrades.zen.verbose_description": ""
}

View file

@ -55,6 +55,7 @@
"history.columns.score": "Оценка",
"history.columns.started": "Дата",
"history.help": "Посмотрите свои {{count}} лучшие игры.",
"history.include_past_versions": "",
"history.locked": "Сыграйте не менее десяти игр, чтобы разблокировать",
"history.title": "История побегов",
"lab.help": "Попробуйте любую сборку.",
@ -227,16 +228,18 @@
"starting_perks.title": "Стартовые привилегии",
"starting_perks.unchecked": "Приведенные ниже привилегии не предлагаются в качестве стартовых, но вы можете нажать на них, чтобы добавить в пул.",
"unlocks.greyed_out_help": "Выделенные серым апгрейды можно разблокировать, увеличив общее количество очков. Общий счет увеличивается каждый раз, когда вы набираете очки в игре.",
"unlocks.intro": "Ваш общий счет составляет {{ts}}. Ниже представлены все обновления и уровни, которые предлагает игра. Нажмите на апгрейд или уровень ниже, чтобы начать тестовую игру с ним.",
"unlocks.intro": "",
"unlocks.just_unlocked": "Уровень разблокирован",
"unlocks.just_unlocked_plural": "Вы только что разблокировали {{count}} уровней",
"unlocks.level": "<h2>Вы разблокировали {{unlocked}} уровней из {{out_of}}</h2>\n<p>Здесь представлены все уровни игры, нажмите на один из них, чтобы опробовать его.</p> ",
"unlocks.level": "",
"unlocks.level_description": "Уровень {{size}}x{{size}} с {{bricks}} кирпичами, {{colors}} цветами и {{bombs}} бомбами.",
"unlocks.levels": "",
"unlocks.minScore": "Достигните ${{minScore}} в беге, чтобы разблокировать игру.",
"unlocks.minScoreWithPerks": "Достигните ${{minScore}} в беге с {{required}} , но без {{forbidden}} для разблокировки.",
"unlocks.minTotalScore": "Накопите в общей сложности ${{score}}",
"unlocks.reached": "Ваш лучший результат - {{reached}}.",
"unlocks.title_upgrades": "Вы разблокировали {{unlocked}} обновлений из {{out_of}}",
"unlocks.upgrades": "",
"upgrades.addiction.name": "Наркомания",
"upgrades.addiction.tooltip": "+{{lvl}} комбо / кирпич, комбо сбрасывается на {{delay}}с после разрушения кирпича.",
"upgrades.addiction.verbose_description": "Отсчет начинается только после разрушения первого кирпича на каждом уровне. Он остановится, как только все кирпичи будут уничтожены.",
@ -411,7 +414,7 @@
"upgrades.soft_reset.tooltip": "Комбо-сброс сохраняет {{percent}}%",
"upgrades.soft_reset.verbose_description": "Ограничьте влияние комбо-сброса.",
"upgrades.sticky_coins.name": "Липкие монеты",
"upgrades.sticky_coins.tooltip": "Монеты прилипают к кирпичам и могут быть смещены взрывами.",
"upgrades.sticky_coins.tooltip": "Монеты прилипают к кирпичам",
"upgrades.sticky_coins.verbose_description": "",
"upgrades.streak_shots.name": "Попадание в полосу",
"upgrades.streak_shots.tooltip": "Больше монет, если вы разобьете много кирпичей, прежде чем подпрыгнуть на лопатке.",
@ -461,6 +464,6 @@
"upgrades.yoyo.tooltip": "Мяч падает на лопатку",
"upgrades.yoyo.verbose_description": "Это противоположность телекинезу: управляйте мячом, пока он падает обратно.",
"upgrades.zen.name": "Дзен",
"upgrades.zen.tooltip": "+{{lvl}} комбо за кирпич, сбрасывается при взрыве",
"upgrades.zen.verbose_description": "В конце концов, это ненасильственная игра."
"upgrades.zen.tooltip": "+{{lvl}} комбо за бомбу на экране при разрушении кирпичей, сбрасывается при взрыве",
"upgrades.zen.verbose_description": ""
}

View file

@ -55,6 +55,7 @@
"history.columns.score": "Gol",
"history.columns.started": "Tarih",
"history.help": "En iyi {{count}} oyununuzu görün.",
"history.include_past_versions": "",
"history.locked": "Kilidi açmak için en az on oyun oynayın",
"history.title": "Koşu geçmişi",
"lab.help": "İstediğiniz herhangi bir yapıyı deneyin",
@ -227,16 +228,18 @@
"starting_perks.title": "Başlangıç avantajları",
"starting_perks.unchecked": "Aşağıdaki avantajlar başlangıç avantajı olarak sunulmamaktadır, ancak havuza eklemek için tıklayabilirsiniz.",
"unlocks.greyed_out_help": "Grileştirilmiş yükseltmeler toplam puanınızı artırarak açılabilir. Toplam puan, oyunda her puan aldığınızda artar.",
"unlocks.intro": "Toplam puanınız {{ts}}. Aşağıda oyunun sunduğu tüm yükseltmeler ve seviyeler bulunmaktadır. Aşağıdaki bir yükseltmeye veya seviyeye tıklayarak onunla bir test oyunu başlatın.",
"unlocks.intro": "",
"unlocks.just_unlocked": "Seviye kilidi açıldı",
"unlocks.just_unlocked_plural": "Az önce {{count}} seviyenin kilidini açtınız",
"unlocks.level": "<h2> {{out_of}}seviyeden {{unlocked}} tanesinin kilidini açtın</h2>\n<p>İşte tüm oyun seviyeleri, denemek için birine tıkla.</p> ",
"unlocks.level": "",
"unlocks.level_description": " {{bricks}} tuğla, {{colors}} renk ve {{bombs}} bombadan oluşan {{size}}x{{size}} büyüklüğünde bir seviye.",
"unlocks.levels": "",
"unlocks.minScore": "Kilidi açmak için bir koşuda ${{minScore}} 'a ulaşın.",
"unlocks.minScoreWithPerks": " {{required}} ile ancak {{forbidden}} olmadan bir koşuda ${{minScore}} 'a ulaşın.",
"unlocks.minTotalScore": "Toplam ${{score}}biriktirin",
"unlocks.reached": "En iyi skorunuz {{reached}}idi.",
"unlocks.title_upgrades": " {{out_of}}yükseltmeden {{unlocked}} tanesinin kilidini açtınız",
"unlocks.upgrades": "",
"upgrades.addiction.name": "Bağımlılık",
"upgrades.addiction.tooltip": "+{{lvl}} kombo / tuğla, kombo bir tuğlayı kırdıktan sonra {{delay}}saniye içinde sıfırlanır.",
"upgrades.addiction.verbose_description": "Geri sayım yalnızca her seviyenin ilk tuğlası kırıldıktan sonra başlar. Tüm tuğlalar yok edildiğinde durur.",
@ -411,7 +414,7 @@
"upgrades.soft_reset.tooltip": "Kombo sıfırlamaları % {{percent}}tutar",
"upgrades.soft_reset.verbose_description": "Bir kombo sıfırlamanın etkisini sınırlayın.",
"upgrades.sticky_coins.name": "Yapışkan paralar",
"upgrades.sticky_coins.tooltip": "Madeni paralar tuğlalara yapışır ve patlamalarla yerinden çıkabilir",
"upgrades.sticky_coins.tooltip": "Paralar tuğlalara yapışıyor",
"upgrades.sticky_coins.verbose_description": "",
"upgrades.streak_shots.name": "Vuruş serisi",
"upgrades.streak_shots.tooltip": "Kürek çekmeden önce çok sayıda tuğla kırarsanız daha fazla para kazanırsınız.",
@ -461,6 +464,6 @@
"upgrades.yoyo.tooltip": "Top küreğe doğru düşer",
"upgrades.yoyo.verbose_description": "Telekinezinin tam tersi, topun aşağı düşerken kontrol edilmesi.",
"upgrades.zen.name": "Zen",
"upgrades.zen.tooltip": "Tuğla başına +{{lvl}} kombo, patlama olduğunda sıfırlanır",
"upgrades.zen.verbose_description": "Sonuçta bu şiddet içermeyen bir oyun."
"upgrades.zen.tooltip": "Tuğla kırarken ekrandaki bomba başına +{{lvl}} kombo, patlama olduğunda sıfırlanır",
"upgrades.zen.verbose_description": ""
}

View file

@ -8,15 +8,6 @@ export function comboKeepingRate(level: number) {
return clamp(1 - (1 / (1 + level)) * 1.5, 0, 1);
}
export function shouldCoinsStick(gameState: GameState) {
return (
gameState.perks.sticky_coins &&
(!gameState.lastExplosion ||
gameState.lastExplosion <
gameState.levelTime - 300 * gameState.perks.sticky_coins)
);
}
export function ballTransparency(ball: Ball, gameState: GameState) {
if (!gameState.perks.transparency) return 0;
return clamp(

View file

@ -427,7 +427,7 @@ export function render(gameState: GameState) {
});
startWork("render:puck");
ctx.globalAlpha = isMovingWhilePassiveIncome(gameState) ? 0.2: 1;
ctx.globalAlpha = isMovingWhilePassiveIncome(gameState) ? 0.2 : 1;
ctx.globalCompositeOperation = "source-over";
drawPuck(
ctx,
@ -685,7 +685,6 @@ export function renderAllBricks() {
const redBorderOnBricksWithWrongColor =
hasCombo && gameState.perks.picky_eater && isPickyEatingPossible(gameState);
const redRowReach = reachRedRowIndex(gameState);
const { clairvoyant } = gameState.perks;
let offset = getDashOffset(gameState);
@ -746,7 +745,7 @@ export function renderAllBricks() {
color !== "black" &&
redBorderOnBricksWithWrongColor) ||
(hasCombo && gameState.perks.zen && color === "black") ||
redBecauseOfReach ;
redBecauseOfReach;
canctx.globalCompositeOperation = "source-over";
drawBrick(

View file

@ -1,8 +1,9 @@
import { getHistory } from "./gameOver";
import { icons } from "./loadGameData";
import { appVersion, icons } from "./loadGameData";
import { t } from "./i18n/i18n";
import { asyncAlert } from "./asyncAlert";
import { rawUpgrades } from "./upgrades";
import { getSettingValue, setSettingValue } from "./settings";
export function runHistoryViewerMenuEntry() {
const history = getHistory();
@ -41,6 +42,11 @@ export function runHistoryViewerMenuEntry() {
})),
];
while (true) {
const hasCurrentVersion = history.find(
(r) => r.appVersion === appVersion,
);
const hasPastVersion = history.find((r) => r.appVersion !== appVersion);
const header = columns
.map(
(c, ci) =>
@ -49,6 +55,12 @@ export function runHistoryViewerMenuEntry() {
.join("");
const toString = (v) => v.toString();
const tbody = history
.filter(
(r) =>
!hasCurrentVersion ||
r.appVersion === appVersion ||
getSettingValue("show_old_versions_in_stats", false),
)
.sort(
(a, b) =>
sortDir * (columns[sort].field(a) - columns[sort].field(b)),
@ -77,6 +89,14 @@ export function runHistoryViewerMenuEntry() {
<tbody>${tbody}</tbody>
</table>
`,
hasPastVersion &&
hasCurrentVersion && {
icon: getSettingValue("show_old_versions_in_stats", false)
? icons["icon:checkmark_checked"]
: icons["icon:checkmark_unchecked"],
value: "toggle",
text: t("history.include_past_versions"),
},
],
});
if (!result) return;
@ -89,6 +109,12 @@ export function runHistoryViewerMenuEntry() {
sort = newSort;
}
}
if (result === "toggle") {
setSettingValue(
"show_old_versions_in_stats",
!getSettingValue("show_old_versions_in_stats", false),
);
}
}
},
};

View file

@ -869,8 +869,11 @@ export const rawUpgrades = [
id: "double_or_nothing",
max: 3,
name: t("upgrades.double_or_nothing.name"),
help: (lvl: number) => t("upgrades.double_or_nothing.tooltip",
{percent: lvl*10, multiplier:1+lvl}),
help: (lvl: number) =>
t("upgrades.double_or_nothing.tooltip", {
percent: lvl * 10,
multiplier: 1 + lvl,
}),
fullHelp: t("upgrades.double_or_nothing.verbose_description"),
},
{
@ -882,7 +885,8 @@ export const rawUpgrades = [
name: t("upgrades.wrap_left.name"),
help: () => t("upgrades.wrap_left.tooltip"),
fullHelp: t("upgrades.wrap_left.verbose_description"),
}, {
},
{
requires: "",
threshold: 245000,
gift: false,