diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ea157f1..c98810a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -29,8 +29,8 @@ android { applicationId = "me.lecaro.breakout" minSdk = 21 targetSdk = 34 - versionCode = 29088937 - versionName = "29088937" + versionCode = 29090246 + versionName = "29090246" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { useSupportLibrary = true diff --git a/app/src/main/assets/index.html b/app/src/main/assets/index.html deleted file mode 100644 index 491e7db..0000000 --- a/app/src/main/assets/index.html +++ /dev/null @@ -1 +0,0 @@ -Breakout 71 \ No newline at end of file diff --git a/dist/index.html b/dist/index.html index 37cbc01..dcce567 100644 --- a/dist/index.html +++ b/dist/index.html @@ -569,6 +569,16 @@ h2.histogram-title strong { opacity: .8; color: #8a8a8a; } + +.help_button_tooltip { + z-index: 8; + background: #000; + border-bottom: 1px solid #fff; + padding: 20px; + position: fixed; + top: 0; + left: 0; +} @@ -1397,7 +1407,7 @@ async function openUnlockedUpgradesList() { help: ts < threshold ? (0, _i18N.t)("unlocks.minTotalScore", { score: threshold }) : help(1), - tooltip: ts < threshold ? '' : fullHelp + tooltip: ts < threshold ? "" : fullHelp })); const tryOn = await (0, _asyncAlert.asyncAlert)({ title: (0, _i18N.t)("unlocks.title_upgrades", { @@ -1565,12 +1575,12 @@ document.getElementById("menu")?.setAttribute("data-tooltip", (0, _i18N.t)("play },{"./loadGameData":"l1B4x","./sounds":"dQKPV","./game_utils":"cEeac","./PWA/sw_loader":"2n0gK","./i18n/i18n":"eNPRm","./settings":"5blfu","./gameStateMutators":"9ZeQl","./render":"9AS2t","./recording":"godmD","./newGameState":"aQN6X","./asyncAlert":"rSqLY","./options":"d5NoS","./pure_functions":"6pQh7","./help":"bqkdF","./creative":"63kYJ","./tooltip":"3RWxb","./startingPerks":"lv30m","./migrations":"a9qdY","./gameOver":"caCAf","./generateSaveFileContent":"iEcoB","./runHistoryViewer":"b80Ki","./openScorePanel":"aHTmD","./monitorLevelsUnlocks":"jjD0P","./levelEditor":"cirX1","@parcel/transformer-js/src/esmodule-helpers.js":"gkKU3","./upgrades":"1u3Dx"}],"l1B4x":[function(require,module,exports,__globalThis) { var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js"); parcelHelpers.defineInteropFlag(exports); +parcelHelpers.export(exports, "upgrades", ()=>upgrades); parcelHelpers.export(exports, "appVersion", ()=>appVersion); parcelHelpers.export(exports, "icons", ()=>icons); parcelHelpers.export(exports, "transformRawLevel", ()=>transformRawLevel); parcelHelpers.export(exports, "allLevelsAndIcons", ()=>allLevelsAndIcons); parcelHelpers.export(exports, "allLevels", ()=>allLevels); -parcelHelpers.export(exports, "upgrades", ()=>upgrades); var _paletteJson = require("./data/palette.json"); var _paletteJsonDefault = parcelHelpers.interopDefault(_paletteJson); var _levelsJson = require("./data/levels.json"); @@ -1581,6 +1591,9 @@ var _upgrades = require("./upgrades"); var _getLevelBackground = require("./getLevelBackground"); var _levelIcon = require("./levelIcon"); var _pureFunctions = require("./pure_functions"); +const upgrades = [ + ...(0, _upgrades.rawUpgrades) +].sort((a, b)=>a.category - b.category || a.threshold - b.threshold); const palette = (0, _paletteJsonDefault.default); const rawLevelsList = (0, _levelsJsonDefault.default); const appVersion = (0, _versionJsonDefault.default); @@ -1589,7 +1602,7 @@ function transformRawLevel(level) { const splitBricks = level.bricks.split(""); const bricks = splitBricks.map((c)=>palette[c]).slice(0, level.size * level.size); const bricksCount = bricks.filter((i)=>i).length; - const icon = (0, _levelIcon.levelIconHTML)(bricks, level.size, level.color); + const icon = (0, _levelIcon.levelIconHTML)(bricks, level.size); icons[level.name] = icon; return { ...level, @@ -1603,10 +1616,6 @@ function transformRawLevel(level) { } const allLevelsAndIcons = rawLevelsList.map(transformRawLevel); const allLevels = allLevelsAndIcons.filter((l)=>!l.name.startsWith("icon:")); -const upgrades = (0, _upgrades.rawUpgrades).map((u)=>({ - ...u, - icon: icons["icon:" + u.id] - })); },{"./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","./pure_functions":"6pQh7"}],"ktRBU":[function(require,module,exports,__globalThis) { module.exports = JSON.parse("{\"_\":\"\",\"B\":\"black\",\"W\":\"#FFFFFF\",\"g\":\"#231f20\",\"y\":\"#FFD300\",\"b\":\"#6262EA\",\"t\":\"#5DA3EA\",\"s\":\"#E67070\",\"r\":\"#e32119\",\"R\":\"#ab0c0c\",\"c\":\"#59EEA3\",\"G\":\"#A1F051\",\"v\":\"#A664E8\",\"p\":\"#E869E8\",\"a\":\"#5BECEC\",\"C\":\"#53EE53\",\"S\":\"#F44848\",\"P\":\"#E66BA8\",\"O\":\"#F29E4A\",\"k\":\"#618227\",\"e\":\"#e1c8b4\",\"l\":\"#9b9fa4\"}"); @@ -1615,7 +1624,7 @@ module.exports = JSON.parse("{\"_\":\"\",\"B\":\"black\",\"W\":\"#FFFFFF\",\"g\" module.exports = JSON.parse('[{"name":"icon:addiction","size":9,"bricks":"__________________________t__WWWWW_tWWWrrttttr_WWWWW_tr_______t__________________","credit":""},{"name":"icon:asceticism","size":8,"bricks":"_tttttt__tt__tt_____W_______r______________r_________r_____WWW__","credit":""},{"name":"icon:ball_attract_ball","size":8,"bricks":"__b__b____b__b__bbW__Wbb________________bbW__Wbb__b__b____b__b__","credit":""},{"name":"icon:ball_attracts_coins","size":8,"bricks":"WWW_____WWW_y___WWW____y__y_y____y____y_____y_____y____y___y_y__","credit":""},{"name":"icon:ball_repulse_ball","size":8,"bricks":"Wbb__bbWb______bb______b________________b______bb______bWbb__bbW","credit":""},{"name":"icon:base_combo","size":7,"bricks":"________ttttt__tytyt__ttttt__tytyt__ttttt________","credit":""},{"name":"icon:bigger_explosions","size":8,"bricks":"__O__Oy___Oyy_____OyOy__OyyyByOO_OOBBBy___yyByO__yOOy_OO_OO_____","credit":""},{"name":"icon:bigger_puck","size":8,"bricks":"_________GGGGGG__GGGGGG______________________W___________WWWWWW_","credit":""},{"name":"icon:bricks_attract_ball","size":8,"bricks":"ttW_____tt_y________y________ytt____y_tt___y____tty_____tt_y____","credit":""},{"name":"icon:bricks_attract_coins","size":9,"bricks":"______________________________bbbybbbbybbb______bbbybb___y_y______b_b______b_b___","credit":""},{"name":"icon:buoy","size":7,"bricks":"___y______y_____yyy__tyyyyytttOOOtttttOtttttttttt","credit":""},{"name":"icon:checkmark_checked","size":6,"bricks":"_ggggbgBBBbbbbBbbggbbbBggBbBBg_gggg_","credit":""},{"name":"icon:checkmark_unchecked","size":6,"bricks":"_gggg_gBBBBggBBBBggBBBBggBBBBg_gggg_","credit":""},{"name":"icon:clairvoyant","size":9,"bricks":"__y___y__y__y_y__y_y__t__y____ttt_____tWWWt___tWWgWWt_tttWWWttt__________________","credit":""},{"name":"icon:coin_magnet","size":8,"bricks":"__y__y_yy_________y_y_y_y________y_y______________y______WWW____","credit":""},{"name":"icon:coins","size":8,"bricks":"__bbbb___bbggbb_bbggggbbbggggggbbggggggbbbggggbb_bbggbb___bbbb__","credit":""},{"name":"icon:compound_interest","size":8,"bricks":"_________tttttt__ttt__t_____W________________r___________WWW__r_","credit":""},{"name":"icon:concave_puck","size":7,"bricks":"___W_____________W__________G__W__GGG___GGGGGGGGG","credit":""},{"name":"icon:corner_shot","size":9,"bricks":"___W________W________W__WW____W__WW____W________W______W_W_WWW_WW_W_WWWWWW_W_WWWW","credit":""},{"name":"icon:creative","size":7,"bricks":"bbg_bgg_______bbb_bgg_______bgg_bbg_______bbg_bbb","credit":""},{"name":"icon:double_or_nothing","size":10,"bricks":"_______________________bbbb____bbbbbbbb__bbbbbbby_bbbbbbbyyybbbbbbyyyy______________________________","credit":""},{"name":"icon:download","size":8,"bricks":"___bb______bb______bb______bb______bb____bbbbbb___bbbb__gggbbggg","credit":""},{"name":"icon:editor","size":10,"bricks":"_______ggg______gggg_____ggggg____ggggg____ggggg____ggggg____ggggg____bgggg_____bbgg______bbb_______","credit":""},{"name":"icon:etherealcoins","size":11,"bricks":"_____y_________yyy________bbb________bbb_______ybbby_____yybbbyy____yybbbyy____yybbbyy____y__y__y________________________","credit":""},{"name":"icon:extra_levels","size":6,"bricks":"__________t__W_tt_WWW_t__W_ttt______","credit":""},{"name":"icon:extra_life","size":9,"bricks":"___________GG_WG___GGWWGGW_GGWWGGWWGGWWGGWWGG_WGGWWGG___GWWGG_____WGG_______G____","credit":""},{"name":"icon:forgiving","size":8,"bricks":"____y______y_y____y___y__y_____yy_____y__y___y____y_y____WWWWW__","credit":""},{"name":"icon:fountain_toss","size":12,"bricks":"_____________________y_________y______________y______y__y_____WWWWWWWW___WttttttttW_WtytttytyttWWtttyttttttWWWtyttttytWW_WWWWWWWWWW___WWWWWWWWW_","credit":""},{"name":"icon:ghost_coins","size":7,"bricks":"__bbb___bbbbb_bbybybbbbbbbbbbbyyybbbbbbbbbbb_b_bb","credit":""},{"name":"icon:happy_family","size":9,"bricks":"__tt_tt____tt_tt____tt_tt____________________W_______W__W_W_W___________rrrWWWrrr","credit":""},{"name":"icon:helium","size":8,"bricks":"_y____y_yb____bybb___ybbb____b_b_____b____________________WWW___","credit":""},{"name":"icon:help","size":8,"bricks":"___bb_____bbbb___bb__bb__bb__bb_____bb_____bb______________bb___","credit":""},{"name":"icon:history","size":8,"bricks":"__gggg___ggbggg_gggbgggggggbggggggggbbgggggggggg_gggggg___gggg__","credit":""},{"name":"icon:hot_start","size":7,"bricks":"tt__ttt__t_trt_t__tttt_____ttttWttt________WWW___","credit":""},{"name":"icon:hypnosis","size":8,"bricks":"_bbby____bbb_y___bbby_y__y_y_y_y__y_y_y____y_y_y____y_y______y_y","credit":""},{"name":"icon:implosions","size":8,"bricks":"y______b___yb_b__y_Bbb_____Bbbby_bbbB_____bbB___yb_by___b_____y_","credit":""},{"name":"icon:left_is_lava","size":8,"bricks":"r_______rtttttt_rtttttt_r_______r_______r____W__r_______r_WWW___","credit":""},{"name":"icon:limitless","size":12,"bricks":"_________________________bbb____yyb_bbbbb__yyybbbb_bbbyyy_bbbb__bbby__bbbb_yybbb__bbyyyyyybbbbbb_yyy___bbbb_____________________________________","credit":""},{"name":"icon:metamorphosis","size":8,"bricks":"yyyyyy__yyyy__________W___________bbyybb__bbbbbb_________WWW____","credit":""},{"name":"icon:minefield","size":7,"bricks":"tB___Bttt___tt__ByB____yyy__tB___Bttt___tt_______","credit":""},{"name":"icon:multiball","size":8,"bricks":"_________tttttt__tttttt___________W__W____________________WWW___","credit":""},{"name":"icon:nbricks","size":7,"bricks":"________tttrt__ttr_r____________W__________WWW___","credit":""},{"name":"icon:new_run","size":7,"bricks":"_ggg____gbgg___gbbgg__gbbbg__gbbgg__gbgg___ggg___","credit":""},{"name":"icon:one_more_choice","size":7,"bricks":"WWW____WGGG___WGWWW__WGWGGG__GWGGG___WGGG____GGG_","credit":""},{"name":"icon:ottawa_treaty","size":8,"bricks":"BBbyybBBBbbyybbBbyybbbybbbyyyybbbbbyybbbbbyyybbbByybybbBBBbbbyBB","credit":""},{"name":"icon:passive_income","size":8,"bricks":"_ttttt___ttt_t______yW_____________y______________WWW_______y___","credit":""},{"name":"icon:picky_eater","size":8,"bricks":"_rrr_______rt_____rtt_____r_t______ttt_______W____________WWWW__","credit":""},{"name":"icon:pierce","size":6,"bricks":"ttttttttttWtttt__ttt__ttt__ttt__tttt","credit":""},{"name":"icon:pierce_color","size":8,"bricks":"tt___tttt__t_ttt_____ttt____ttttt____ttttt____ttttt____ttttt____","credit":""},{"name":"icon:premium","size":11,"bricks":"__g____g___g____g____g_g__gbg__g______g______gg_gbg_gg_gbbgbbbgbbggbbgbbbgbbg_gbgbbbgbg___ggggggg____ggggggg_____________","credit":""},{"name":"icon:puck_repulse_ball","size":8,"bricks":"__________________W_______b___W___b__b______b____________WWW____","credit":""},{"name":"icon:rainbow","size":10,"bricks":"yyyyybbb__yyyybbb___yyybbbr___yybbbOrr__ybbbyOOrr_bbbCyyOOrrbbtCCyyOOrb_ttCCyyOO___ttCCyyO____ttCCyy","credit":""},{"name":"icon:reach","size":8,"bricks":"tttttttttttttttttt____ttrr____rr___________W_____________WWW____","credit":""},{"name":"icon:reroll","size":8,"bricks":"__llllll_llBlBlelllllleBWWWWWeeeWBWBWeBeWWWWWeeeWBWBWBe_WWWWWe__","credit":""},{"name":"icon:reset","size":8,"bricks":"bb____bbbbb__bbb_bbbbbb___bbbb____bbbb___bbbbbb_bbb__bbbbb____bb","credit":""},{"name":"icon:respawn","size":9,"bricks":"tttttytttttttyyytttttttyttt_____________________________W_________________WWW____","credit":""},{"name":"icon:right_is_lava","size":8,"bricks":"_______r_ttttttr_ttttttr_______r_______r_____W_r_______r__WWW__r","credit":""},{"name":"icon:sacrifice","size":9,"bricks":"__b___b___bbb_bbb_bbyyyyybbbbybybybbbbyybyybb_bbyyybb___bybyb_____bbb_______b____","credit":""},{"name":"icon:sapper","size":9,"bricks":"_____WW______W__W_tttWttt_yttgggtt__tgggggt__tgggggt__tgggggt__ttgggtt__ttttttt__","credit":""},{"name":"icon:settings","size":9,"bricks":"___g_g____g_ggg_g___ggbgg__gggbbbggg_gbb_bbg_gggbbbggg__ggbgg___g_ggg_g____g_g___","credit":""},{"name":"icon:shocks","size":8,"bricks":"____y_Oy_bbbO_y__bbbOO_O_bbby_yyyyOyyOO_OO_ybbb__yO_bbb_y__ybbb_","credit":""},{"name":"icon:shunt","size":8,"bricks":"_______y______yy______yy__yttyyy__y__yyy_yy__yyy_yy__yyyyyy__yyy","credit":""},{"name":"icon:side_flip","size":7,"bricks":"________rtttt__rtttt____________W__________WWW___","credit":""},{"name":"icon:side_kick","size":7,"bricks":"________ttttr__ttttr__________W______________WWW_","credit":""},{"name":"icon:skip_last","size":5,"bricks":"_GGG_G_G_GGG_GGG_G_G_GGG_","credit":""},{"name":"icon:slow_down","size":10,"bricks":"_____________kk_______kkkk_____kkkkkkGG__kkkkkkGBG_kkkkkkGGGGkkkkkkGG__GGGGGG____GG__GG_____________","credit":""},{"name":"icon:smaller_puck","size":8,"bricks":"_________bbbbbb__bbbbbb_____________y_____________________yy____","credit":""},{"name":"icon:soft_reset","size":9,"bricks":"__yy______yyy_tt__yyyy_ttt_yyyy_tttt_____tttt_tttttttt_tttttttt__tttttt____tttt__","credit":""},{"name":"icon:starting_perks","size":8,"bricks":"_________b_b_b___________g_g_g_g_________g_g_g_g_________g_g_g_g","credit":""},{"name":"icon:sticky_coins","size":8,"bricks":"__________yy_yy___bbbby__ybbbb___ybbbb____bbbby______yy_________","credit":""},{"name":"icon:streak_shots","size":8,"bricks":"_tttttt__ttWttt___W_W____W___W__W_____W__W___W____W_W_____rrr___","credit":""},{"name":"icon:sturdy_bricks","size":7,"bricks":"tttttttttttttt____y_____y_y___y___y_______WWW____","credit":""},{"name":"icon:superhot","size":11,"bricks":"____________________________________________W_W_WWW_WWWWWW_W_W__W_W_W_WWW__W_____________________________________________","credit":""},{"name":"icon:telekinesis","size":8,"bricks":"______WW____GGWW___G______G_______G_______G_______G_____WWWWW___","credit":""},{"name":"icon:three_cushion","size":7,"bricks":"tttttttttttttt____r______r______r______r_____WWW_","credit":""},{"name":"icon:top_is_lava","size":8,"bricks":"rrrrrrrr_tttttt__tttttt____________________W_______________WWW__","credit":""},{"name":"icon:trampoline","size":8,"bricks":"_r_r_r_rrtttttt__ttttttrr___________W__rr______________r__WWW___","credit":""},{"name":"icon:transparency","size":9,"bricks":"__t_y_t___________t_y_t_y_t_________y_t_y_t_y_________t_y_t_y_t___________t_y_t__","credit":""},{"name":"icon:trickledown","size":8,"bricks":"_ybbbbbb_________y_y_y__bbbbbb____________y_y_y___bbbbbb_y______","credit":""},{"name":"icon:unbounded","size":8,"bricks":"bbyyyybbbbyyyybbbb____bbbb____bbbb____bbbb__y_bbbb____bbbbyyy_bb","credit":""},{"name":"icon:unlocked_levels","size":9,"bricks":"ggggggggggbbbgbbbggbgggggbggbgbgbgbgggggggggggbgbgbgbggbgggggbggbbbgbbbgggggggggg","credit":""},{"name":"icon:unlocked_upgrades","size":9,"bricks":"___ggg_____ggbgg___ggbbbgg_ggbbgbbgggbbbgbbbggggbgbggg__gbgbg____gbgbg____ggggg__","credit":""},{"name":"icon:upload","size":8,"bricks":"gggbbggg__bbbb___bbbbbb____bb______bb______bb______bb______bb___","credit":""},{"name":"icon:viscosity","size":8,"bricks":"________bb______ttbb__bbttttbbtttbttbtttttbttbtttttyttyttttttttt","credit":""},{"name":"icon:wind","size":9,"bricks":"_bb______b___yyyy_b_________bbbbbbb___________bbbbbbb_b________b___yyyy__bb______","credit":""},{"name":"icon:wrap_left","size":7,"bricks":"__W_______b_______b_______b_y_____b_y______WWW___","credit":""},{"name":"icon:wrap_right","size":7,"bricks":"___W_____b_____b_____b_____y_____y_____y____WWW__","credit":""},{"name":"icon:yoyo","size":8,"bricks":"____W____GGWGGG_GGWGGGGGGWGGGGGG_WWWWWW_GGGGGGGGGGGGGGGG_GGGGGG_","credit":""},{"name":"icon:zen","size":12,"bricks":"________________tttt_______tttttt_______tttt________BrrB_______tttttt_____tttttttt_____tttttt______BrrrrB_____tttttttt___tttttttttt___tttttttt__","credit":""},{"name":"71 mini","size":5,"bricks":"bbb____bt__btt__b_t___ttt","credit":""},{"name":"Butterfly","size":9,"bricks":"_________bb_t_t_bbbbb_t_bbbbbbbtbbbb_bbbtbbb____btb____bbbtbbb__bb_t_bb__________","credit":""},{"name":"Castle","size":7,"bricks":"s_s_s_ssssssssssBBBssssBBBssttbbbttttbbbtttbtbtbt","credit":""},{"name":"Eyes","size":9,"bricks":"ttttttt__tWWWWWWW_tWrrWttW_tWWWWWWW_ttttttt_____t______ttttt____ttttt_____t_t____","credit":"My favorite character in https://nuclearthrone.com/"},{"name":"Creeper","size":10,"bricks":"___________ccGGccGG__cGccGcGc__GBBccBBc__cBBGcBBc__GccBBGGc__ccBBBBcG__GGBBBBcG__cGBccBGc___________","credit":"https://en.wikipedia.org/wiki/Creeper_(Minecraft)"},{"name":"Stairs","size":8,"bricks":"tt______tt______bbtt____bbtt____vvbbtt__vvbbtt__ppvvbbttppvvbbtt","credit":""},{"name":"Dots","size":9,"bricks":"b_t_a_c_c__________b_t_a_c__________P_b_t_a_c__________P_b_t_a__________P_P_b_t_a","credit":""},{"name":"Lines","size":9,"bricks":"aaaaaaaa___________tttttttt_________aaaaaaaa___________tttttttt_________aaaaaaaa_","credit":""},{"name":"Heart","size":15,"bricks":"__________________RRR___RRR_____RSSSR_RSSSR___RSWWSSRSSSSSR__RSWSSSSSSSSSR__RSSSSSSSSSSSR__RSWSSSSSSSSSR___RSSSSSSSSSR_____RSSSSSSSR_______RSSSSSR_________RSSSR___________RSR_____________R_____________________________________","credit":"https://www.youtube.com/watch?v=gdWiTfzXb1g"},{"name":"Swiss","size":7,"bricks":"________RRRRR__RRWRR__RWWWR__RRWRR__RRRRR________","credit":""},{"name":"Germany","size":4,"bricks":"____ggggrrrryyyy","credit":""},{"name":"France","size":6,"bricks":"______ttWWrrttWWrrttWWrrttWWrrttWWrr","credit":""},{"name":"Smiley","size":8,"bricks":"_________yy__yy__yy__yy__________________yyyyyy___yyyy__________","credit":""},{"name":"Labyrinthe","size":11,"bricks":"_______tttS_Stttt_S________t___S__Stt_ttttt____t_____S__ttt_S_S____t___t_tttt_t_S_t____tSt_t_t_Sttt___t_t_____Sttt_tttttS","credit":""},{"name":"Temple","size":11,"bricks":"_______________WWW______WWWWWWW___WWWWWWWWW___b_b_b_b____b_b_b_b____v_v_v_v____P_P_P_P____P_P_P_P____WWWWWWW___WWWWWWWWW_","credit":""},{"name":"Pacman","size":12,"bricks":"____yyyy______yyyyyyyy___yyyyByyyyy__yyyyyyyyy__yyyyyyyy____yyyyyy______yyyyyy___S_Syyyyyyyy_____yyyyyyyyy___yyyyyyyyyy___yyyyyyyy______yyyy____","credit":"https://en.wikipedia.org/wiki/Pacman"},{"name":"Ship","size":11,"bricks":"____sWW________sWWW_______sWWW_______s___OOOOOOOOOOOOOO_OBOBOBOBOO__OOOOOOOO_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb___________","credit":""},{"name":"We come in peace","size":13,"bricks":"________________a_____a_______a___a_______aaaaaaa_____aaBaaaBaa___aaaaaaaaaaa__aaaaaaaaaaa__a_aaaaaaa_a__a_a_____a_a_____aa_aa___________________________________________","credit":"https://en.wikipedia.org/wiki/Space_invaders"},{"name":"Space mushroom","size":10,"bricks":"______________WW_______WWWW_____WWWWWW___WWBWWBWW__WWWWWWWW____W__W_____W_WW_W___W_W__W_W___________","credit":"https://en.wikipedia.org/wiki/Space_invaders"},{"name":"Wololo","size":9,"bricks":"____WW_OOW___WW__OWW__W___OWWWbbbW_WWW_WbW_WOW__WWb__OW__bbb__O___W_W__O___W_W__O","credit":"https://aoe.heavengames.com/theacademy/unitsboatsandbuildings/priest/"},{"name":"Small heart","size":15,"bricks":"________________________________RRRR___RRRR___RrWWrR_RWWrrR__RWWrrrRWWrrrR__RrrrrrrrrrrrR__RrrrrrrrrrrrR___RrrrrrrrrrR_____RrrrrrrrR_______RrrrrrR_________RrrrR___________RrR_____________R_____________________________________","credit":""},{"name":"Eye","size":9,"bricks":"____________ggg_____gWWWg___gWbbbWg_gWWbBbWWg_gWbbbWg___gWWWg_____ggg____________","credit":""},{"name":"Enderman","size":10,"bricks":"___________gggggggg__gggggggg__gggggggg__gggggggg__vvvggvvv__gggggggg__gggggggg__gggggggg___________","credit":"https://minecraft.wiki/w/Enderman"},{"name":"Mushroom","size":16,"bricks":"_____________________rrrrWW________WWrrrrWWWW_____WWrrrrrrWWWW____WrrWWWWrrWWW___rrrWWWWWWrrrrr__rrrWWWWWWrrWWr__WrrWWWWWWrWWWW__WWrrWWWWrrWWWW__WWrrrrrrrrrWWr__WrrWWWWWWWWrrr_____WWBWWBWW_______WWWBWWBWWW______WWWWWWWWWW_______WWWWWWWW____________________","credit":"https://pixelartmaker.com/art/cce4295a92035ea"},{"name":"Tulip","size":11,"bricks":"______________R_R_R______RRRRR______RRRRR______RRRRR_______RRR_________k________k_k_k______k_k_k_______kkk_________k_____","credit":""},{"name":"Chain","size":7,"bricks":"yyy____yBy____yyyyy____yBy____yyyyy____yBy____yyy","credit":""},{"name":"Marion","size":9,"bricks":"rr_____rr_rr___rr__rrr_rrr__rrrrrrr__rr_r_rr__rr___rr__rr___rr__rr___rr_rrr___rrr","credit":""},{"name":"Renan","size":9,"bricks":"yyyyyyy___yyyyyyy__yy___yy__yy___yy__yyyyyy___yy_yy____yy__yy___yy___yy_yyy___yyy","credit":""},{"name":"Violet Pairs","size":8,"bricks":"b_b_b_b_b_b_b_b__________t_t_t_t_t_t_t_t________b_b_b_b_b_b_b_b_","credit":""},{"name":"Red Cups","size":11,"bricks":"___________rBr_rBr_rBrrrr_rrr_rrr___________r_rBr_rBr_rr_rrr_rrr_r___________rBr_rBr_rBrrrr_rrr_rrr______________________","credit":""},{"name":"Cactus","size":10,"bricks":"____G______rG_Gk______G_Gk______kkkk_r_____kkk_G______GkGk_____rGkk_______Gk________kk________kk____","credit":""},{"name":"Sunny Face","size":11,"bricks":"____yyy______yyyyyyy___yyyyyyyyy__yyyyyyyyy_yyyWWyWWyyyyyyyyyyyyyyyyyyyyyyyyy_yyWWWWWyy__yyyWWWyyy___yyyyyyy______yyy____","credit":""},{"name":"Mountain","size":9,"bricks":"_______________W_______WWW______GGWW__W_GGGGG_kkkGGGGG_kkkkGGGGkkkkkGGGGkkkkkkGGG","credit":""},{"name":"Dollar","size":17,"bricks":"________________________G_G______________G_G____________GGGGGGG_________GGGGGGGGG_______GG__G_G__GG______GG__G_G__GG______GG__G_G___________GGGGGGGG__________GGGGGGGG___________G_G__GG______GG__G_G__GG______GG__G_G__GG_______GGGGGGGGG_________GGGGGGG____________G_G______________G_G_______","credit":""},{"name":"Waves","size":8,"bricks":"___bbb____bbb____bbttbbbbbttbbbbttttaatttttaattttaaaaaaa________","credit":""},{"name":"Box","size":8,"bricks":"yyyyyyyyy______yy_bbbb_yy_b__b_yy_b__b_yy_bbbb_yy______yyyyyyyyy","credit":""},{"name":"Rose","size":9,"bricks":"__SS______SSSS_____SSSS_____SSSS______SS_k______k_kk_____kk_k______kk________k___","credit":""},{"name":"Time","size":9,"bricks":"__________WWWWWWW___WWWWW_____yyy_______y________y_______WyW_____WyyyW___yyyyyyy_","credit":""},{"name":"Watermelon","size":8,"bricks":"_____Sk_____SSBk___SBSSk__SSSSSk_SSBSSk_SBSSSSk_kSSSkk___kkk____","credit":""},{"name":"Worms","size":13,"bricks":"___sssss_______sssssss______WWsWWsss_____WBsBWsss_____WBsBWsss_____WWsWWsss_____sssssss_______ssssss_____WWWWWWss_______WssWs__s_____ssss__sss___sssssssssss__sssssssss_s","credit":"https://en.wikipedia.org/wiki/Worms_(series)"},{"name":"Ocean Sunrise","size":8,"bricks":"SSSSSSSSSSSyySSSSSyyyySSSyyyyyySbttttttbbbttttbbbbbttbbbbbbbbbbb","credit":""},{"name":"Crosses","size":13,"bricks":"b___b___b___b__v___v___v___vvv_vvv_vvv___v___v___v__p___p___p___ppp_ppp_ppp_ppp___p___p___p__P___P___P___PPP_PPP_PPP___P___P___P__p___p___p___ppp_ppp_ppp_ppp___p___p___p","credit":""},{"name":"Negative space","size":9,"bricks":"tttttttttt_t_t_t_t_________b_b_b_b_bbbbbbbbbb_b_b_b_b___________t_t_t_t_ttttttttt","credit":""},{"name":"UK","size":11,"bricks":"brbbWrWbbrbbbrbWrWbrbbbbbrWrWrbbbWWWWWrWWWWWrrrrrrrrrrrWWWWWrWWWWWbbbrWrWrbbbbbrbWrWbrbbbrbbWrWbbrb______________________","credit":""},{"name":"Greece","size":11,"bricks":"ttWttttttttttWttWWWWWWWWWWWttttttttWttWWWWWWttWttttttttWWWWWWWWWWWtttttttttttWWWWWWWWWWWttttttttttt______________________","credit":""},{"name":"Russia","size":8,"bricks":"________WWWWWWWWWWWWWWWWttttttttttttttttrrrrrrrrrrrrrrrr________","credit":""},{"name":"Ukraine","size":8,"bricks":"________ttttttttttttttttttttttttyyyyyyyyyyyyyyyyyyyyyyyy________","credit":""},{"name":"Poland","size":7,"bricks":"________WWWWW__WWWWW__rrrrr__rrrrr_______________","credit":""},{"name":"Yellow 71","size":9,"bricks":"_________yyyyy__yyyyyyy_yyy___yy__yy__yyy__yy_yyy___yy_yy____yy_yy____yy_________","credit":""},{"name":"71 on white","size":6,"bricks":"WWWWWWrrrWWrWWrWrrWrWWWrWrWWWrWWWWWW","credit":""},{"name":"Blue 71","size":8,"bricks":"ttttt__bttttt_bb___ttbbb__tt__bb__tt__bb_tt___bb_tt___bb_tt___bb","credit":""},{"name":"Seventy one","size":21,"bricks":"rr_yy_rrry_yrrry_yrrrr_ry_yr__y_yr_ry_y_r_rr_yy_rr_yy_r_ry_y_r_r_ry_yr__y_yr_ry_y_r_rr_y_yrrry_yrrryyy_r_yyy__________________y______________r_____yyyrrry_yrrryyyrr_y_y__yrr_y_yrr_y_yr__y_yyyyrrr_y_rrry_yrrryyy____________________yrrryyyrrr_________yy_r_ry_yrr_____________rrry_yrrryyyyyyyyyyyy___________________________________________________________________________________________________________________________________________________","credit":""},{"name":"B71","size":10,"bricks":"__________bbbtttt_b_b__b__tbb_b__b__t_b_bbb__t__b_b__b_t__b_b__bt___b_bbb_t__bbb____________________","credit":""},{"name":"Pig","size":9,"bricks":"__________PP___PP__PPP_PPP__WWPPPWW__WBPPPBW__PPsssPP__PsBsBsP__PPsssPP__________","credit":""},{"name":"Big Pig","size":15,"bricks":"________________sss_______sss__ss__sssss__ss____sssssssss_____sWBsssssBWs___ssBBsssssBBss__ssss_____ssss__sss_sssss_sss__sss_sBsBs_sss__sss_sssss_sss___sss_____sss____sssssssssss__GGGsssssssssGGGGGGsGsssssGsGGGGGGssGGGGGssGGG","credit":""},{"name":"Donkey Kong","size":9,"bricks":"OOr__a___OOr__a___ppppppp_O______a________a____pppppppr_a______b_a___O__ppppppp__","credit":""},{"name":"Banana","size":12,"bricks":"_________________e__________eee_________eee_________eee_________eeeyy_____yyeeyyyy___yyyyey_yC___yy_yyy___C_____yyyy_________yyyy_________yyyy__","credit":""},{"name":"Fox","size":8,"bricks":"e______eee_OO_eeeeOOOOeeeOBOOBOeOOOOOOOO_WWBBWW___WWWW_____WW___","credit":""},{"name":"Wiki","size":10,"bricks":"_______________________GGGG_____GGkkGG___GkggggkG__GgWWWWgG__GkggggkG___GGkkGG_____GGGG_____________","credit":""},{"name":"Baby Dog","size":8,"bricks":"_______W__eeeeWWWWeeWeWWWeBWeBeeeeWWWWee_eWBBWe__eWWWWe____WW___","credit":""},{"name":"dog 21","size":9,"bricks":"__________O_____O_OOOWWWOOOOOWWWWWOOOOeWWWWOO_eBeWWBW__eBeWWBW___eWBWW_____WRW___","credit":"https://prohama.com/dog-21-pattern/"},{"name":"A","size":7,"bricks":"__ttt___ttttt_ttt_ttttt___ttttttttttt___tttt___tt","credit":""},{"name":"B","size":9,"bricks":"_bbbbb_____bb_bb____bb_bb____bb_bb____bbbb_____bb_bb____bb_bb____bb_bb___bbbbb___","credit":""},{"name":"C","size":8,"bricks":"__rrrr___rrrrrr_rrr___rrrr______rr______rrr___rr_rrrrrr___rrrr__","credit":""},{"name":"D","size":8,"bricks":"_GGGGG____GG__G___GG__GG__GG__GG__GG__GG__GG__GG__GG__G__GGGGG__","credit":""},{"name":"e","size":8,"bricks":"__tttt___tttttt_tt____tttt____tttttttttttt_______tt__tt___tttt__","credit":""},{"name":"Elephant","size":18,"bricks":"_________________________llll_________lll_llllll_lll___lsssllllllllsssl__lsssllllllllsssl__lsssllBllBllsssl__lssllWllllWllssl___ll__llllll__ll_________llll_______________ll______________llll______________ll______________________________________________________________________________________________________________________","credit":"https://prohama.com/elephant-5-pattern/"},{"name":"Orca","size":20,"bricks":"____________________________________________________________________________________________ggggg____ggg_ggg___ggggggg____ggggg___ggggggggg____ggg___ggggWggWWW_____gggggggggggWWWW_____ggggggggggWWWWW_____gggggggggWWWWW_______gggggggWWWWW___________WWggWWW______________ggg_gg______________gg__g__________________________________________________________________________________________________________","credit":"https://prohama.com/whale-2-pattern/"},{"name":"Shark","size":17,"bricks":"__________________________________________g_______________ggg____________ggggggg_________ggggggggg_______ggggggggggg_____gggggWWWggggg____gBgWWWWWWWgBg___ggWWWWrWrWWWWgg__ggWWWrrrrrWWWgg_ggWWWrrrrrrrWWWggggWWrrrrrrrrrWWgggWWWrWrWrWrWrWWWggWWrrWWWWWWWrrWWggWWWWWWWWWWWWWWWg_________________","credit":"https://prohama.com/shark-2-pattern/"},{"name":"Bird","size":13,"bricks":"_______RRR____R____RSSSR___RR__RSSWWWR__RSR_RSWWBWR__RSSRRSWWWWyy_RSSSRSWWWR___RSSSSSSRR_____RRSSyyyy______RSyyyyy___RRRRSyyyy____RSSSRyyy_____RRRR______________________","credit":"https://prohama.com/bird-1-size-13x12/"},{"name":"Tux","size":14,"bricks":"_____gggg________gggggggg_____gggggggggg____gggggggggg___gggggggggggg__gggWBggWBggg__gggBBggBBggg__ggggyyyygggg_ggggggyyggggggggggWWWWWWggggg_gWWWWWWWWg_g__WWWWWWWWWW____WWWWWWWWWW____yyy____yyy__","credit":"https://prohama.com/pingwin-4-pattern/"},{"name":"Armenia","size":6,"bricks":"_______rrrr__bbbb__yyyy_____________","credit":""},{"name":"Austria","size":6,"bricks":"_______rrrr__WWWW__rrrr_____________","credit":""},{"name":"Benin","size":8,"bricks":"_________kkyyyy__kkyyyy__kkrrrr__kkrrrr_________________________","credit":""},{"name":"Botswana","size":10,"bricks":"___________tttttttt__tttttttt__tttttttt__WWWWWWWW__BBBBBBBB__WWWWWWWW__tttttttt__tttttttt__tttttttt_","credit":""},{"name":"Bulgaria","size":6,"bricks":"_______WWWW__cccc__rrrr_____________","credit":""},{"name":"Canada","size":7,"bricks":"________rWWWr__rWrWr__rWWWr______________________","credit":""},{"name":"Chad","size":8,"bricks":"_________bbyyRR__bbyyRR__bbyyRR_________________________________","credit":""},{"name":"China","size":6,"bricks":"______RRyRRRRyRyRRRRyRRRRRRRRR______","credit":""},{"name":"Colombia","size":7,"bricks":"________yyyyy__yyyyy__bbbbb__RRRRR_______________","credit":""},{"name":"Republic of the Congo","size":7,"bricks":"________kkkyy__kkyyr__kyyrr__yyrrr_______________","credit":""},{"name":"C\xf4te d\'Ivoire","size":8,"bricks":"_________OOWWGG__OOWWGG__OOWWGG_________________________________","credit":""},{"name":"Denmark","size":8,"bricks":"_________rrWrrr__rrWrrr__WWWWWW__rrWrrr__rrWrrr_________________","credit":""},{"name":"El Salvador","size":8,"bricks":"_________bbbbbb__bbbbbb__WWWkWW__WWkWWW__bbbbbb__bbbbbb_________","credit":""},{"name":"Egypt","size":8,"bricks":"_________RRRRRR__RRRRRR__WWWyWW__WWyWWW__gggggg__gggggg_________","credit":""},{"name":"Estonia","size":8,"bricks":"_________tttttt__tttttt__gggggg__gggggg__WWWWWW__WWWWWW_________","credit":""},{"name":"Finland","size":6,"bricks":"_______WtWW__tttt__WtWW_____________","credit":""},{"name":"Gabon","size":5,"bricks":"______CCC__yyy__ttt______","credit":""},{"name":"Georgia","size":9,"bricks":"__________WrWrWrW__WWWrWWW__rrrrrrr__WWWrWWW__WrWrWrW____________________________","credit":""},{"name":"Guinea","size":8,"bricks":"_________rryycc__rryycc__rryycc_________________________________","credit":""},{"name":"Indonesia","size":6,"bricks":"_______rrrr__rrrr__WWWW__WWWW_______","credit":""},{"name":"Pingwin","size":13,"bricks":"______gggg________ggWWgg_______gWWgWgy______ggWWWg_______ggggg_______gggWWW______gggggWWW___gggggggWWW____ggggggWWW_____ggggWWWW____gggWWWWW______ggWWWW________gWWyyy___","credit":"https://prohama.com/pingwin-2-pattern/"},{"name":"Dog 8","size":17,"bricks":"_____________________________________gg_ggggg_gg____ggWWgWWWWWgWWgg__gWWgWWWWWWWgWWg__gWWgWWWWWWWgWWg__gggWWWWWWWWWggg___gWggWWWWWggWg____gWggWWWWWggWg____gWWWWgggWWWWg_____gWgWWgWWgWg______gWWggsggWWg_______gWgsssgWg_________ggsssgg____________ggg_________________________________________","credit":"https://prohama.com/dog-8-pattern/"},{"name":"Sunglasses","size":24,"bricks":"____________________________________________________ggggg______ggggg_______gg___g______g___gg_____gg________________gg___gg__________________gg_gggggggggg____gggggggggggggtttttggggggggbbbbbgggggtWWWttttggggbbbbWWWbgg_gtWttttttggggbbbbWbbbg__gtttttttgg__ggbbbbbbbg__gtttttttg____gbbbbbbbg__ggtttttgg____ggbbbbbgg___ggtttgg______ggbbbgg_____ggggg________ggggg___________________________________________________________________________________________________________________________________________________________________________________________________________________________","credit":"https://prohama.com/sunglasses-pattern-1/"},{"name":"Balloon","size":21,"bricks":"_____bbbWbbbWbbb_________PWbWPWbWPWbWP_______bWbbbWbbbWbbbWb_____WbbbWbbbWbbbWbbbW___WPWbWPWbWPWbWPWbWPW__bWbbbWbbbWbbbWbbbWb__bbbPbbbPbbbPbbbPbbb__bbPPPbPPPbPPPbPPPbb___PPWPPPWPPPWPPPWPP____PWbWPWbWPWbWPWbWP_____PWPPPWPPPWPPPWP_______PPWPPPWPPPWPP_________WbWPWbWPWbW___________bbbbbbbbb_____________b_____b______________b_____b______________b_____b______________WWWWWWW_______________PPPPP________________PPPPP________________PPPPP________","credit":"https://prohama.com/balloon-1/"},{"name":"Opening","size":14,"bricks":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbyyyyyyyyyyyybbyB___BB___Bybby__________ybbyyy______yyybbbbyyB__Byybbbbbbbyy__yybbbbbbbbby__ybbbbbyyyyby__ybyyyy___yby__yby______yby__yby______yBy__yBy______yyy__yyy___","credit":""},{"name":"Stripes","size":17,"bricks":"bbb______tttttt________tttttt________tttttt______bbtttttt______bbbbbttt______bbbbbb________bbbbbb________bbbbbb______ttbbbbbb______tttttbbb______tttttt________tttttt________tttttt______bbtttttt______bbbbbttt______bbbbbb________bbbbbb________bbbbbb________bbbbbb___________bbb______________","credit":""},{"name":"You are here","size":13,"bricks":"_____rrr_________rrrrr_______rrr_rrr______rr___rr______rr___rr_______rr_rr________rrrrr_________rrr__________rrr_________WWrWW_______WWWrWWW______WWWWWWW_______WWWWW____","credit":""},{"name":"Gear","size":13,"bricks":"_________________l_l_l______l_lllll_l_____lllllll____lllll_lllll___lll___lll___lll_____lll___lll___lll___lllll_lllll____lllllll_____l_lllll_l______l_l_l_________________","credit":""},{"name":"Play","size":15,"bricks":"_________________rrrrrrrrrrr___rrrrWWrrrrrrr__rrrrWWWrrrrrr__rrrrWWWWrrrrr__rrrrWWWWWrrrr__rrrrWWWWWWrrr__rrrrWWWWWrrrr__rrrrWWWWrrrrr__rrrrWWWrrrrrr__rrrrWWrrrrrrr___rrrrrrrrrrr_______________________________________________","credit":""},{"name":"City","size":18,"bricks":"_______yyy___bbbbb________yyy__ybyyb________yyy__ybyyb__tt___yyy_b_ybbbb_tttt______bbbbbbbtttttt_______ybyybbbbbbb_______ybyybbyybyb_____b_ybbbbbyybyb_____bbbbbbbbbbbbb__bb___bbbbbbybyyb_bbbb__ybyybbybyybbbbbbb_ybyybbbbbbbtttttt_ybbbbbyybybtyyyyt_bbbbbbyybybtyyyyt_bbbbbbbbbbbtttttt_byybybybyybtytyyt_byybybybyybtttttt_byybb","credit":""},{"name":"Wiggle","size":17,"bricks":"__________________cccccc_ccc_cccc__c____c_c_c_c__c__ccc_cc_c_ccc_cc____c_c__c_____c___ccc_cccc_ccc_cc__c________c_c__c__ccc_ccc_cc_cccc____c_c_c_c________ccc_c_c_ccccccc__c___c_________c__ccc_ccccccccccc____c______________ccc_ccc_ccc_ccc__c___c_c_c_c_c_c__ccccc_ccc_ccc_c__________________","credit":""},{"name":"Graph","size":18,"bricks":"_______________________yy________________yyt__yytttt______tt_tttyy___t____yyt____t_____t____yy____tt_____t____t_____t______yy___t_____t______yy__tt_____yytttttt___tt___ttyy_____t___t____t__t_____t___yytttt__t_____t___yy______tt____t____t_______yy___t____ttt_____yyttyy______tyy___t___yy_______yytttt_________________________","credit":""},{"name":"Lightbulb","size":14,"bricks":"_______________y__yyyyy___y____yyyyyyy______yyyyyyyyy_____yyyyyyyyy___y_yyyyyyyyy__y__yyyyyyyyy_____yyyyyyyyy_____yyyBBByyy___y__yyByByy___y____yByBy_________lllll______y___lll___y_______lll______","credit":""},{"name":"Note","size":16,"bricks":"_____________WWW__________WWWWWW_______WWWWWW__W____WWWWWW_____W____WWW________W____W__________W____W__________W____W__________W____W__________W____W________WWW____W_______WWWW____W_______WWW___WWW____________WWWW____________WWW____________________________","credit":""},{"name":"Rocket","size":13,"bricks":"______b___________bbb_________bbBbb________btttb________ttBtt________ttttt________ttBtt________ttttt________ttBtt_______bbtttbb_____bbbyyybbb____bbbyyybbb____bb_ByB_bb__","credit":""},{"name":"Abstract","size":16,"bricks":"________________aaaaa_cccc_aaaaaaaaaa_cccc_aaaaa________________aaaa_cccc_aaaaaaaaaa_cccc_aaaaaa________________aaa_cccc_aaaaaaaaaa_cccc_aaaaaaa________________aa_cccc_aaaaaaaaaa_cccc_aaaaaaaa________________a_cccc_aaaaaaaaaa_cccc_aaaaaaaaa________________","credit":""},{"name":"Fingerprint","size":15,"bricks":"___SSSSSSSS______S_______SS____S__SSSSS__SS__S__S____SS__S____S__SS__SS_S___S__S_SS__S__S_S__S___SS_SS__SS_S_____S___S__S_S__SS__S__SS_S_S_SS_S__S__S_S_S_S___S_S__S_S_S_S___S_S__S___S_S___S_S__S__S__S___S_S__S__S__S__S___S_S_","credit":""},{"name":"Leaf","size":14,"bricks":"____________________________________________________________GGkGG________GGkGGkGG_____GGkGGkGGkkG_kkkkkkkkkkkGGG__GGkGGkGGkkG____GGkGGkGG_______GGkGG_______________________________________________","credit":""},{"name":"Abstract 2","size":14,"bricks":"______________yyyy______yyyy______________bbb_bbbbbb_bbbbb___bbbb___bbb__y__bb__y__b______________bbb_bbbbbb_bbbbb___bbbb___bbb__y__bb__y__b______________bbb_bbbbbb_bbbbb___bbbb___bbb__y__bb__y__b","credit":""},{"name":"Abstract 3","size":13,"bricks":"______________p_aaa_ppp_a__p___a_p___a__ppp_a_p_aaa_______________aaa_p_a_ppp__a___p_a___p__a_ppp_aaa_p_______________p_aaa_ppp_a__p___a_p___a__ppp_a_p_aaa______________","credit":""},{"name":"Abstract 4","size":13,"bricks":"______________y_y_y_y_y_y__y_y_y_y_y_y__y_y_y_y_y_y_______________bbb_bbb_bbb_______________bbb_bbb_bbb_______________y_y_y_y_y_y__y_y_y_y_y_y__y_y_y_y_y_y______________","credit":""},{"name":"Abstract 5","size":13,"bricks":"______________ccc_ccc_ccc__c_a_c_c_a_c__caa_aaa_aac_______________cca_aaa_acc__c_a_a_a_a_c__cca_aaa_acc_______________caa_aaa_aac__c_a_c_c_a_c__ccc_ccc_ccc______________","credit":""},{"name":"Abstract 6","size":13,"bricks":"_vvvvv_vvvvv__v___v_v___v__v_bbbbbbb_v__v_b_v_v_b_v__v_b_v_v_b_v__v_b_v_v_b_v__v_b_v_v_b_v__v_b_v_v_b_v__v_b_v_v_b_v__v_b_vvv_b_v__v_b_____b_v__vvvvvvvvvvv_bbbb_____bbbb","credit":""},{"name":"Hemiola","size":11,"bricks":"___gggg_____gggrrgg_____ggrrg_______gggg_____gggyygg_____ggyyg_______gggg_____gggCCgg_____ggCCg_______gggg________gg_____","credit":"Left a wonderful review on the play store."},{"name":"Obigre","size":13,"bricks":"_______________________________________OOOORgRgRgOOOOWOORgRgRgOOOOOWORgRgRgOWOOWOORgRgRgOOWOOWORgRgRgOWOOWOORgRgRgOOOOOOORgRgRgOOO_______________________________________","credit":"Colin helped a lot with the game design https://colin-crapahute.bearblog.dev/"},{"name":"Noodlemire","size":15,"bricks":"_________________________________ggggggggg_____g_________g___g___________g_g_____________gg_____________gg_____yyy_____ggg__yyyyyyy__ggggtyyyyyyyyytggggtttttttttttgggg_ttttttttt_gg_____ttttt___________________________________","credit":"Early adopter of the game"},{"name":"Bearded axe","size":12,"bricks":"______________WyyyOOy_____WyyyOOy_____Wyy_OO______Wyy_OO______Wyy_OO__________OO__________OO__________OO__________OO__________OO__________OO____","credit":"Did some nice bug reports"},{"name":"Lebanon","size":9,"bricks":"_________rrrrrrrrrWWWWkWWWWWWWkkkWWWWWkkkkkWWWWWWkWWWWrrrrrrrrr__________________","credit":""},{"name":"Spain","size":9,"bricks":"_________rrrrrrrrryyyyyyyyyyWrWyyyyyyrWryyyyyyWrWyyyyyyyyyyyyyyrrrrrrrrr_________","credit":""},{"name":"Uzbekistan","size":8,"bricks":"tWtttWttWtttWttttWtWtWttWWWWWWWWWWWWWWWWGGGGGGGGGGGGGGGGGGGGGGGG","credit":""},{"name":"Pakistan","size":8,"bricks":"________WWkkkkkkWWkkWkWkWWkWkkkkWWkWkkWkWWkkWWkkWWkkkkkk________","credit":""},{"name":"Korea","size":10,"bricks":"__________WWWWWWWWWWWgWWWWWWgWWgWrrrrWgWWWWrrbbWWWWWWrrbbWWWWgWbbbbWgWWgWWWWWWgWWWWWWWWWWW__________","credit":""},{"name":"Chile","size":9,"bricks":"_________tttWWWWWWtWtWWWWWWtttWWWWWWrrrrrrrrrrrrrrrrrrrrrrrrrrr__________________","credit":""},{"name":"T\xfcrkiye","size":12,"bricks":"____________rrrrrrrrrrrrrrrWWWrrrrrrrrWWrrrrrrrrrWWrrWrWrrrrrWWrrrWrrrrrrWWrrWrWrrrrrrWWrrrrrrrrrrrWWWrrrrrrrrrrrrrrrrrr________________________","credit":""},{"name":"Taj Mahal","size":11,"bricks":"_____e________WWWWW_____WWWWWWW____WWWWWWW____WWWWWWW__W__lllll__WWWeeeeeeeWWeeeeeWeeeeeeleeWWWeeleeeeWWWWWeeeeleWWlWWele","credit":"An approximative reproduction "},{"name":"Abstract 7","size":9,"bricks":"__________SS_t_SS__S_____S____t_t____t_____t____t_t____S_____S__SS_t_SS__________","credit":""},{"name":"Abstract 9","size":8,"bricks":"PP_vv_PP_P__v__P________vv_PP_vvv__P__v_________PP_vv_PP_P__v__P","credit":""},{"name":"Crosshair","size":9,"bricks":"____W_____WWWWWWW__WB_W_BW__W_____W_WWW_B_WWW_W_____W__WB_W_BW__WWWWWWW_____W____","credit":""},{"name":"Abstract 10","size":15,"bricks":"bbbB_ttttt_BbbbbBbb_ttBtt_bbBbb____tt_tt____bbbbb_tt_tt_bbbb_______________ttttt_b_b_tttttt_____b_b_____tt_ttt_b_b_ttt_ttBtBt_bBb_tBtBtttt_t_bbb_t_ttt________________bb_ttttttt_bb__Bb_tB___Bt_bB__Bb_ttt_ttt_bB_bbb_________bbb","credit":""},{"name":"Face","size":6,"bricks":"SSSSSSSOOOOSSBOOBSSOOOOSSOOOOS_OSSO_","credit":""},{"name":"Eiffel tower","size":11,"bricks":"_____O__________O__________O__________O_________OOO________OOO____k___O_O___kkk_OO_OO_kkkkkOOOOOkkkkkOOO_OOOkkkOOO___OOOk","credit":""},{"name":"Abstract 11","size":9,"bricks":"P_t_s_t_PP_t___t_PP_ttttt_PP_______PPPPPPPPPPP_______PP_sssss_PP_s___s_PP_s_t_s_P","credit":""},{"name":"Abstract 12","size":8,"bricks":"BbBb____bbbb____BbBb____bbbb________tBtB____tttt____tBtB____tttt","credit":""},{"name":"Abstract 13","size":9,"bricks":"SSSSbSSSSSbbSbSbbSSbbS_SbbSSSSS_SSSSbb_____bbSSSS_SSSSSbbS_SbbSSbbSbSbbSSSSSbSSSS","credit":""},{"name":"Abstract 14","size":11,"bricks":"aa_tt_aa_ttaa_tt_aa_tt__B__B__B__bb_aa_bb_aabb_aa_bb_aa__B__B__B__aa_bb_tt_bbaa_bb_tt_bb__B__B__B__tt_aa_bb_aatt_aa_bb_aa","credit":""},{"name":"S","size":10,"bricks":"___________Oyyyyyyy__Oyyyyyyy__Oyy__Oyy__Oyy_______Oyyyyyyy_______Oyy__Oyy__Oyy__Oyyyyyyy__Oyyyyyyy_","credit":""},{"name":"Abstract 15","size":11,"bricks":"____________S_vvv_SSS__S___v___S__SSS_vvv_S__________S__S_vvv_SSS__S___v______SSS_vvv_S____S_____S__v_SSS_SSS____________","credit":"Just random strokes"},{"name":"Mario!","size":11,"bricks":"________________________RRRRR_____RRRRRRRRR__kkkOOkO___kOkOOOkOOO_kOkkOOOkOOOkkOOOOkkkk___OOOOOOO________________________","credit":"Suggested by Nicolas03. A Mario level ! Sprite taken from https://art.pixilart.com/sr2d5c0683c82aws3.png . The sprite belongs to Nintendo"},{"name":"Minesweeper","size":16,"bricks":"___llltCCttBC______lllCBBttCB______lttbBbtltt______ltBrBClttt______lttCCCttBt______llttCBtttt______ltCBCttlll______ltBCCtCtCt______lttCCBCBrB______llltBCCtrB______ttttttlltt______CBrttlllll______CBrBCttttl______ttCCBttBtl______tttCCCtCCt______tBttBtltBt___","credit":"Suggested by Noodlemire. For once, you\'ll want to trigger as many mines as possible."},{"name":"Target","size":19,"bricks":"__________________________________________________________________________________________________________________________WWW_______________WrrrW_____________WrWWWrW____________WrWBWrW____________WrWWWrW_____________WrrrW_______________WWW__________________________________________________________________________________________________________________________","credit":"Suggested by Noodlemire. Unusually small level, with lots of room to miss your shots. Acts as decent aim practice."},{"name":"The Boys","size":10,"bricks":"__________rrrrr_____WWrWWrrrrrWWrWWWWrWWWWrWWWWrWWrWrWWWWrWWWrWWWrWrWW_____WrWWW____________________","credit":"Suggested by Bearded-Axe. My boys initals"},{"name":"A Very Dangerous High-Five","size":21,"bricks":"__________________________________________________yy_______________yy__yy__yy___________yy__yy__yy____________yy__yy_yy_________y__yy__yy_yy________yyy_yyy_yy_yy_________yy__yy_yyyyy__________yy_yyyyyyyy___yyy____yyyyygggyyy__yyy______yyygBBBgyy_yyy________ygBBBBBgyyyy__W______ygBBBBBgyyy__________yygBBBgyyyy___________yygBgyyyy____________yyyByyyy_____________yyyyByy_______________yyByy_________________r_________________________________","credit":"Suggested by Noodlemire. A unique shape, fun to bounce the ball between fingers. The palm was initially boring on its own, so I gave it a big bomb. It adds a distinct feeling between the top and bottom halves."},{"name":"Blinky","size":20,"bricks":"____________________________gggg______________ggrrrrgg___________grrrrrrrrg_________grrrrrrrrrrg_______grrrWWrrrrWWrg______grrWWWWrrWWWWg______grrWWbbrrWWbbg_____grrrWWbbrrWWbbrg____grrrrWWrrrrWWrrg____grrrrrrrrrrrrrrg____grrrrrrrrrrrrrrg____grrrrrrrrrrrrrrg____grrrrrrrrrrrrrrg____grrgrrrggrrrgrrg____grg_grg__grg_grg_____g___g____g___g_______________________________________________________________","credit":"Suggested by Big Goober. The red ghost, Blinky, from the arcade game \\"Pac Man\\""}]'); },{}],"iyP6E":[function(require,module,exports,__globalThis) { -module.exports = JSON.parse("\"29088937\""); +module.exports = JSON.parse("\"29090246\""); },{}],"1u3Dx":[function(require,module,exports,__globalThis) { var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js"); @@ -2536,7 +2545,7 @@ const rawUpgrades = [ }), fullHelp: (0, _i18N.t)("upgrades.sturdy_bricks.verbose_description") } -].sort((a, b)=>a.category - b.category || a.threshold - b.threshold); +]; },{"./i18n/i18n":"eNPRm","./pure_functions":"6pQh7","@parcel/transformer-js/src/esmodule-helpers.js":"gkKU3"}],"eNPRm":[function(require,module,exports,__globalThis) { var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js"); @@ -2907,7 +2916,7 @@ const levelIconHTMLCanvasCtx = levelIconHTMLCanvas.getContext("2d", { antialias: false, alpha: true }); -function levelIconHTML(bricks, levelSize, color) { +function levelIconHTML(bricks, levelSize) { const size = 46; const c = levelIconHTMLCanvas; const ctx = levelIconHTMLCanvasCtx; @@ -3285,7 +3294,6 @@ parcelHelpers.export(exports, "hoursSpentPlaying", ()=>hoursSpentPlaying); var _loadGameData = require("./loadGameData"); var _i18N = require("./i18n/i18n"); var _pureFunctions = require("./pure_functions"); -var _upgrades = require("./upgrades"); var _getLevelBackground = require("./getLevelBackground"); var _settings = require("./settings"); var _options = require("./options"); @@ -3375,7 +3383,7 @@ function pickedUpgradesHTMl(gameState) { "banned", "free" ][state]}"> - ${u.icon} + ${(0, _loadGameData.icons)['icon:' + u.id]}

${u.name} ${u.help(Math.max(1, gameState.perks[u.id]))} @@ -3508,7 +3516,7 @@ function isExcluded(id) { "slow_down" ]); // Avoid excluding a perk that's needed for the required one - (0, _upgrades.rawUpgrades).forEach((u)=>{ + (0, _loadGameData.upgrades).forEach((u)=>{ if (u.requires) excluded.add(u.requires); }); } @@ -3518,7 +3526,7 @@ function getLevelUnlockCondition(levelIndex) { let required = [], forbidden = [], minScore = Math.max(-1000 + 100 * levelIndex, 0); if (levelIndex > 20) { const possibletargets = [ - ...(0, _upgrades.rawUpgrades) + ...(0, _loadGameData.upgrades) ].slice(0, Math.floor(levelIndex / 2)).filter((u)=>!isExcluded(u.id)).sort((a, b)=>(0, _getLevelBackground.hashCode)(levelIndex + a.id) - (0, _getLevelBackground.hashCode)(levelIndex + b.id)); const length = Math.min(3, Math.ceil(levelIndex / 30)); required = possibletargets.slice(0, length); @@ -3574,7 +3582,7 @@ function hoursSpentPlaying() { } } -},{"./loadGameData":"l1B4x","./i18n/i18n":"eNPRm","./pure_functions":"6pQh7","./upgrades":"1u3Dx","./getLevelBackground":"7OIPf","./settings":"5blfu","./options":"d5NoS","@parcel/transformer-js/src/esmodule-helpers.js":"gkKU3"}],"2n0gK":[function(require,module,exports,__globalThis) { +},{"./loadGameData":"l1B4x","./i18n/i18n":"eNPRm","./pure_functions":"6pQh7","./getLevelBackground":"7OIPf","./settings":"5blfu","./options":"d5NoS","@parcel/transformer-js/src/esmodule-helpers.js":"gkKU3"}],"2n0gK":[function(require,module,exports,__globalThis) { var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js"); parcelHelpers.defineInteropFlag(exports); if ("serviceWorker" in navigator && window.location.href.endsWith("/index.html?isPWA=true")) { @@ -5357,7 +5365,6 @@ var _gameUtils = require("./game_utils"); var _settings = require("./settings"); var _recording = require("./recording"); var _asyncAlert = require("./asyncAlert"); -var _upgrades = require("./upgrades"); var _levelEditor = require("./levelEditor"); var _creative = require("./creative"); function addToTotalPlayTime(ms) { @@ -5384,7 +5391,7 @@ function gameOver(title, intro) { // unlocks const endTs = (0, _settings.getTotalScore)(); const startTs = endTs - (0, _game.gameState).score; - const unlockedPerks = (0, _upgrades.rawUpgrades).filter((o)=>o.threshold > startTs && o.threshold < endTs); + const unlockedPerks = (0, _loadGameData.upgrades).filter((o)=>o.threshold > startTs && o.threshold < endTs); let unlocksInfo = unlockedPerks.length ? `

${unlockedPerks.length === 1 ? (0, _i18N.t)("gameOver.unlocked_perk") : (0, _i18N.t)("gameOver.unlocked_perk_plural", { @@ -5540,7 +5547,7 @@ function getHistograms(gameState) { return unlockedLevels + runStats; } -},{"./loadGameData":"l1B4x","./i18n/i18n":"eNPRm","./game":"edeGs","./game_utils":"cEeac","./settings":"5blfu","./recording":"godmD","./asyncAlert":"rSqLY","./upgrades":"1u3Dx","./levelEditor":"cirX1","./creative":"63kYJ","@parcel/transformer-js/src/esmodule-helpers.js":"gkKU3"}],"godmD":[function(require,module,exports,__globalThis) { +},{"./loadGameData":"l1B4x","./i18n/i18n":"eNPRm","./game":"edeGs","./game_utils":"cEeac","./settings":"5blfu","./recording":"godmD","./asyncAlert":"rSqLY","./levelEditor":"cirX1","./creative":"63kYJ","@parcel/transformer-js/src/esmodule-helpers.js":"gkKU3"}],"godmD":[function(require,module,exports,__globalThis) { var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js"); parcelHelpers.defineInteropFlag(exports); parcelHelpers.export(exports, "recordOneFrame", ()=>recordOneFrame); @@ -5677,6 +5684,7 @@ parcelHelpers.export(exports, "closeModal", ()=>closeModal); parcelHelpers.export(exports, "requiredAsyncAlert", ()=>requiredAsyncAlert); parcelHelpers.export(exports, "asyncAlert", ()=>asyncAlert); var _i18N = require("./i18n/i18n"); +var _options = require("./options"); let alertsOpen = 0, closeModal = null; const popupWrap = document.getElementById("popup"); const closeModaleButton = document.getElementById("close-modale"); @@ -5740,7 +5748,6 @@ ${icon} ${text} ${help || ""} `; - if (tooltip) button.setAttribute("data-tooltip", tooltip); if (disabled) button.setAttribute("disabled", "disabled"); else button.addEventListener("click", (e)=>{ e.preventDefault(); @@ -5751,6 +5758,27 @@ ${icon} }); button.className = className + (lastClickedItemIndex === index ? " needs-focus" : ""); addto.appendChild(button); + if (tooltip) { + if ((0, _options.isOptionOn)("mobile-mode")) { + const helpBtn = document.createElement("button"); + helpBtn.innerText = "?"; + helpBtn.className = "help"; + let helpTooltip = document.createElement("div"); + helpTooltip.textContent = tooltip; + helpTooltip.className = "help_button_tooltip"; + helpBtn.addEventListener("click", (e)=>{ + e.stopPropagation(); + }); + helpBtn.addEventListener("touchstart", (e)=>{ + e.stopPropagation(); + document.body.appendChild(helpTooltip); + }); + helpBtn.addEventListener("touchend", (e)=>{ + document.body.removeChild(helpTooltip); + }); + button.appendChild(helpBtn); + } else button.setAttribute("data-tooltip", tooltip); + } }); popup.addEventListener("click", (e)=>{ const target = e.target; @@ -5774,7 +5802,7 @@ function updateAlertsOpen(delta) { document.body.classList[alertsOpen ? "add" : "remove"]("has-alert-open"); } -},{"./i18n/i18n":"eNPRm","@parcel/transformer-js/src/esmodule-helpers.js":"gkKU3"}],"cirX1":[function(require,module,exports,__globalThis) { +},{"./i18n/i18n":"eNPRm","@parcel/transformer-js/src/esmodule-helpers.js":"gkKU3","./options":"d5NoS"}],"cirX1":[function(require,module,exports,__globalThis) { var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js"); parcelHelpers.defineInteropFlag(exports); parcelHelpers.export(exports, "levelEditorMenuEntry", ()=>levelEditorMenuEntry); @@ -5813,7 +5841,7 @@ async function openLevelEditorLevelsList() { content: [ ...customLevels.map((l, li)=>({ text: l.name, - icon: (0, _levelIcon.levelIconHTML)(l.bricks, l.size, l.color), + icon: (0, _levelIcon.levelIconHTML)(l.bricks, l.size), value () { editRawLevelList(li); }, @@ -6042,7 +6070,7 @@ async function openCreativeModePerksPicker() { }; }), ...customLevels.map((l)=>({ - icon: (0, _levelIcon.levelIconHTML)(l.bricks, l.size, l.color), + icon: (0, _levelIcon.levelIconHTML)(l.bricks, l.size), text: l.name, value: l, disabled: !l.bricks.filter((b)=>b !== "_").length, @@ -6070,7 +6098,7 @@ async function openCreativeModePerksPicker() { }, (0, _i18N.t)("lab.instructions"), ...(0, _loadGameData.upgrades).filter((u)=>!(0, _upgrades.noCreative).includes(u.id)).map((u)=>({ - icon: u.icon, + icon: (0, _loadGameData.icons)['icon:' + u.id], text: u.name, help: (creativeModePerks[u.id] || 0) + "/" + (u.max + (creativeModePerks.limitless || 0)), value: u, @@ -6300,7 +6328,7 @@ async function openStartingPerksEditor() { const buttons = avaliable.map((u)=>{ const checked = isStartingPerk(u); return { - icon: u.icon, + icon: (0, _loadGameData.icons)['icon:' + u.id], text: u.name, tooltip: u.help(1), value: [ @@ -6359,7 +6387,7 @@ function helpMenuEntry() { (0, _pureFunctions.miniMarkDown)((0, _i18N.t)("help.upgrades")), ...(0, _loadGameData.upgrades).map((u)=>`
- ${u.icon} + ${(0, _loadGameData.icons)['icon:' + u.id]}

${u.name}
${u.help(1)} @@ -6557,7 +6585,6 @@ var _gameOver = require("./gameOver"); var _loadGameData = require("./loadGameData"); var _i18N = require("./i18n/i18n"); var _asyncAlert = require("./asyncAlert"); -var _upgrades = require("./upgrades"); var _settings = require("./settings"); function runHistoryViewerMenuEntry() { const history = (0, _gameOver.getHistory)(); @@ -6583,7 +6610,7 @@ function runHistoryViewerMenuEntry() { label: (0, _i18N.t)("history.columns.score"), field: (r)=>r.score }, - ...(0, _upgrades.rawUpgrades).map((u)=>({ + ...(0, _loadGameData.upgrades).map((u)=>({ label: (0, _loadGameData.icons)["icon:" + u.id], tooltip: u.name, field: (r)=>r.perks?.[u.id] || 0, @@ -6635,7 +6662,7 @@ function runHistoryViewerMenuEntry() { }; } -},{"./gameOver":"caCAf","./loadGameData":"l1B4x","./i18n/i18n":"eNPRm","./asyncAlert":"rSqLY","./upgrades":"1u3Dx","@parcel/transformer-js/src/esmodule-helpers.js":"gkKU3","./settings":"5blfu"}],"aHTmD":[function(require,module,exports,__globalThis) { +},{"./gameOver":"caCAf","./loadGameData":"l1B4x","./i18n/i18n":"eNPRm","./asyncAlert":"rSqLY","@parcel/transformer-js/src/esmodule-helpers.js":"gkKU3","./settings":"5blfu"}],"aHTmD":[function(require,module,exports,__globalThis) { var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js"); parcelHelpers.defineInteropFlag(exports); parcelHelpers.export(exports, "openScorePanel", ()=>openScorePanel); diff --git a/src/PWA/sw-b71.js b/src/PWA/sw-b71.js index b9f1dc2..207ce85 100644 --- a/src/PWA/sw-b71.js +++ b/src/PWA/sw-b71.js @@ -1,5 +1,5 @@ // The version of the cache. -const VERSION = "29088937"; +const VERSION = "29090246"; // The name of the cache const CACHE_NAME = `breakout-71-${VERSION}`; diff --git a/src/asyncAlert.ts b/src/asyncAlert.ts index 6eb9e23..9e619b4 100644 --- a/src/asyncAlert.ts +++ b/src/asyncAlert.ts @@ -1,4 +1,5 @@ import { t } from "./i18n/i18n"; +import { isOptionOn } from "./options"; export let alertsOpen = 0, closeModal: null | (() => void) = null; @@ -118,9 +119,6 @@ ${icon} ${help || ""}

`; - if (tooltip) { - button.setAttribute("data-tooltip", tooltip); - } if (disabled) { button.setAttribute("disabled", "disabled"); } else { @@ -137,6 +135,31 @@ ${icon} className + (lastClickedItemIndex === index ? " needs-focus" : ""); addto.appendChild(button); + + if (tooltip) { + if (isOptionOn("mobile-mode")) { + const helpBtn = document.createElement("button"); + helpBtn.innerText = "?"; + helpBtn.className = "help"; + let helpTooltip = document.createElement("div"); + helpTooltip.textContent = tooltip; + helpTooltip.className = "help_button_tooltip"; + helpBtn.addEventListener("click", (e) => { + e.stopPropagation(); + }); + helpBtn.addEventListener("touchstart", (e) => { + e.stopPropagation(); + document.body.appendChild(helpTooltip); + }); + helpBtn.addEventListener("touchend", (e) => { + document.body.removeChild(helpTooltip); + }); + + button.appendChild(helpBtn); + } else { + button.setAttribute("data-tooltip", tooltip); + } + } }); popup.addEventListener( diff --git a/src/creative.ts b/src/creative.ts index 0afa5c6..8078268 100644 --- a/src/creative.ts +++ b/src/creative.ts @@ -57,7 +57,7 @@ export async function openCreativeModePerksPicker() { }; }), ...customLevels.map((l) => ({ - icon: levelIconHTML(l.bricks, l.size, l.color), + icon: levelIconHTML(l.bricks, l.size), text: l.name, value: l, disabled: !l.bricks.filter((b) => b !== "_").length, @@ -93,7 +93,7 @@ export async function openCreativeModePerksPicker() { ...upgrades .filter((u) => !noCreative.includes(u.id)) .map((u) => ({ - icon: u.icon, + icon: icons['icon:'+u.id], text: u.name, help: (creativeModePerks[u.id] || 0) + diff --git a/src/data/levels.json b/src/data/levels.json index 00931e3..5aae1bc 100644 --- a/src/data/levels.json +++ b/src/data/levels.json @@ -1397,4 +1397,4 @@ "bricks": "____________________________gggg______________ggrrrrgg___________grrrrrrrrg_________grrrrrrrrrrg_______grrrWWrrrrWWrg______grrWWWWrrWWWWg______grrWWbbrrWWbbg_____grrrWWbbrrWWbbrg____grrrrWWrrrrWWrrg____grrrrrrrrrrrrrrg____grrrrrrrrrrrrrrg____grrrrrrrrrrrrrrg____grrrrrrrrrrrrrrg____grrgrrrggrrrgrrg____grg_grg__grg_grg_____g___g____g___g_______________________________________________________________", "credit": "Suggested by Big Goober. The red ghost, Blinky, from the arcade game \"Pac Man\"" } -] \ No newline at end of file +] diff --git a/src/data/version.json b/src/data/version.json index 783f29c..a1d2976 100644 --- a/src/data/version.json +++ b/src/data/version.json @@ -1 +1 @@ -"29088937" +"29090246" diff --git a/src/game.less b/src/game.less index 8fde163..84fd193 100644 --- a/src/game.less +++ b/src/game.less @@ -197,6 +197,7 @@ body:not(.has-alert-open) #popup { &.actionsAsGrid.large > div > section { grid-template-columns: repeat(auto-fill, minmax(400px, 1fr)); } + &.actionsAsGrid > div { max-width: none; @@ -504,10 +505,12 @@ h2.histogram-title strong { opacity 200ms, transform 200ms; z-index: 7; + &.hidden { opacity: 0; transform: translate(-20px, -20px) scale(0.5); } + &.visible { opacity: 0.8; transform: none; @@ -523,6 +526,7 @@ h2.histogram-title strong { height: 40px; border: 1px solid; cursor: pointer; + &:hover { border-color: gold; z-index: 1; @@ -530,6 +534,7 @@ h2.histogram-title strong { box-shadow: inset 2px 2px 4px rgba(0, 0, 0, 0.2); } } + .gridEdit { & > div { display: flex; @@ -544,6 +549,7 @@ h2.histogram-title strong { .palette { display: flex; flex-wrap: wrap; + & > span { &[data-selected="true"] { border: 2px solid white; @@ -561,15 +567,18 @@ h2.histogram-title strong { z-index: 3; pointer-events: none; opacity: 1; + & > div { background: rgba(38, 38, 38, 0.5); position: relative; + > div { background: @purple; position: absolute; inset: 0; transform-origin: top left; } + > strong { position: relative; padding: 0 5px; @@ -579,6 +588,7 @@ h2.histogram-title strong { .highlight { position: relative; + &:before { content: ""; position: absolute; @@ -588,7 +598,18 @@ h2.histogram-title strong { opacity: 0.3; } } + .not-highlighed { opacity: 0.8; color: #8a8a8a; } + +.help_button_tooltip { + position: fixed; + z-index: 8; + left: 0; + top: 0; + background: black; + padding: 20px; + border-bottom: 1px solid white; +} diff --git a/src/game.ts b/src/game.ts index ee1a4db..a9b4596 100644 --- a/src/game.ts +++ b/src/game.ts @@ -80,7 +80,8 @@ import { catchRateGood, clamp, levelTimeBest, - levelTimeGood, miniMarkDown, + levelTimeGood, + miniMarkDown, missesBest, missesGood, wallBouncedBest, @@ -97,7 +98,7 @@ import { runHistoryViewerMenuEntry } from "./runHistoryViewer"; import { getNearestUnlockHTML, openScorePanel } from "./openScorePanel"; import { monitorLevelsUnlocks } from "./monitorLevelsUnlocks"; import { levelEditorMenuEntry } from "./levelEditor"; -import {categories} from "./upgrades"; +import { categories } from "./upgrades"; export async function play() { if (await applyFullScreenChoice()) return; @@ -912,7 +913,7 @@ async function openUnlockedUpgradesList() { const ts = getTotalScore(); const upgradeActions = upgrades .sort((a, b) => a.threshold - b.threshold) - .map(({ name, id, threshold, icon, help ,category, fullHelp}) => ({ + .map(({ name, id, threshold, icon, help, category, fullHelp }) => ({ text: name, disabled: ts < threshold, value: { @@ -925,7 +926,7 @@ async function openUnlockedUpgradesList() { ts < threshold ? t("unlocks.minTotalScore", { score: threshold }) : help(1), - tooltip:ts < threshold ? '': fullHelp, + tooltip: ts < threshold ? "" : fullHelp, })); const tryOn = await asyncAlert({ @@ -934,18 +935,20 @@ async function openUnlockedUpgradesList() { out_of: upgradeActions.length, }), content: [ - t("unlocks.intro", { ts }), - upgradeActions.find((u) => u.disabled) ? t("unlocks.greyed_out_help") : "", - miniMarkDown(t("unlocks.category.beginner")), - ...upgradeActions.filter(u=>u.category==categories.beginner), - miniMarkDown(t("unlocks.category.combo")), - ...upgradeActions.filter(u=>u.category==categories.combo), - miniMarkDown(t("unlocks.category.combo_boost")), - ...upgradeActions.filter(u=>u.category==categories.combo_boost), - miniMarkDown(t("unlocks.category.simple")), - ...upgradeActions.filter(u=>u.category==categories.simple), - miniMarkDown(t("unlocks.category.advanced")), - ...upgradeActions.filter(u=>u.category==categories.advanced), + t("unlocks.intro", { ts }), + upgradeActions.find((u) => u.disabled) + ? t("unlocks.greyed_out_help") + : "", + miniMarkDown(t("unlocks.category.beginner")), + ...upgradeActions.filter((u) => u.category == categories.beginner), + miniMarkDown(t("unlocks.category.combo")), + ...upgradeActions.filter((u) => u.category == categories.combo), + miniMarkDown(t("unlocks.category.combo_boost")), + ...upgradeActions.filter((u) => u.category == categories.combo_boost), + miniMarkDown(t("unlocks.category.simple")), + ...upgradeActions.filter((u) => u.category == categories.simple), + miniMarkDown(t("unlocks.category.advanced")), + ...upgradeActions.filter((u) => u.category == categories.advanced), ], allowClose: true, // className: "actionsAsGrid large", diff --git a/src/gameOver.ts b/src/gameOver.ts index 6c34f47..724b38d 100644 --- a/src/gameOver.ts +++ b/src/gameOver.ts @@ -16,7 +16,6 @@ import { } from "./settings"; import { stopRecording } from "./recording"; import { asyncAlert } from "./asyncAlert"; -import { rawUpgrades } from "./upgrades"; import { editRawLevelList } from "./levelEditor"; import { openCreativeModePerksPicker } from "./creative"; @@ -52,7 +51,7 @@ export function gameOver(title: string, intro: string) { // unlocks const endTs = getTotalScore(); const startTs = endTs - gameState.score; - const unlockedPerks = rawUpgrades.filter( + const unlockedPerks = upgrades.filter( (o) => o.threshold > startTs && o.threshold < endTs, ); diff --git a/src/game_utils.ts b/src/game_utils.ts index 7dabcbc..010ede3 100644 --- a/src/game_utils.ts +++ b/src/game_utils.ts @@ -11,7 +11,6 @@ import { import { icons, upgrades } from "./loadGameData"; import { t } from "./i18n/i18n"; import { clamp } from "./pure_functions"; -import { rawUpgrades } from "./upgrades"; import { hashCode } from "./getLevelBackground"; import { getSettingValue, getTotalScore } from "./settings"; import { isOptionOn } from "./options"; @@ -132,7 +131,7 @@ export function pickedUpgradesHTMl(gameState: GameState) { state, html: `
- ${u.icon} + ${icons['icon:'+u.id]}

${u.name} ${u.help(Math.max(1, gameState.perks[u.id]))} @@ -310,7 +309,7 @@ function isExcluded(id: PerkId) { "slow_down", ]); // Avoid excluding a perk that's needed for the required one - rawUpgrades.forEach((u) => { + upgrades.forEach((u) => { if (u.requires) excluded.add(u.requires); }); } @@ -323,7 +322,7 @@ export function getLevelUnlockCondition(levelIndex: number) { minScore = Math.max(-1000 + 100 * levelIndex, 0); if (levelIndex > 20) { - const possibletargets = [...rawUpgrades] + const possibletargets = [...upgrades] .slice(0, Math.floor(levelIndex / 2)) .filter((u) => !isExcluded(u.id)) .sort( diff --git a/src/help.ts b/src/help.ts index cee8710..0f04c19 100644 --- a/src/help.ts +++ b/src/help.ts @@ -39,7 +39,7 @@ export function helpMenuEntry() { ...upgrades.map( (u) => `

- ${u.icon} + ${icons['icon:'+u.id]}

${u.name}
${u.help(1)} diff --git a/src/levelEditor.ts b/src/levelEditor.ts index e4d620f..a4b64ec 100644 --- a/src/levelEditor.ts +++ b/src/levelEditor.ts @@ -40,7 +40,7 @@ async function openLevelEditorLevelsList() { content: [ ...customLevels.map((l, li) => ({ text: l.name, - icon: levelIconHTML(l.bricks, l.size, l.color), + icon: levelIconHTML(l.bricks, l.size), value() { editRawLevelList(li); }, diff --git a/src/levelIcon.ts b/src/levelIcon.ts index b52d3d3..d5c236e 100644 --- a/src/levelIcon.ts +++ b/src/levelIcon.ts @@ -10,7 +10,6 @@ const levelIconHTMLCanvasCtx = export function levelIconHTML( bricks: string[], levelSize: number, - color: string, ) { const size = 46; const c = levelIconHTMLCanvas; diff --git a/src/level_editor/levels_editor.tsx b/src/level_editor/levels_editor.tsx index 10cd64b..5c96edd 100644 --- a/src/level_editor/levels_editor.tsx +++ b/src/level_editor/levels_editor.tsx @@ -2,14 +2,13 @@ import { Level, Palette, RawLevel } from "../types"; import _backgrounds from "../data/backgrounds.json"; import _palette from "../data/palette.json"; import { createRoot } from "react-dom/client"; -import { useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { moveLevel, resizeLevel, setBrick } from "./levels_editor_util"; import { automaticBackgroundColor, levelCodeToRawLevel, } from "../pure_functions"; - const palette = _palette as Palette; let allLevels = null; @@ -22,13 +21,22 @@ function App() { fetch("http://localhost:4400/src/data/levels.json") .then((r) => r.json()) .then((lvls) => { - - const cleaned = lvls.map(l=>({name:l.name, size:l.size, bricks:(l.bricks+'_'.repeat(l.size*l.size)).slice(0,l.size*l.size), credit:l.credit||''})) - const sorted = [ - ...cleaned.filter(l=>l.name.match('icon:')).sort((a,b)=>a.name>b.name ? 1:-1), - ...cleaned.filter(l=>!l.name.match('icon:')) - ] - setLevels(sorted as RawLevel[]) + const cleaned = lvls.map((l) => ({ + name: l.name, + size: l.size, + bricks: (l.bricks + "_".repeat(l.size * l.size)).slice( + 0, + l.size * l.size, + ), + credit: l.credit || "", + })); + const sorted = [ + ...cleaned + .filter((l) => l.name.match("icon:")) + .sort((a, b) => (a.name > b.name ? 1 : -1)), + ...cleaned.filter((l) => !l.name.match("icon:")), + ]; + setLevels(sorted as RawLevel[]); allLevels = sorted; }); }, []); diff --git a/src/loadGameData.test.ts b/src/loadGameData.test.ts index ba3887f..1559671 100644 --- a/src/loadGameData.test.ts +++ b/src/loadGameData.test.ts @@ -30,18 +30,6 @@ describe("json data checks", () => { it("Has a few colors", () => { expect(Object.keys(_palette).length).toBeGreaterThan(10); }); - it("Avoids dark bricks on dark bg", () => { - const levelsWithDarkBricksAndBG = _rawLevelsList - .filter((l) => !l.color && !l.name.match(/^icon:/)) - .map((l) => ({ - name: l.name, - bricks: l.bricks.split("").filter((c) => c !== "_").length, - darkBricks: l.bricks.split("").filter((c) => c === "g").length, - })) - .filter((l) => l.darkBricks > 0.05 * l.bricks); - - expect(levelsWithDarkBricksAndBG).toEqual([]); - }); it("Has an _appVersion", () => { expect(parseInt(_appVersion)).toBeGreaterThan(2000); }); diff --git a/src/loadGameData.ts b/src/loadGameData.ts index b00b11e..d770702 100644 --- a/src/loadGameData.ts +++ b/src/loadGameData.ts @@ -8,6 +8,7 @@ import { levelIconHTML } from "./levelIcon"; import { automaticBackgroundColor } from "./pure_functions"; +export const upgrades = [...rawUpgrades].sort((a, b) => a.category - b.category || a.threshold - b.threshold) as Upgrade[]; const palette = _palette as Palette; const rawLevelsList = _rawLevelsList as RawLevel[]; @@ -22,7 +23,7 @@ export function transformRawLevel(level: RawLevel) { .map((c) => palette[c]) .slice(0, level.size * level.size); const bricksCount = bricks.filter((i) => i).length; - const icon = levelIconHTML(bricks, level.size, level.color); + const icon = levelIconHTML(bricks, level.size); icons[level.name] = icon; return { ...level, @@ -43,7 +44,3 @@ export const allLevels = allLevelsAndIcons.filter( (l) => !l.name.startsWith("icon:"), ); -export const upgrades = rawUpgrades.map((u) => ({ - ...u, - icon: icons["icon:" + u.id], -})) as Upgrade[]; diff --git a/src/runHistoryViewer.ts b/src/runHistoryViewer.ts index d6546e7..f50857c 100644 --- a/src/runHistoryViewer.ts +++ b/src/runHistoryViewer.ts @@ -1,8 +1,7 @@ import { getHistory } from "./gameOver"; -import { appVersion, icons } from "./loadGameData"; +import {appVersion, icons, upgrades} from "./loadGameData"; import { t } from "./i18n/i18n"; import { asyncAlert } from "./asyncAlert"; -import { rawUpgrades } from "./upgrades"; import { getSettingValue, setSettingValue } from "./settings"; export function runHistoryViewerMenuEntry() { @@ -31,7 +30,7 @@ export function runHistoryViewerMenuEntry() { label: t("history.columns.score"), field: (r) => r.score, }, - ...rawUpgrades.map((u) => ({ + ...upgrades.map((u) => ({ label: icons["icon:" + u.id], tooltip: u.name, field: (r) => r.perks?.[u.id] || 0, diff --git a/src/startingPerks.ts b/src/startingPerks.ts index 5d54aa9..3555c3d 100644 --- a/src/startingPerks.ts +++ b/src/startingPerks.ts @@ -31,7 +31,7 @@ export async function openStartingPerksEditor() { const buttons = avaliable.map((u) => { const checked = isStartingPerk(u); return { - icon: u.icon, + icon: icons['icon:'+u.id], text: u.name, tooltip: u.help(1), value: [u], diff --git a/src/types.d.ts b/src/types.d.ts index 3e41bf2..8eb009d 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -7,7 +7,6 @@ export type RawLevel = { name: string; size: number; bricks: string; - color: string; credit?: string; }; export type Level = { @@ -28,8 +27,7 @@ export type Upgrade = { gift: boolean; id: PerkId; name: string; - category: string; - icon: string; + category: number; max: number; help: (lvl: number) => string; fullHelp: string; diff --git a/src/upgrades.ts b/src/upgrades.ts index 430546a..b7453ed 100644 --- a/src/upgrades.ts +++ b/src/upgrades.ts @@ -1,7 +1,7 @@ import { t } from "./i18n/i18n"; import { comboKeepingRate } from "./pure_functions"; -import { PerkId } from "./types"; +import {PerkId, Upgrade} from "./types"; // Those perks are excluded from creative mode export const noCreative: PerkId[] = [ @@ -10,877 +10,882 @@ export const noCreative: PerkId[] = [ "one_more_choice", ]; -export const categories={ - beginner:1, - combo:2, - combo_boost:2.5, - simple:3, - advanced:4, -} +export const categories = { + beginner: 1, + combo: 2, + combo_boost: 2.5, + simple: 3, + advanced: 4, +}; -export const rawUpgrades = [ - { - category: categories.beginner, - requires: "", - threshold: 0, - gift: false, - id: "slow_down", - max: 2, - name: t("upgrades.slow_down.name"), - help: (lvl: number) => t("upgrades.slow_down.tooltip", { lvl }), - fullHelp: t("upgrades.slow_down.verbose_description"), - }, - { - category: categories.beginner, - requires: "", - threshold: 0, - gift: false, - id: "extra_life", - max: 7, - name: t("upgrades.extra_life.name"), - help: (lvl: number) => - lvl === 1 - ? t("upgrades.extra_life.tooltip") - : t("upgrades.extra_life.help_plural", { lvl }), - fullHelp: t("upgrades.extra_life.verbose_description"), - }, - { - category: categories.beginner, - requires: "", - threshold: 60000, - gift: false, - id: "concave_puck", - max: 1, - name: t("upgrades.concave_puck.name"), - help: (lvl: number) => t("upgrades.concave_puck.tooltip"), - fullHelp: t("upgrades.concave_puck.verbose_description"), - }, - { - category: categories.beginner, - requires: "", - threshold: 500, - id: "telekinesis", - gift: true, - max: 1, - name: t("upgrades.telekinesis.name"), - help: (lvl: number) => - lvl == 1 - ? t("upgrades.telekinesis.tooltip") - : t("upgrades.telekinesis.help_plural"), - fullHelp: t("upgrades.telekinesis.verbose_description"), - }, - { - category: categories.beginner, - requires: "", - threshold: 85000, - gift: false, - id: "yoyo", - max: 1, - name: t("upgrades.yoyo.name"), - help: (lvl: number) => t("upgrades.yoyo.tooltip"), - fullHelp: t("upgrades.yoyo.verbose_description"), - }, - { - category: categories.beginner, - requires: "", - threshold: 0, - gift: false, - id: "bigger_puck", - max: 2, - name: t("upgrades.bigger_puck.name"), - help: () => t("upgrades.bigger_puck.tooltip"), - fullHelp: t("upgrades.bigger_puck.verbose_description"), - }, +export const rawUpgrades = [ + { + category: categories.beginner, + requires: "", + threshold: 0, + gift: false, + id: "slow_down", + max: 2, + name: t("upgrades.slow_down.name"), + help: (lvl: number) => t("upgrades.slow_down.tooltip", { lvl }), + fullHelp: t("upgrades.slow_down.verbose_description"), + }, + { + category: categories.beginner, + requires: "", + threshold: 0, + gift: false, + id: "extra_life", + max: 7, + name: t("upgrades.extra_life.name"), + help: (lvl: number) => + lvl === 1 + ? t("upgrades.extra_life.tooltip") + : t("upgrades.extra_life.help_plural", { lvl }), + fullHelp: t("upgrades.extra_life.verbose_description"), + }, + { + category: categories.beginner, + requires: "", + threshold: 60000, + gift: false, + id: "concave_puck", + max: 1, + name: t("upgrades.concave_puck.name"), + help: (lvl: number) => t("upgrades.concave_puck.tooltip"), + fullHelp: t("upgrades.concave_puck.verbose_description"), + }, + { + category: categories.beginner, + requires: "", + threshold: 500, + id: "telekinesis", + gift: true, + max: 1, + name: t("upgrades.telekinesis.name"), + help: (lvl: number) => + lvl == 1 + ? t("upgrades.telekinesis.tooltip") + : t("upgrades.telekinesis.help_plural"), + fullHelp: t("upgrades.telekinesis.verbose_description"), + }, + { + category: categories.beginner, + requires: "", + threshold: 85000, + gift: false, + id: "yoyo", + max: 1, + name: t("upgrades.yoyo.name"), + help: (lvl: number) => t("upgrades.yoyo.tooltip"), + fullHelp: t("upgrades.yoyo.verbose_description"), + }, + { + category: categories.beginner, + requires: "", + threshold: 0, + gift: false, + id: "bigger_puck", + max: 2, + name: t("upgrades.bigger_puck.name"), + help: () => t("upgrades.bigger_puck.tooltip"), + fullHelp: t("upgrades.bigger_puck.verbose_description"), + }, - { - category: categories.beginner, - requires: "", - threshold: 50000, - gift: false, - id: "one_more_choice", - max: 3, - name: t("upgrades.one_more_choice.name"), - help: (lvl: number) => t("upgrades.one_more_choice.tooltip", { lvl }), - fullHelp: t("upgrades.one_more_choice.verbose_description"), - }, - { - category: categories.beginner, - requires: "", - threshold: 50, - gift: false, - id: "skip_last", - max: 7, - name: t("upgrades.skip_last.name"), - help: (lvl: number) => - lvl == 1 - ? t("upgrades.skip_last.tooltip") - : t("upgrades.skip_last.help_plural", { lvl }), - fullHelp: t("upgrades.skip_last.verbose_description"), - }, - { - category: categories.combo, - requires: "", - threshold: 100, - id: "streak_shots", - gift: true, - max: 1, - name: t("upgrades.streak_shots.name"), - help: (lvl: number) => t("upgrades.streak_shots.tooltip", { lvl }), - fullHelp: t("upgrades.streak_shots.verbose_description"), - }, + { + category: categories.beginner, + requires: "", + threshold: 50000, + gift: false, + id: "one_more_choice", + max: 3, + name: t("upgrades.one_more_choice.name"), + help: (lvl: number) => t("upgrades.one_more_choice.tooltip", { lvl }), + fullHelp: t("upgrades.one_more_choice.verbose_description"), + }, + { + category: categories.beginner, + requires: "", + threshold: 50, + gift: false, + id: "skip_last", + max: 7, + name: t("upgrades.skip_last.name"), + help: (lvl: number) => + lvl == 1 + ? t("upgrades.skip_last.tooltip") + : t("upgrades.skip_last.help_plural", { lvl }), + fullHelp: t("upgrades.skip_last.verbose_description"), + }, + { + category: categories.combo, + requires: "", + threshold: 100, + id: "streak_shots", + gift: true, + max: 1, + name: t("upgrades.streak_shots.name"), + help: (lvl: number) => t("upgrades.streak_shots.tooltip", { lvl }), + fullHelp: t("upgrades.streak_shots.verbose_description"), + }, - { - category: categories.combo, - requires: "", - threshold: 200, - id: "left_is_lava", - gift: true, - max: 1, - name: t("upgrades.left_is_lava.name"), - help: (lvl: number) => t("upgrades.left_is_lava.tooltip", { lvl }), - fullHelp: t("upgrades.left_is_lava.verbose_description"), - }, - { - category: categories.combo, - requires: "", - threshold: 300, - id: "right_is_lava", - gift: true, - max: 1, - name: t("upgrades.right_is_lava.name"), - help: (lvl: number) => t("upgrades.right_is_lava.tooltip", { lvl }), - fullHelp: t("upgrades.right_is_lava.verbose_description"), - }, - { - category: categories.combo, - requires: "", - threshold: 400, - id: "top_is_lava", - gift: true, - max: 1, - name: t("upgrades.top_is_lava.name"), - help: (lvl: number) => t("upgrades.top_is_lava.tooltip", { lvl }), - fullHelp: t("upgrades.top_is_lava.verbose_description"), - }, - { - category: categories.combo, - requires: "", - threshold: 4000, - id: "hot_start", - gift: true, - max: 3, - name: t("upgrades.hot_start.name"), - help: (lvl: number) => - t("upgrades.hot_start.tooltip", { - start: lvl * 30 + 1, - loss: lvl, - }), - fullHelp: t("upgrades.hot_start.verbose_description"), - }, + { + category: categories.combo, + requires: "", + threshold: 200, + id: "left_is_lava", + gift: true, + max: 1, + name: t("upgrades.left_is_lava.name"), + help: (lvl: number) => t("upgrades.left_is_lava.tooltip", { lvl }), + fullHelp: t("upgrades.left_is_lava.verbose_description"), + }, + { + category: categories.combo, + requires: "", + threshold: 300, + id: "right_is_lava", + gift: true, + max: 1, + name: t("upgrades.right_is_lava.name"), + help: (lvl: number) => t("upgrades.right_is_lava.tooltip", { lvl }), + fullHelp: t("upgrades.right_is_lava.verbose_description"), + }, + { + category: categories.combo, + requires: "", + threshold: 400, + id: "top_is_lava", + gift: true, + max: 1, + name: t("upgrades.top_is_lava.name"), + help: (lvl: number) => t("upgrades.top_is_lava.tooltip", { lvl }), + fullHelp: t("upgrades.top_is_lava.verbose_description"), + }, + { + category: categories.combo, + requires: "", + threshold: 4000, + id: "hot_start", + gift: true, + max: 3, + name: t("upgrades.hot_start.name"), + help: (lvl: number) => + t("upgrades.hot_start.tooltip", { + start: lvl * 30 + 1, + loss: lvl, + }), + fullHelp: t("upgrades.hot_start.verbose_description"), + }, - { - category: categories.combo, - requires: "", - threshold: 2000, - id: "picky_eater", - gift: true, - max: 1, - name: t("upgrades.picky_eater.name"), - help: (lvl: number) => t("upgrades.picky_eater.tooltip", { lvl }), - fullHelp: t("upgrades.picky_eater.verbose_description"), - }, + { + category: categories.combo, + requires: "", + threshold: 2000, + id: "picky_eater", + gift: true, + max: 1, + name: t("upgrades.picky_eater.name"), + help: (lvl: number) => t("upgrades.picky_eater.tooltip", { lvl }), + fullHelp: t("upgrades.picky_eater.verbose_description"), + }, - { - category: categories.combo, - requires: "", - threshold: 3000, - id: "compound_interest", - gift: true, - max: 1, - name: t("upgrades.compound_interest.name"), - help: (lvl: number) => t("upgrades.compound_interest.tooltip", { lvl }), - fullHelp: t("upgrades.compound_interest.verbose_description"), - }, - { - category: categories.combo, - requires: "", - threshold: 150000, - gift: true, - id: "side_kick", - max: 3, - name: t("upgrades.side_kick.name"), - help: (lvl: number) => - t("upgrades.side_kick.tooltip", { lvl, loss: lvl * 2 }), - fullHelp: t("upgrades.side_kick.verbose_description"), - }, - { - category: categories.combo, - requires: "", - threshold: 150000, - gift: true, - id: "side_flip", - max: 3, - name: t("upgrades.side_flip.name"), - help: (lvl: number) => - t("upgrades.side_flip.tooltip", { lvl, loss: lvl * 2 }), - fullHelp: t("upgrades.side_flip.verbose_description"), - }, - { - category: categories.combo, - requires: "", - threshold: 135000, - // a bit too hard when starting up - gift: false, - id: "reach", - max: 1, - name: t("upgrades.reach.name"), - help: (lvl: number) => t("upgrades.reach.tooltip", { lvl }), - fullHelp: t("upgrades.reach.verbose_description"), - }, - { - category: categories.combo, - requires: "multiball", - threshold: 245000, - gift: false, - id: "happy_family", - max: 1, - name: t("upgrades.happy_family.name"), - help: () => t("upgrades.happy_family.tooltip"), - fullHelp: t("upgrades.happy_family.verbose_description"), - }, - { - category: categories.combo, - requires: "", - threshold: 165000, - gift: false, - id: "addiction", - max: 7, - name: t("upgrades.addiction.name"), - help: (lvl: number) => - t("upgrades.addiction.tooltip", { lvl, delay: (5 / lvl).toFixed(2) }), - fullHelp: t("upgrades.addiction.verbose_description"), - }, - { - category: categories.combo, - requires: "", - threshold: 90000, - gift: true, - id: "nbricks", - max: 3, - name: t("upgrades.nbricks.name"), - help: (lvl: number) => t("upgrades.nbricks.tooltip", { lvl }), - fullHelp: t("upgrades.nbricks.verbose_description"), - }, - { - category: categories.combo, - requires: "", - threshold: 230000, - gift: false, - id: "three_cushion", - max: 1, - name: t("upgrades.three_cushion.name"), - help: (lvl: number) => - t("upgrades.three_cushion.tooltip", { max: lvl * 3 }), - fullHelp: t("upgrades.three_cushion.verbose_description"), - }, - { - category: categories.combo, - requires: "", - threshold: 115000, - gift: true, - id: "trampoline", - max: 1, - name: t("upgrades.trampoline.name"), - help: (lvl: number) => t("upgrades.trampoline.tooltip", { lvl }), - fullHelp: t("upgrades.trampoline.verbose_description"), - }, + { + category: categories.combo, + requires: "", + threshold: 3000, + id: "compound_interest", + gift: true, + max: 1, + name: t("upgrades.compound_interest.name"), + help: (lvl: number) => t("upgrades.compound_interest.tooltip", { lvl }), + fullHelp: t("upgrades.compound_interest.verbose_description"), + }, + { + category: categories.combo, + requires: "", + threshold: 150000, + gift: true, + id: "side_kick", + max: 3, + name: t("upgrades.side_kick.name"), + help: (lvl: number) => + t("upgrades.side_kick.tooltip", { lvl, loss: lvl * 2 }), + fullHelp: t("upgrades.side_kick.verbose_description"), + }, + { + category: categories.combo, + requires: "", + threshold: 150000, + gift: true, + id: "side_flip", + max: 3, + name: t("upgrades.side_flip.name"), + help: (lvl: number) => + t("upgrades.side_flip.tooltip", { lvl, loss: lvl * 2 }), + fullHelp: t("upgrades.side_flip.verbose_description"), + }, + { + category: categories.combo, + requires: "", + threshold: 135000, + // a bit too hard when starting up + gift: false, + id: "reach", + max: 1, + name: t("upgrades.reach.name"), + help: (lvl: number) => t("upgrades.reach.tooltip", { lvl }), + fullHelp: t("upgrades.reach.verbose_description"), + }, + { + category: categories.combo, + requires: "multiball", + threshold: 245000, + gift: false, + id: "happy_family", + max: 1, + name: t("upgrades.happy_family.name"), + help: () => t("upgrades.happy_family.tooltip"), + fullHelp: t("upgrades.happy_family.verbose_description"), + }, + { + category: categories.combo, + requires: "", + threshold: 165000, + gift: false, + id: "addiction", + max: 7, + name: t("upgrades.addiction.name"), + help: (lvl: number) => + t("upgrades.addiction.tooltip", { lvl, delay: (5 / lvl).toFixed(2) }), + fullHelp: t("upgrades.addiction.verbose_description"), + }, + { + category: categories.combo, + requires: "", + threshold: 90000, + gift: true, + id: "nbricks", + max: 3, + name: t("upgrades.nbricks.name"), + help: (lvl: number) => t("upgrades.nbricks.tooltip", { lvl }), + fullHelp: t("upgrades.nbricks.verbose_description"), + }, + { + category: categories.combo, + requires: "", + threshold: 230000, + gift: false, + id: "three_cushion", + max: 1, + name: t("upgrades.three_cushion.name"), + help: (lvl: number) => + t("upgrades.three_cushion.tooltip", { max: lvl * 3 }), + fullHelp: t("upgrades.three_cushion.verbose_description"), + }, + { + category: categories.combo, + requires: "", + threshold: 115000, + gift: true, + id: "trampoline", + max: 1, + name: t("upgrades.trampoline.name"), + help: (lvl: number) => t("upgrades.trampoline.tooltip", { lvl }), + fullHelp: t("upgrades.trampoline.verbose_description"), + }, - { - category: categories.combo, - requires: "", - threshold: 105000, - gift: true, - id: "zen", - max: 1, - name: t("upgrades.zen.name"), - help: (lvl: number) => t("upgrades.zen.tooltip", { lvl }), - fullHelp: t("upgrades.zen.verbose_description"), - }, - { - category: categories.combo, - requires: "", - threshold: 70000, - gift: true, - id: "asceticism", - max: 1, - name: t("upgrades.asceticism.name"), - help: (lvl: number) => t("upgrades.asceticism.tooltip", { combo: lvl * 3 }), - fullHelp: t("upgrades.asceticism.verbose_description"), - }, - // Regular + { + category: categories.combo, + requires: "", + threshold: 105000, + gift: true, + id: "zen", + max: 1, + name: t("upgrades.zen.name"), + help: (lvl: number) => t("upgrades.zen.tooltip", { lvl }), + fullHelp: t("upgrades.zen.verbose_description"), + }, + { + category: categories.combo, + requires: "", + threshold: 70000, + gift: true, + id: "asceticism", + max: 1, + name: t("upgrades.asceticism.name"), + help: (lvl: number) => + t("upgrades.asceticism.tooltip", { combo: lvl * 3 }), + fullHelp: t("upgrades.asceticism.verbose_description"), + }, + // Regular - { - category: categories.simple, - requires: "", - threshold: 15000, - gift: false, - id: "pierce_color", - max: 4, - name: t("upgrades.pierce_color.name"), - help: (lvl: number) => t("upgrades.pierce_color.tooltip", { lvl }), - fullHelp: t("upgrades.pierce_color.verbose_description"), - }, - { - category: categories.simple, - requires: "", - threshold: 1500, - id: "pierce", - gift: false, - max: 3, - name: t("upgrades.pierce.name"), - help: (lvl: number) => t("upgrades.pierce.tooltip", { count: 3 * lvl }), - fullHelp: t("upgrades.pierce.verbose_description"), - }, - { - category: categories.simple, - requires: "", - threshold: 800, - id: "multiball", - gift: true, - max: 6, - name: t("upgrades.multiball.name"), - help: (lvl: number) => t("upgrades.multiball.tooltip", { count: lvl + 1 }), - fullHelp: t("upgrades.multiball.verbose_description"), - }, - { - category: categories.advanced, - requires: "multiball", - threshold: 21000, - gift: false, - id: "ball_repulse_ball", - max: 3, - name: t("upgrades.ball_repulse_ball.name"), - help: (lvl: number) => - lvl == 1 - ? t("upgrades.ball_repulse_ball.tooltip") - : t("upgrades.ball_repulse_ball.help_plural"), - fullHelp: t("upgrades.ball_repulse_ball.verbose_description"), - }, - { - category: categories.advanced, - requires: "multiball", - threshold: 25000, - gift: false, - id: "ball_attract_ball", - max: 3, - name: t("upgrades.ball_attract_ball.name"), - help: (lvl: number) => - lvl == 1 - ? t("upgrades.ball_attract_ball.tooltip") - : t("upgrades.ball_attract_ball.help_plural"), - fullHelp: t("upgrades.ball_attract_ball.verbose_description"), - }, - { - category: categories.advanced, - requires: "", - threshold: 30000, - gift: false, - id: "puck_repulse_ball", - max: 2, - name: t("upgrades.puck_repulse_ball.name"), - help: (lvl: number) => - lvl == 1 - ? t("upgrades.puck_repulse_ball.tooltip") - : t("upgrades.puck_repulse_ball.help_plural"), - fullHelp: t("upgrades.puck_repulse_ball.verbose_description"), - }, - { - category: categories.advanced, - requires: "", - threshold: 35000, - gift: false, - id: "wind", - max: 3, - name: t("upgrades.wind.name"), - help: (lvl: number) => - lvl == 1 ? t("upgrades.wind.tooltip") : t("upgrades.wind.help_plural"), - fullHelp: t("upgrades.wind.verbose_description"), - }, - { - category: categories.advanced, - requires: "", - threshold: 65000, - gift: false, - id: "helium", - max: 3, - name: t("upgrades.helium.name"), - help: (lvl: number) => t("upgrades.helium.tooltip"), - fullHelp: t("upgrades.helium.verbose_description"), - }, - { - category: categories.advanced, - requires: "", - threshold: 200000, - gift: false, - id: "bricks_attract_coins", - max: 3, - name: t("upgrades.bricks_attract_coins.name"), - help: (lvl: number) => t("upgrades.bricks_attract_coins.tooltip", { lvl }), - fullHelp: t("upgrades.bricks_attract_coins.verbose_description"), - }, - { - category: categories.advanced, - requires: "", - threshold: 240000, - gift: false, - id: "wrap_left", - max: 1, - name: t("upgrades.wrap_left.name"), - help: () => t("upgrades.wrap_left.tooltip"), - fullHelp: t("upgrades.wrap_left.verbose_description"), - }, - { - category: categories.advanced, - requires: "", - threshold: 245000, - gift: false, - id: "wrap_right", - max: 1, - name: t("upgrades.wrap_right.name"), - help: () => t("upgrades.wrap_right.tooltip"), - fullHelp: t("upgrades.wrap_right.verbose_description"), - }, + { + category: categories.simple, + requires: "", + threshold: 15000, + gift: false, + id: "pierce_color", + max: 4, + name: t("upgrades.pierce_color.name"), + help: (lvl: number) => t("upgrades.pierce_color.tooltip", { lvl }), + fullHelp: t("upgrades.pierce_color.verbose_description"), + }, + { + category: categories.simple, + requires: "", + threshold: 1500, + id: "pierce", + gift: false, + max: 3, + name: t("upgrades.pierce.name"), + help: (lvl: number) => t("upgrades.pierce.tooltip", { count: 3 * lvl }), + fullHelp: t("upgrades.pierce.verbose_description"), + }, + { + category: categories.simple, + requires: "", + threshold: 800, + id: "multiball", + gift: true, + max: 6, + name: t("upgrades.multiball.name"), + help: (lvl: number) => + t("upgrades.multiball.tooltip", { count: lvl + 1 }), + fullHelp: t("upgrades.multiball.verbose_description"), + }, + { + category: categories.advanced, + requires: "multiball", + threshold: 21000, + gift: false, + id: "ball_repulse_ball", + max: 3, + name: t("upgrades.ball_repulse_ball.name"), + help: (lvl: number) => + lvl == 1 + ? t("upgrades.ball_repulse_ball.tooltip") + : t("upgrades.ball_repulse_ball.help_plural"), + fullHelp: t("upgrades.ball_repulse_ball.verbose_description"), + }, + { + category: categories.advanced, + requires: "multiball", + threshold: 25000, + gift: false, + id: "ball_attract_ball", + max: 3, + name: t("upgrades.ball_attract_ball.name"), + help: (lvl: number) => + lvl == 1 + ? t("upgrades.ball_attract_ball.tooltip") + : t("upgrades.ball_attract_ball.help_plural"), + fullHelp: t("upgrades.ball_attract_ball.verbose_description"), + }, + { + category: categories.advanced, + requires: "", + threshold: 30000, + gift: false, + id: "puck_repulse_ball", + max: 2, + name: t("upgrades.puck_repulse_ball.name"), + help: (lvl: number) => + lvl == 1 + ? t("upgrades.puck_repulse_ball.tooltip") + : t("upgrades.puck_repulse_ball.help_plural"), + fullHelp: t("upgrades.puck_repulse_ball.verbose_description"), + }, + { + category: categories.advanced, + requires: "", + threshold: 35000, + gift: false, + id: "wind", + max: 3, + name: t("upgrades.wind.name"), + help: (lvl: number) => + lvl == 1 ? t("upgrades.wind.tooltip") : t("upgrades.wind.help_plural"), + fullHelp: t("upgrades.wind.verbose_description"), + }, + { + category: categories.advanced, + requires: "", + threshold: 65000, + gift: false, + id: "helium", + max: 3, + name: t("upgrades.helium.name"), + help: (lvl: number) => t("upgrades.helium.tooltip"), + fullHelp: t("upgrades.helium.verbose_description"), + }, + { + category: categories.advanced, + requires: "", + threshold: 200000, + gift: false, + id: "bricks_attract_coins", + max: 3, + name: t("upgrades.bricks_attract_coins.name"), + help: (lvl: number) => + t("upgrades.bricks_attract_coins.tooltip", { lvl }), + fullHelp: t("upgrades.bricks_attract_coins.verbose_description"), + }, + { + category: categories.advanced, + requires: "", + threshold: 240000, + gift: false, + id: "wrap_left", + max: 1, + name: t("upgrades.wrap_left.name"), + help: () => t("upgrades.wrap_left.tooltip"), + fullHelp: t("upgrades.wrap_left.verbose_description"), + }, + { + category: categories.advanced, + requires: "", + threshold: 245000, + gift: false, + id: "wrap_right", + max: 1, + name: t("upgrades.wrap_right.name"), + help: () => t("upgrades.wrap_right.tooltip"), + fullHelp: t("upgrades.wrap_right.verbose_description"), + }, - { - category: categories.simple, - requires: "", - threshold: 45000, - gift: false, - id: "respawn", - max: 4, - name: t("upgrades.respawn.name"), - help: (lvl: number) => - t("upgrades.respawn.tooltip", { - percent: Math.floor(100 * comboKeepingRate(lvl)), - delay: (3 / lvl).toFixed(2), - }), - fullHelp: t("upgrades.respawn.verbose_description"), - }, - { - category: categories.advanced, - requires: "", - threshold: 55000, - gift: false, - 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, - }), - fullHelp: t("upgrades.double_or_nothing.verbose_description"), - }, + { + category: categories.simple, + requires: "", + threshold: 45000, + gift: false, + id: "respawn", + max: 4, + name: t("upgrades.respawn.name"), + help: (lvl: number) => + t("upgrades.respawn.tooltip", { + percent: Math.floor(100 * comboKeepingRate(lvl)), + delay: (3 / lvl).toFixed(2), + }), + fullHelp: t("upgrades.respawn.verbose_description"), + }, + { + category: categories.advanced, + requires: "", + threshold: 55000, + gift: false, + 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, + }), + fullHelp: t("upgrades.double_or_nothing.verbose_description"), + }, - { - category: categories.advanced, - requires: "", - threshold: 75000, - gift: false, - id: "unbounded", - max: 3, - name: t("upgrades.unbounded.name"), - help: (lvl: number) => t("upgrades.unbounded.tooltip", { lvl }), - fullHelp: t("upgrades.unbounded.verbose_description"), - }, + { + category: categories.advanced, + requires: "", + threshold: 75000, + gift: false, + id: "unbounded", + max: 3, + name: t("upgrades.unbounded.name"), + help: (lvl: number) => t("upgrades.unbounded.tooltip", { lvl }), + fullHelp: t("upgrades.unbounded.verbose_description"), + }, - { - category: categories.advanced, - requires: "", - threshold: 95000, - gift: false, - id: "etherealcoins", - max: 1, - name: t("upgrades.etherealcoins.name"), - help: (lvl: number) => t("upgrades.etherealcoins.tooltip"), - fullHelp: t("upgrades.etherealcoins.verbose_description"), - }, - { - category: categories.advanced, - requires: "multiball", - threshold: 100000, - gift: false, - id: "shocks", - max: 1, - name: t("upgrades.shocks.name"), - help: (lvl: number) => t("upgrades.shocks.tooltip"), - fullHelp: t("upgrades.shocks.verbose_description"), - }, - { - category: categories.advanced, - requires: "extra_life", - threshold: 110000, - gift: false, - id: "sacrifice", - max: 1, - name: t("upgrades.sacrifice.name"), - help: (lvl: number) => - lvl == 1 - ? t("upgrades.sacrifice.help_l1") - : t("upgrades.sacrifice.help_over", { lvl }), - fullHelp: t("upgrades.sacrifice.verbose_description"), - }, + { + category: categories.advanced, + requires: "", + threshold: 95000, + gift: false, + id: "etherealcoins", + max: 1, + name: t("upgrades.etherealcoins.name"), + help: (lvl: number) => t("upgrades.etherealcoins.tooltip"), + fullHelp: t("upgrades.etherealcoins.verbose_description"), + }, + { + category: categories.advanced, + requires: "multiball", + threshold: 100000, + gift: false, + id: "shocks", + max: 1, + name: t("upgrades.shocks.name"), + help: (lvl: number) => t("upgrades.shocks.tooltip"), + fullHelp: t("upgrades.shocks.verbose_description"), + }, + { + category: categories.advanced, + requires: "extra_life", + threshold: 110000, + gift: false, + id: "sacrifice", + max: 1, + name: t("upgrades.sacrifice.name"), + help: (lvl: number) => + lvl == 1 + ? t("upgrades.sacrifice.help_l1") + : t("upgrades.sacrifice.help_over", { lvl }), + fullHelp: t("upgrades.sacrifice.verbose_description"), + }, - { - category: categories.advanced, - requires: "", - threshold: 120000, - gift: false, - id: "ghost_coins", - max: 3, - name: t("upgrades.ghost_coins.name"), - help: (lvl: number) => t("upgrades.ghost_coins.tooltip", { lvl }), - fullHelp: t("upgrades.ghost_coins.verbose_description"), - }, - { - category: categories.combo_boost, - requires: "", - threshold: 125000, - gift: false, - id: "forgiving", - max: 1, - name: t("upgrades.forgiving.name"), - help: (lvl: number) => t("upgrades.forgiving.tooltip"), - fullHelp: t("upgrades.forgiving.verbose_description"), - }, - { - category: categories.simple, - requires: "", - threshold: 130000, - gift: false, - id: "ball_attracts_coins", - max: 3, - name: t("upgrades.ball_attracts_coins.name"), - help: (lvl: number) => t("upgrades.ball_attracts_coins.tooltip"), - fullHelp: t("upgrades.ball_attracts_coins.verbose_description"), - }, - { - category: categories.simple, - requires: "", - threshold: 145000, - gift: false, - id: "clairvoyant", - max: 1, - name: t("upgrades.clairvoyant.name"), - help: (lvl: number) => t("upgrades.clairvoyant.tooltip"), - fullHelp: t("upgrades.clairvoyant.verbose_description"), - }, + { + category: categories.advanced, + requires: "", + threshold: 120000, + gift: false, + id: "ghost_coins", + max: 3, + name: t("upgrades.ghost_coins.name"), + help: (lvl: number) => t("upgrades.ghost_coins.tooltip", { lvl }), + fullHelp: t("upgrades.ghost_coins.verbose_description"), + }, + { + category: categories.combo_boost, + requires: "", + threshold: 125000, + gift: false, + id: "forgiving", + max: 1, + name: t("upgrades.forgiving.name"), + help: (lvl: number) => t("upgrades.forgiving.tooltip"), + fullHelp: t("upgrades.forgiving.verbose_description"), + }, + { + category: categories.simple, + requires: "", + threshold: 130000, + gift: false, + id: "ball_attracts_coins", + max: 3, + name: t("upgrades.ball_attracts_coins.name"), + help: (lvl: number) => t("upgrades.ball_attracts_coins.tooltip"), + fullHelp: t("upgrades.ball_attracts_coins.verbose_description"), + }, + { + category: categories.simple, + requires: "", + threshold: 145000, + gift: false, + id: "clairvoyant", + max: 1, + name: t("upgrades.clairvoyant.name"), + help: (lvl: number) => t("upgrades.clairvoyant.tooltip"), + fullHelp: t("upgrades.clairvoyant.verbose_description"), + }, - { - category: categories.advanced, - requires: "", - threshold: 155000, - gift: false, - id: "implosions", - max: 1, - name: t("upgrades.implosions.name"), - help: (lvl: number) => t("upgrades.implosions.tooltip"), - fullHelp: t("upgrades.implosions.verbose_description"), - }, - { - category: categories.simple, - requires: "", - threshold: 160000, - gift: false, - id: "corner_shot", - max: 1, - name: t("upgrades.corner_shot.name"), - help: (lvl: number) => t("upgrades.corner_shot.tooltip"), - fullHelp: t("upgrades.corner_shot.verbose_description"), - }, - { - category: categories.advanced, - requires: "", - threshold: 175000, - gift: false, - id: "limitless", - max: 1, - name: t("upgrades.limitless.name"), - help: (lvl: number) => t("upgrades.limitless.tooltip", { lvl }), - fullHelp: t("upgrades.limitless.verbose_description"), - }, - { - category: categories.advanced, - requires: "", - threshold: 185000, - gift: false, - id: "trickledown", - max: 1, - name: t("upgrades.trickledown.name"), - help: (lvl: number) => t("upgrades.trickledown.tooltip", { lvl }), - fullHelp: t("upgrades.trickledown.verbose_description"), - }, - { - category: categories.combo_boost, - requires: "", - threshold: 190000, - gift: false, - id: "transparency", - max: 3, - name: t("upgrades.transparency.name"), - help: (lvl: number) => - t("upgrades.transparency.tooltip", { lvl, percent: lvl * 50 }), - fullHelp: t("upgrades.transparency.verbose_description"), - }, - { - category: categories.simple, - requires: "", - threshold: 195000, - gift: false, - id: "superhot", - max: 3, - name: t("upgrades.superhot.name"), - help: (lvl: number) => t("upgrades.superhot.tooltip", { lvl }), - fullHelp: t("upgrades.superhot.verbose_description"), - }, - { - category: categories.advanced, - requires: "", - threshold: 205000, - gift: false, - id: "rainbow", - max: 7, - name: t("upgrades.rainbow.name"), - help: (lvl: number) => t("upgrades.rainbow.tooltip", { lvl }), - fullHelp: t("upgrades.rainbow.verbose_description"), - }, - { - category: categories.advanced, - requires: "metamorphosis", - threshold: 210000, - gift: false, - id: "hypnosis", - max: 1, - name: t("upgrades.hypnosis.name"), - help: (lvl: number) => t("upgrades.hypnosis.tooltip", { lvl }), - fullHelp: t("upgrades.hypnosis.verbose_description"), - }, - { - category: categories.simple, - requires: "", - threshold: 215000, - gift: false, - id: "bricks_attract_ball", - max: 1, - name: t("upgrades.bricks_attract_ball.name"), - help: (lvl: number) => - t("upgrades.bricks_attract_ball.tooltip", { count: lvl * 3 }), - fullHelp: t("upgrades.bricks_attract_ball.verbose_description"), - }, - { - category: categories.simple, - requires: "", - threshold: 220000, - gift: false, - id: "buoy", - max: 3, - name: t("upgrades.buoy.name"), - help: (lvl: number) => t("upgrades.buoy.tooltip", { duration: lvl * 0.5 }), - fullHelp: t("upgrades.buoy.verbose_description"), - }, - { - category: categories.advanced, - requires: "", - threshold: 225000, - gift: false, - id: "ottawa_treaty", - max: 1, - name: t("upgrades.ottawa_treaty.name"), - help: () => t("upgrades.ottawa_treaty.tooltip"), - fullHelp: t("upgrades.ottawa_treaty.verbose_description"), - }, + { + category: categories.advanced, + requires: "", + threshold: 155000, + gift: false, + id: "implosions", + max: 1, + name: t("upgrades.implosions.name"), + help: (lvl: number) => t("upgrades.implosions.tooltip"), + fullHelp: t("upgrades.implosions.verbose_description"), + }, + { + category: categories.simple, + requires: "", + threshold: 160000, + gift: false, + id: "corner_shot", + max: 1, + name: t("upgrades.corner_shot.name"), + help: (lvl: number) => t("upgrades.corner_shot.tooltip"), + fullHelp: t("upgrades.corner_shot.verbose_description"), + }, + { + category: categories.advanced, + requires: "", + threshold: 175000, + gift: false, + id: "limitless", + max: 1, + name: t("upgrades.limitless.name"), + help: (lvl: number) => t("upgrades.limitless.tooltip", { lvl }), + fullHelp: t("upgrades.limitless.verbose_description"), + }, + { + category: categories.advanced, + requires: "", + threshold: 185000, + gift: false, + id: "trickledown", + max: 1, + name: t("upgrades.trickledown.name"), + help: (lvl: number) => t("upgrades.trickledown.tooltip", { lvl }), + fullHelp: t("upgrades.trickledown.verbose_description"), + }, + { + category: categories.combo_boost, + requires: "", + threshold: 190000, + gift: false, + id: "transparency", + max: 3, + name: t("upgrades.transparency.name"), + help: (lvl: number) => + t("upgrades.transparency.tooltip", { lvl, percent: lvl * 50 }), + fullHelp: t("upgrades.transparency.verbose_description"), + }, + { + category: categories.simple, + requires: "", + threshold: 195000, + gift: false, + id: "superhot", + max: 3, + name: t("upgrades.superhot.name"), + help: (lvl: number) => t("upgrades.superhot.tooltip", { lvl }), + fullHelp: t("upgrades.superhot.verbose_description"), + }, + { + category: categories.advanced, + requires: "", + threshold: 205000, + gift: false, + id: "rainbow", + max: 7, + name: t("upgrades.rainbow.name"), + help: (lvl: number) => t("upgrades.rainbow.tooltip", { lvl }), + fullHelp: t("upgrades.rainbow.verbose_description"), + }, + { + category: categories.advanced, + requires: "metamorphosis", + threshold: 210000, + gift: false, + id: "hypnosis", + max: 1, + name: t("upgrades.hypnosis.name"), + help: (lvl: number) => t("upgrades.hypnosis.tooltip", { lvl }), + fullHelp: t("upgrades.hypnosis.verbose_description"), + }, + { + category: categories.simple, + requires: "", + threshold: 215000, + gift: false, + id: "bricks_attract_ball", + max: 1, + name: t("upgrades.bricks_attract_ball.name"), + help: (lvl: number) => + t("upgrades.bricks_attract_ball.tooltip", { count: lvl * 3 }), + fullHelp: t("upgrades.bricks_attract_ball.verbose_description"), + }, + { + category: categories.simple, + requires: "", + threshold: 220000, + gift: false, + id: "buoy", + max: 3, + name: t("upgrades.buoy.name"), + help: (lvl: number) => + t("upgrades.buoy.tooltip", { duration: lvl * 0.5 }), + fullHelp: t("upgrades.buoy.verbose_description"), + }, + { + category: categories.advanced, + requires: "", + threshold: 225000, + gift: false, + id: "ottawa_treaty", + max: 1, + name: t("upgrades.ottawa_treaty.name"), + help: () => t("upgrades.ottawa_treaty.tooltip"), + fullHelp: t("upgrades.ottawa_treaty.verbose_description"), + }, + + { + category: categories.advanced, + requires: "", + threshold: 235000, + gift: false, + id: "sticky_coins", + max: 1, + name: t("upgrades.sticky_coins.name"), + help: (lvl: number) => t("upgrades.sticky_coins.tooltip"), + fullHelp: t("upgrades.sticky_coins.verbose_description"), + }, + { + category: categories.combo_boost, + requires: "", + threshold: 0, + id: "base_combo", + gift: true, + max: 7, + name: t("upgrades.base_combo.name"), + help: (lvl: number) => + t("upgrades.base_combo.tooltip", { coins: 1 + lvl * 3 }), + fullHelp: t("upgrades.base_combo.verbose_description"), + }, + { + category: categories.simple, + requires: "", + threshold: 0, + gift: false, + id: "viscosity", + max: 3, + name: t("upgrades.viscosity.name"), + help: () => t("upgrades.viscosity.tooltip"), + fullHelp: t("upgrades.viscosity.verbose_description"), + }, + { + category: categories.simple, + requires: "", + threshold: 700, + gift: false, + id: "coin_magnet", + max: 3, + name: t("upgrades.coin_magnet.name"), + help: (lvl: number) => + lvl == 1 + ? t("upgrades.coin_magnet.tooltip") + : t("upgrades.coin_magnet.help_plural"), + fullHelp: t("upgrades.coin_magnet.verbose_description"), + }, + { + category: categories.advanced, + requires: "", + threshold: 1000, + gift: false, + id: "smaller_puck", + max: 2, + name: t("upgrades.smaller_puck.name"), + help: (lvl: number) => + t("upgrades.smaller_puck.tooltip", { percent: 50 * lvl }), + fullHelp: t("upgrades.smaller_puck.verbose_description"), + }, + { + category: categories.advanced, + requires: "", + threshold: 2500, + gift: false, + id: "metamorphosis", + max: 1, + name: t("upgrades.metamorphosis.name"), + help: (lvl: number) => t("upgrades.metamorphosis.tooltip", { lvl }), + fullHelp: t("upgrades.metamorphosis.verbose_description"), + }, + { + category: categories.simple, + requires: "", + threshold: 6000, + id: "sapper", + gift: false, + max: 7, + name: t("upgrades.sapper.name"), + help: (lvl: number) => + lvl == 1 + ? t("upgrades.sapper.tooltip") + : t("upgrades.sapper.help_plural", { lvl }), + fullHelp: t("upgrades.sapper.verbose_description"), + }, + { + category: categories.simple, + requires: "", + threshold: 9000, + id: "bigger_explosions", + gift: false, + max: 1, + name: t("upgrades.bigger_explosions.name"), + help: (lvl: number) => t("upgrades.bigger_explosions.tooltip"), + fullHelp: t("upgrades.bigger_explosions.verbose_description"), + }, + { + category: categories.simple, + requires: "", + threshold: 13000, + gift: false, + adventure: false, + id: "extra_levels", + max: 3, + name: t("upgrades.extra_levels.name"), + help: (lvl: number) => + t("upgrades.extra_levels.tooltip", { count: lvl + 7 }), + fullHelp: t("upgrades.extra_levels.verbose_description"), + }, + { + category: categories.combo_boost, + requires: "", + threshold: 170000, + gift: false, + id: "fountain_toss", + max: 7, + name: t("upgrades.fountain_toss.name"), + help: () => t("upgrades.fountain_toss.tooltip"), + fullHelp: t("upgrades.fountain_toss.verbose_description"), + }, + { + category: categories.combo_boost, + requires: "", + threshold: 180000, + gift: false, + id: "minefield", + max: 3, + name: t("upgrades.minefield.name"), + help: (lvl: number) => t("upgrades.minefield.tooltip", { lvl }), + fullHelp: t("upgrades.minefield.verbose_description"), + }, + { + category: categories.combo_boost, + requires: "", + threshold: 18000, + gift: false, + id: "soft_reset", + max: 3, + name: t("upgrades.soft_reset.name"), + help: (lvl: number) => + t("upgrades.soft_reset.tooltip", { + percent: Math.round(comboKeepingRate(lvl) * 100), + }), + fullHelp: t("upgrades.soft_reset.verbose_description"), + }, + { + category: categories.combo_boost, + requires: "", + threshold: 80000, + gift: false, + id: "shunt", + max: 3, + name: t("upgrades.shunt.name"), + help: (lvl: number) => + t("upgrades.shunt.tooltip", { + percent: Math.round(comboKeepingRate(lvl) * 100), + }), + fullHelp: t("upgrades.shunt.verbose_description"), + }, + { + category: categories.combo_boost, + requires: "", + threshold: 140000, + gift: true, + id: "passive_income", + max: 4, + name: t("upgrades.passive_income.name"), + help: (lvl: number) => + t("upgrades.passive_income.tooltip", { time: lvl * 0.25, lvl }), + fullHelp: t("upgrades.passive_income.verbose_description"), + }, + { + category: categories.combo_boost, + requires: "", + threshold: 40000, + gift: false, + id: "sturdy_bricks", + max: 4, + name: t("upgrades.sturdy_bricks.name"), + help: (lvl: number) => + t("upgrades.sturdy_bricks.tooltip", { lvl, percent: lvl * 50 }), + fullHelp: t("upgrades.sturdy_bricks.verbose_description"), + }, + ] as const - { - category: categories.advanced, - requires: "", - threshold: 235000, - gift: false, - id: "sticky_coins", - max: 1, - name: t("upgrades.sticky_coins.name"), - help: (lvl: number) => t("upgrades.sticky_coins.tooltip"), - fullHelp: t("upgrades.sticky_coins.verbose_description"), - }, - { - category: categories.combo_boost, - requires: "", - threshold: 0, - id: "base_combo", - gift: true, - max: 7, - name: t("upgrades.base_combo.name"), - help: (lvl: number) => - t("upgrades.base_combo.tooltip", { coins: 1 + lvl * 3 }), - fullHelp: t("upgrades.base_combo.verbose_description"), - }, - { - category: categories.simple, - requires: "", - threshold: 0, - gift: false, - id: "viscosity", - max: 3, - name: t("upgrades.viscosity.name"), - help: () => t("upgrades.viscosity.tooltip"), - fullHelp: t("upgrades.viscosity.verbose_description"), - }, - { - category: categories.simple, - requires: "", - threshold: 700, - gift: false, - id: "coin_magnet", - max: 3, - name: t("upgrades.coin_magnet.name"), - help: (lvl: number) => - lvl == 1 - ? t("upgrades.coin_magnet.tooltip") - : t("upgrades.coin_magnet.help_plural"), - fullHelp: t("upgrades.coin_magnet.verbose_description"), - }, - { - category: categories.advanced, - requires: "", - threshold: 1000, - gift: false, - id: "smaller_puck", - max: 2, - name: t("upgrades.smaller_puck.name"), - help: (lvl: number) => - t("upgrades.smaller_puck.tooltip", { percent: 50 * lvl }), - fullHelp: t("upgrades.smaller_puck.verbose_description"), - }, - { - category: categories.advanced, - requires: "", - threshold: 2500, - gift: false, - id: "metamorphosis", - max: 1, - name: t("upgrades.metamorphosis.name"), - help: (lvl: number) => t("upgrades.metamorphosis.tooltip", { lvl }), - fullHelp: t("upgrades.metamorphosis.verbose_description"), - }, - { - category: categories.simple, - requires: "", - threshold: 6000, - id: "sapper", - gift: false, - max: 7, - name: t("upgrades.sapper.name"), - help: (lvl: number) => - lvl == 1 - ? t("upgrades.sapper.tooltip") - : t("upgrades.sapper.help_plural", { lvl }), - fullHelp: t("upgrades.sapper.verbose_description"), - }, - { - category: categories.simple, - requires: "", - threshold: 9000, - id: "bigger_explosions", - gift: false, - max: 1, - name: t("upgrades.bigger_explosions.name"), - help: (lvl: number) => t("upgrades.bigger_explosions.tooltip"), - fullHelp: t("upgrades.bigger_explosions.verbose_description"), - }, - { - category: categories.simple, - requires: "", - threshold: 13000, - gift: false, - adventure: false, - id: "extra_levels", - max: 3, - name: t("upgrades.extra_levels.name"), - help: (lvl: number) => - t("upgrades.extra_levels.tooltip", { count: lvl + 7 }), - fullHelp: t("upgrades.extra_levels.verbose_description"), - }, - { - category: categories.combo_boost, - requires: "", - threshold: 170000, - gift: false, - id: "fountain_toss", - max: 7, - name: t("upgrades.fountain_toss.name"), - help: () => t("upgrades.fountain_toss.tooltip"), - fullHelp: t("upgrades.fountain_toss.verbose_description"), - }, - { - category: categories.combo_boost, - requires: "", - threshold: 180000, - gift: false, - id: "minefield", - max: 3, - name: t("upgrades.minefield.name"), - help: (lvl: number) => t("upgrades.minefield.tooltip", { lvl }), - fullHelp: t("upgrades.minefield.verbose_description"), - }, - { - category: categories.combo_boost, - requires: "", - threshold: 18000, - gift: false, - id: "soft_reset", - max: 3, - name: t("upgrades.soft_reset.name"), - help: (lvl: number) => - t("upgrades.soft_reset.tooltip", { - percent: Math.round(comboKeepingRate(lvl) * 100), - }), - fullHelp: t("upgrades.soft_reset.verbose_description"), - }, - { - category: categories.combo_boost, - requires: "", - threshold: 80000, - gift: false, - id: "shunt", - max: 3, - name: t("upgrades.shunt.name"), - help: (lvl: number) => - t("upgrades.shunt.tooltip", { - percent: Math.round(comboKeepingRate(lvl) * 100), - }), - fullHelp: t("upgrades.shunt.verbose_description"), - }, - { - category: categories.combo_boost, - requires: "", - threshold: 140000, - gift: true, - id: "passive_income", - max: 4, - name: t("upgrades.passive_income.name"), - help: (lvl: number) => - t("upgrades.passive_income.tooltip", { time: lvl * 0.25, lvl }), - fullHelp: t("upgrades.passive_income.verbose_description"), - }, - { - category: categories.combo_boost, - requires: "", - threshold: 40000, - gift: false, - id: "sturdy_bricks", - max: 4, - name: t("upgrades.sturdy_bricks.name"), - help: (lvl: number) => - t("upgrades.sturdy_bricks.tooltip", { lvl, percent: lvl * 50 }), - fullHelp: t("upgrades.sturdy_bricks.verbose_description"), - }, -].sort((a,b)=>(a.category-b.category) || (a.threshold-b.threshold)) as const;