diff --git a/src/PWA/sw-b71.js b/src/PWA/sw-b71.js
index 9f945fb..fc07767 100644
--- a/src/PWA/sw-b71.js
+++ b/src/PWA/sw-b71.js
@@ -1,5 +1,5 @@
// The version of the cache.
-const VERSION = "29123607";
+const VERSION = "29126551";
// The name of the cache
const CACHE_NAME = `breakout-71-${VERSION}`;
diff --git a/src/data/levels.json b/src/data/levels.json
index acc34aa..be47698 100644
--- a/src/data/levels.json
+++ b/src/data/levels.json
@@ -149,6 +149,12 @@
"bricks": "__________t__W_tt_WWW_t__W_ttt______",
"credit": ""
},
+ {
+ "name": "icon:extra_life",
+ "size": 5,
+ "bricks": "_W_W_WGWGWWGGGW_WGW___W__",
+ "credit": "By Noodlemire"
+ },
{
"name": "icon:forgiving",
"size": 8,
@@ -263,6 +269,12 @@
"bricks": "gggggggggggggggggggggg______ggggg____ggg_g_gggg_g___gg__gg____g____g____g____g_____g__g_______gg____",
"credit": ""
},
+ {
+ "name": "icon:one_more_choice",
+ "size": 6,
+ "bricks": "WW____WGG___WGWW___GWGG___WGG____GG_",
+ "credit": "By Noodlemire"
+ },
{
"name": "icon:ottawa_treaty",
"size": 8,
@@ -402,10 +414,10 @@
"credit": ""
},
{
- "name": "Big turtle",
- "size": 10,
- "bricks": "_____________kk_______kkkk_____kkkkkkGG__kkkkkkGBG_kkkkkkGGGGkkkkkkGG__GGGGGG____GG__GG_____________",
- "credit": ""
+ "name": "icon:slow_down",
+ "size": 6,
+ "bricks": "________k_G__kkkBG_kkkGGGGGG___G_G__",
+ "credit": "By Noodlemire"
},
{
"name": "icon:smaller_puck",
@@ -539,6 +551,30 @@
"bricks": "___W_____b_____b_____y_____y_____b_____b____WWW__",
"credit": ""
},
+ {
+ "name": "icon:wrap_up",
+ "size": 8,
+ "bricks": "___y__b___b__b____b__b___b__b____b__b___b__b____b__y____WWW_____",
+ "credit": ""
+ },
+ {
+ "name": "icon:yoyo",
+ "size": 5,
+ "bricks": "_GGG_GGGGG_WWW_GWGGG_GWG_",
+ "credit": "By Noodlemire"
+ },
+ {
+ "name": "icon:zen",
+ "size": 7,
+ "bricks": "___t___t_btb_tbtbtbtbtbtbtbtttbrbtt_trBrt____r___",
+ "credit": "By Noodlemire"
+ },
+ {
+ "name": "Big turtle",
+ "size": 10,
+ "bricks": "_____________kk_______kkkk_____kkkkkkGG__kkkkkkGBG_kkkkkkGGGGkkkkkkGG__GGGGGG____GG__GG_____________",
+ "credit": ""
+ },
{
"name": "Big yoyo",
"size": 8,
@@ -1536,59 +1572,21 @@
"credit": "https://www.gog.com/en/game/teleglitch_die_more_edition"
},
{
- "color": "#000000",
+ "name": "Piñata",
"size": 11,
"bricks": "____OOO______OSOBOSO___SOO___OOS__OSS_b_SSO___O_y_b_O____b___y__y____y____y___y_b__y_b___b___b____yy__y___y_b___b___b____",
- "name": "Piñata",
"credit": "By Obigre"
},
{
- "color": "#000000",
+ "name": "Zen monk",
"size": 7,
"bricks": "_ee__B__ee_B_BOOOO_e_SOOOOO_SSeO___OOSSS__SSSSO__",
- "name": "Zen monk",
"credit": "By Obigre"
},
{
- "color": "#000000",
- "size": 7,
- "bricks": "___t___t_btb_tbtbtbtbtbtbtbtttbrbtt_trBrt____r___",
- "name": "icon:zen",
- "credit": "By Noodlemire"
- },
- {
- "color": "#000000",
+ "name": "Lotus flower",
"size": 9,
"bricks": "____t_____tBbtbBt__tbtttbt_bbbtttbbbBbbtttbbBtttbtbttt___RBR_______R________R____",
- "name": "Lotus flower",
"credit": "A little bit bigger than the Zen icon, by Obigre"
- },
- {
- "color": "#000000",
- "size": 6,
- "bricks": "________k_G__kkkBG_kkkGGGGGG___G_G__",
- "name": "icon:slow_down",
- "credit": "By Noodlemire"
- },
- {
- "color": "#000000",
- "size": 5,
- "bricks": "_W_W_WGWGWWGGGW_WGW___W__",
- "name": "icon:extra_life",
- "credit": "By Noodlemire"
- },
- {
- "color": "#000000",
- "size": 5,
- "bricks": "_GGG_GGGGG_WWW_GWGGG_GWG_",
- "name": "icon:yoyo",
- "credit": "By Noodlemire"
- },
- {
- "color": "#000000",
- "size": 6,
- "bricks": "WW____WGG___WGWW___GWGG___WGG____GG_",
- "name": "icon:one_more_choice",
- "credit": "By Noodlemire"
}
]
diff --git a/src/data/version.json b/src/data/version.json
index 820e5f1..73deb97 100644
--- a/src/data/version.json
+++ b/src/data/version.json
@@ -1 +1 @@
-"29123607"
+"29126551"
diff --git a/src/gameStateMutators.ts b/src/gameStateMutators.ts
index be96d06..1caed0c 100644
--- a/src/gameStateMutators.ts
+++ b/src/gameStateMutators.ts
@@ -14,6 +14,7 @@ import {
brickCenterX,
brickCenterY,
canvasCenterX,
+ countBrickColors,
currentLevelInfo,
distance2,
distanceBetween,
@@ -27,6 +28,7 @@ import {
max_levels,
reachRedRowIndex,
shouldPierceByColor,
+ sumOfValues,
telekinesisEffectRate,
yoyoEffectRate,
zoneLeftBorderX,
@@ -509,7 +511,6 @@ export function explodeBrick(
gameState.perks.left_is_lava +
gameState.perks.right_is_lava +
gameState.perks.top_is_lava +
- gameState.perks.picky_eater +
gameState.perks.asceticism * 3 +
gameState.perks.passive_income +
gameState.perks.addiction;
@@ -531,6 +532,10 @@ export function explodeBrick(
}
}
+ if (gameState.perks.picky_eater) {
+ comboGain += gameState.perks.picky_eater * countBrickColors(gameState);
+ }
+
if (redRowReach !== -1) {
if (Math.floor(index / gameState.level.size) === redRowReach) {
resetComboNeeeded = true;
@@ -1261,6 +1266,10 @@ export function gameStateTick(
);
}
+ if (gameState.perks.wrap_up > 1 && hitBorder >= 2) {
+ applyWrapUp(gameState, coin, gameState.coinSize / 2);
+ }
+
if (
coin.previousY < gameState.gameZoneHeight &&
coin.y > gameState.gameZoneHeight &&
@@ -1835,6 +1844,10 @@ export function ballTick(gameState: GameState, ball: Ball, frames: number) {
);
}
+ if (gameState.perks.wrap_up && borderHitCode >= 2) {
+ applyWrapUp(gameState, ball, gameState.ballSize / 2);
+ }
+
if (
gameState.perks.left_is_lava &&
borderHitCode % 2 &&
@@ -1856,6 +1869,7 @@ export function ballTick(gameState: GameState, ball: Ball, frames: number) {
if (gameState.perks.top_is_lava && borderHitCode >= 2) {
resetCombo(gameState, ball.x, ball.y);
}
+
if (gameState.perks.trampoline) {
offsetCombo(gameState, -gameState.perks.trampoline, ball.x, ball.y);
}
@@ -2394,3 +2408,26 @@ export function zenTick(gameState: GameState) {
);
}
}
+
+function applyWrapUp(gameState: GameState, ball: Ball | Coin, radius) {
+ schedulGameSound(gameState, "plouf", ball.x, 1);
+
+ ball.y = gameState.gameZoneHeight - gameState.puckHeight - radius;
+ ball.x = clamp(
+ gameState.puckPosition,
+ gameState.offsetXRoundedDown + radius,
+ gameState.canvasWidth - gameState.offsetXRoundedDown - radius,
+ );
+ if (ball.vy > 0) {
+ ball.vy *= -1;
+ }
+
+ spawnParticlesExplosion(gameState, 7, ball.x, ball.y, "#6262EA");
+ spawnParticlesImplosion(
+ gameState,
+ 7,
+ ball.previousX,
+ ball.previousY,
+ "#6262EA",
+ );
+}
diff --git a/src/game_utils.ts b/src/game_utils.ts
index 3863a0e..3a674bd 100644
--- a/src/game_utils.ts
+++ b/src/game_utils.ts
@@ -355,3 +355,14 @@ export function zoneLeftBorderX(gameState: GameState) {
export function zoneRightBorderX(gameState: GameState) {
return gameState.canvasWidth - gameState.offsetXRoundedDown + 1;
}
+
+let countsCounterSet: Record
= {};
+export function countBrickColors(gameState: GameState) {
+ for (let key in countsCounterSet) {
+ countsCounterSet[key] = 0;
+ }
+ gameState.bricks.forEach((brick) => {
+ if (brick && brick !== "black") countsCounterSet[brick] = 1;
+ });
+ return sumOfValues(countsCounterSet);
+}
diff --git a/src/help.ts b/src/help.ts
index 5a195d6..9ce88ca 100644
--- a/src/help.ts
+++ b/src/help.ts
@@ -1,4 +1,4 @@
-import { allLevels, icons, upgrades } from "./loadGameData";
+import { allLevels, allLevelsAndIcons, icons, upgrades } from "./loadGameData";
import { t } from "./i18n/i18n";
import { asyncAlert } from "./asyncAlert";
import { miniMarkDown } from "./pure_functions";
@@ -37,7 +37,7 @@ export function helpMenuEntry() {
`,
),
"" + t("help.levels") + "
",
- ...allLevels
+ ...allLevelsAndIcons
.filter((l) => l.credit?.trim())
.map(
(l) => `
diff --git a/src/i18n/ar.json b/src/i18n/ar.json
index a6c46d9..7de4d9e 100644
--- a/src/i18n/ar.json
+++ b/src/i18n/ar.json
@@ -474,6 +474,9 @@
"upgrades.wrap_right.name": "لف إلى اليمين",
"upgrades.wrap_right.tooltip": "ضرب الجانب الأيمن ينقل الكرة إلى الجانب الأيسر",
"upgrades.wrap_right.verbose_description": "يمكن نقل العملات المعدنية إلى المستويات الأعلى أيضًا.",
+ "upgrades.wrap_up.name": "اختتام",
+ "upgrades.wrap_up.tooltip": "سوف يؤدي لمس الجزء العلوي من الشاشة إلى نقل الكرة إلى ما فوق المضرب مباشرة.",
+ "upgrades.wrap_up.verbose_description": "لن يُحتسب هذا كضربة قرص. في المستوى الثاني، تنتقل العملات المعدنية أيضًا.",
"upgrades.yoyo.name": "يو يو",
"upgrades.yoyo.tooltip": "الكرة تسقط نحو المضرب",
"upgrades.yoyo.verbose_description": "إنه عكس التحريك الذهني، أي التحكم بالكرة أثناء سقوطها مرة أخرى إلى الأسفل.",
diff --git a/src/i18n/b71.babel b/src/i18n/b71.babel
index 3ee7e15..6375281 100644
--- a/src/i18n/b71.babel
+++ b/src/i18n/b71.babel
@@ -17127,6 +17127,116 @@
+
+ wrap_up
+
+
+ name
+
+
+
+
+ ar-LB
+ false
+
+
+ de-DE
+ false
+
+
+ en-US
+ false
+
+
+ es-CL
+ false
+
+
+ fr-FR
+ false
+
+
+ ru-RU
+ false
+
+
+ tr-TR
+ false
+
+
+
+
+ tooltip
+
+
+
+
+ ar-LB
+ false
+
+
+ de-DE
+ false
+
+
+ en-US
+ false
+
+
+ es-CL
+ false
+
+
+ fr-FR
+ false
+
+
+ ru-RU
+ false
+
+
+ tr-TR
+ false
+
+
+
+
+ verbose_description
+
+
+
+
+ ar-LB
+ false
+
+
+ de-DE
+ false
+
+
+ en-US
+ false
+
+
+ es-CL
+ false
+
+
+ fr-FR
+ false
+
+
+ ru-RU
+ false
+
+
+ tr-TR
+ false
+
+
+
+
+
yoyo
diff --git a/src/i18n/de.json b/src/i18n/de.json
index bf5bbed..013cc2a 100644
--- a/src/i18n/de.json
+++ b/src/i18n/de.json
@@ -474,6 +474,9 @@
"upgrades.wrap_right.name": "Rechts umbrechen",
"upgrades.wrap_right.tooltip": "Wenn Sie die rechte Seite treffen, wird der Ball auf die linke Seite teleportiert",
"upgrades.wrap_right.verbose_description": "Höhere Level teleportieren auch Münzen.",
+ "upgrades.wrap_up.name": "Einpacken",
+ "upgrades.wrap_up.tooltip": "Durch Berühren der Oberseite des Bildschirms wird der Ball direkt über den Schläger teleportiert.",
+ "upgrades.wrap_up.verbose_description": "Dies zählt nicht als Pucktreffer. Auf Stufe 2 werden auch Münzen teleportiert.",
"upgrades.yoyo.name": "Yo-Yo",
"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.",
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 8ebb200..be927c1 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -374,7 +374,7 @@
"upgrades.passive_income.verbose_description": "+{{lvl}} combo / brick broken, paddle is immaterial {{time}}s after moving. Some perks can help the balls do what you want without needing to do anything.",
"upgrades.picky_eater.name": "Picky eater",
"upgrades.picky_eater.tooltip": "More coins if you break bricks color by color",
- "upgrades.picky_eater.verbose_description": "Whenever you break a brick the same color as your ball, your combo increases by one. \nIf it's a different color, the ball takes that new color, but the combo resets, unless there were no bricks left of the ball's color. \nOnce you get a combo higher than your minimum, the bricks of the wrong color will get a red border. \nIf you have more than one ball, they all switch color whenever one of them hits a brick.",
+ "upgrades.picky_eater.verbose_description": "Whenever you break a brick the same color as your ball, your combo increases by the number of colors on screen. \nIf it's a different color, the ball takes that new color, but the combo resets, unless there were no bricks left of the ball's color. \nOnce you get a combo higher than your minimum, the bricks of the wrong color will get a red border. \nIf you have more than one ball, they all switch color whenever one of them hits a brick.",
"upgrades.pierce.name": "Piercing",
"upgrades.pierce.tooltip": "Ball pierces {{count}} bricks after a paddle bounce",
"upgrades.pierce.verbose_description": "The ball normally bounces as soon as it touches something. With this perk, it will continue its trajectory for up to 3 bricks broken. \n\nAfter that, it will bounce on the 4th brick, and you'll need to touch the paddle to reset the counter.",
@@ -474,6 +474,9 @@
"upgrades.wrap_right.name": "Wrap right",
"upgrades.wrap_right.tooltip": "Hitting the right side teleports the ball to the left side",
"upgrades.wrap_right.verbose_description": "Higher levels teleport coins too.",
+ "upgrades.wrap_up.name": "Wrap up",
+ "upgrades.wrap_up.tooltip": "Touching the top of the screen will teleport the ball just above the paddle.",
+ "upgrades.wrap_up.verbose_description": "This won't count as a puck hit. At level 2, coins teleport too. ",
"upgrades.yoyo.name": "Yo-yo",
"upgrades.yoyo.tooltip": "The ball falls toward the paddle",
"upgrades.yoyo.verbose_description": "It's the opposite of telekinesis, control the ball while it's falling back down.",
diff --git a/src/i18n/es.json b/src/i18n/es.json
index ea5655b..ee82a68 100644
--- a/src/i18n/es.json
+++ b/src/i18n/es.json
@@ -474,6 +474,9 @@
"upgrades.wrap_right.name": "Envolver a la derecha",
"upgrades.wrap_right.tooltip": "Golpear el lado derecho teletransporta la pelota al lado izquierdo.",
"upgrades.wrap_right.verbose_description": "Los niveles superiores también teletransportan monedas.",
+ "upgrades.wrap_up.name": "Envolver",
+ "upgrades.wrap_up.tooltip": "Al tocar la parte superior de la pantalla, la pelota se teletransportará justo por encima de la paleta.",
+ "upgrades.wrap_up.verbose_description": "Esto no cuenta como golpe de disco. En el nivel 2, las monedas también se teletransportan.",
"upgrades.yoyo.name": "Yo-Yo",
"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.",
diff --git a/src/i18n/fr.json b/src/i18n/fr.json
index 8a538bd..e66351e 100644
--- a/src/i18n/fr.json
+++ b/src/i18n/fr.json
@@ -474,6 +474,9 @@
"upgrades.wrap_right.name": "Envelopper à droite",
"upgrades.wrap_right.tooltip": "Frapper le côté droit téléporte la balle vers le côté gauche",
"upgrades.wrap_right.verbose_description": "Les niveaux supérieurs téléportent également des pièces.",
+ "upgrades.wrap_up.name": "Conclure",
+ "upgrades.wrap_up.tooltip": "Toucher le haut de l'écran téléportera la balle juste au-dessus de la raquette.",
+ "upgrades.wrap_up.verbose_description": "Cela ne compte pas comme un coup de rondelle. Au niveau 2, les pièces se téléportent également.",
"upgrades.yoyo.name": "Yo-yo",
"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.",
diff --git a/src/i18n/ru.json b/src/i18n/ru.json
index c4b26cd..411398a 100644
--- a/src/i18n/ru.json
+++ b/src/i18n/ru.json
@@ -474,6 +474,9 @@
"upgrades.wrap_right.name": "Обернуть вправо",
"upgrades.wrap_right.tooltip": "Удар по правой стороне телепортирует мяч на левую сторону.",
"upgrades.wrap_right.verbose_description": "Более высокие уровни также телепортируют монеты.",
+ "upgrades.wrap_up.name": "Заворачивать",
+ "upgrades.wrap_up.tooltip": "Прикосновение к верхней части экрана телепортирует мяч чуть выше ракетки.",
+ "upgrades.wrap_up.verbose_description": "Это не будет считаться попаданием шайбы. На уровне 2 монеты тоже телепортируются.",
"upgrades.yoyo.name": "Йо-йо",
"upgrades.yoyo.tooltip": "Мяч падает на лопатку",
"upgrades.yoyo.verbose_description": "Это противоположность телекинезу: управляйте мячом, пока он падает обратно.",
diff --git a/src/i18n/tr.json b/src/i18n/tr.json
index e8f3986..db2250b 100644
--- a/src/i18n/tr.json
+++ b/src/i18n/tr.json
@@ -474,6 +474,9 @@
"upgrades.wrap_right.name": "Sağa doğru sarın",
"upgrades.wrap_right.tooltip": "Sağ tarafa vurmak topu sol tarafa ışınlar",
"upgrades.wrap_right.verbose_description": "Daha yüksek seviyelerde ışınlanma paraları da var.",
+ "upgrades.wrap_up.name": "Özetlemek gerekirse",
+ "upgrades.wrap_up.tooltip": "Ekranın üst kısmına dokunduğunuzda top, küreğin hemen üstüne ışınlanacaktır.",
+ "upgrades.wrap_up.verbose_description": "Bu bir disk vuruşu olarak sayılmaz. 2. seviyede, paralar da ışınlanır.",
"upgrades.yoyo.name": "Yo-yo",
"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.",
diff --git a/src/render.ts b/src/render.ts
index 24430bf..ac10a1e 100644
--- a/src/render.ts
+++ b/src/render.ts
@@ -425,7 +425,8 @@ export function render(gameState: GameState) {
ctx.lineWidth = 2;
ctx.setLineDash(emptyArray);
}
- ctx.globalAlpha = 1;
+
+ ctx.globalAlpha = ballAlpha;
if (
(gameState.perks.clairvoyant && gameState.ballStickToPuck) ||
(gameState.perks.steering > 1 && !gameState.ballStickToPuck)
diff --git a/src/upgrades.ts b/src/upgrades.ts
index 53ebb1f..3e72441 100644
--- a/src/upgrades.ts
+++ b/src/upgrades.ts
@@ -969,4 +969,15 @@ export const rawUpgrades = [
help: (lvl: number) => t("upgrades.steering.tooltip"),
fullHelp: (lvl: number) => t("upgrades.steering.verbose_description"),
},
+ {
+ category: categories.advanced,
+ requires: "",
+ threshold: 255000,
+ gift: false,
+ id: "wrap_up",
+ max: 1,
+ name: t("upgrades.wrap_up.name"),
+ help: (lvl: number) => t("upgrades.wrap_up.tooltip"),
+ fullHelp: (lvl: number) => t("upgrades.wrap_up.verbose_description"),
+ },
] as const;