This commit is contained in:
Renan LE CARO 2025-04-29 17:53:35 +02:00
parent d17eba50e5
commit 99930cb77f
13 changed files with 256 additions and 104 deletions

115
dist/index.html vendored

File diff suppressed because one or more lines are too long

View file

@ -184,7 +184,7 @@ body:not(.has-alert-open) #popup {
cursor: not-allowed; cursor: not-allowed;
} }
&.no-border{ &.no-border {
border-color: transparent; border-color: transparent;
} }
@ -214,6 +214,7 @@ body:not(.has-alert-open) #popup {
} }
> button[data-help-content] { > button[data-help-content] {
user-select: none;
border-radius: 4px; border-radius: 4px;
outline: none; outline: none;
align-self: center; align-self: center;
@ -432,10 +433,10 @@ h2.histogram-title strong {
line-height: 12px; line-height: 12px;
display: inline-block; display: inline-block;
position: relative; position: relative;
top: -3px; //top: -3px;
font-weight: bold; font-weight: bold;
border: 1px solid #FFF; border: 1px solid #FFF;
margin-left: 5px; //margin-left: 5px;
> span { > span {
display: inline-block; display: inline-block;
@ -488,12 +489,39 @@ h2.histogram-title strong {
} }
&.free { &.free {
opacity: 0.8; //opacity: 0.8;
img {
opacity: 0.5;
}
} }
&.banned { &.banned {
opacity: 0.8; opacity: 0.8;
} }
&.greyed-out {
opacity: 0.2;
}
button {
color: #fff;
background: gold;
align-self: flex-start;
font-weight: bold;
padding: 5px;
border-radius: 5px;
box-shadow: 0 4px 0 gold, 0 4px 10px black;
border: 2px solid white;
cursor: pointer;
text-shadow: 0 0 4px rgba(0, 0, 0, 0.3);
user-select: none;
&:active{
transform: translate(0,4px);
box-shadow: 0 0px 0 gold, 0 0px 10px black;
}
transition: transform 0.2s, box-shadow 0.2s;
}
} }
#tooltip { #tooltip {

View file

@ -319,3 +319,7 @@ export function hoursSpentPlaying() {
return 0; return 0;
} }
} }
export function escapeAttribute(str:String){
return str.replace(/&/gi,'&amp;').replace(/</gi,'&lt;').replace(/"/gi,'&quot;').replace(/'/gi,'&#39;')
}

View file

@ -72,8 +72,10 @@
"level_up.instructions": "", "level_up.instructions": "",
"level_up.maxed_upgrade": "", "level_up.maxed_upgrade": "",
"level_up.no_points": "", "level_up.no_points": "",
"level_up.pick": "",
"level_up.pick_upgrade": "", "level_up.pick_upgrade": "",
"level_up.title": "لقد انتهيت للتو من المستوى {{level}}/{{max}}.", "level_up.title": "لقد انتهيت للتو من المستوى {{level}}/{{max}}.",
"level_up.upgrade": "",
"level_up.upgrade_perk_to_level": "", "level_up.upgrade_perk_to_level": "",
"main_menu.basic": "", "main_menu.basic": "",
"main_menu.basic_help": "", "main_menu.basic_help": "",

View file

@ -2632,6 +2632,41 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>pick</name>
<description/>
<comment/>
<translations>
<translation>
<language>ar-LB</language>
<approved>false</approved>
</translation>
<translation>
<language>de-DE</language>
<approved>false</approved>
</translation>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-CL</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-FR</language>
<approved>false</approved>
</translation>
<translation>
<language>ru-RU</language>
<approved>false</approved>
</translation>
<translation>
<language>tr-TR</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>pick_upgrade</name> <name>pick_upgrade</name>
<description/> <description/>
@ -2702,6 +2737,41 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>upgrade</name>
<description/>
<comment/>
<translations>
<translation>
<language>ar-LB</language>
<approved>false</approved>
</translation>
<translation>
<language>de-DE</language>
<approved>false</approved>
</translation>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-CL</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-FR</language>
<approved>false</approved>
</translation>
<translation>
<language>ru-RU</language>
<approved>false</approved>
</translation>
<translation>
<language>tr-TR</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>upgrade_perk_to_level</name> <name>upgrade_perk_to_level</name>
<description/> <description/>

View file

@ -72,8 +72,10 @@
"level_up.instructions": "", "level_up.instructions": "",
"level_up.maxed_upgrade": "", "level_up.maxed_upgrade": "",
"level_up.no_points": "", "level_up.no_points": "",
"level_up.pick": "",
"level_up.pick_upgrade": "", "level_up.pick_upgrade": "",
"level_up.title": "Du hast gerade Level {{level}}/{{max}} beendet.", "level_up.title": "Du hast gerade Level {{level}}/{{max}} beendet.",
"level_up.upgrade": "",
"level_up.upgrade_perk_to_level": "", "level_up.upgrade_perk_to_level": "",
"main_menu.basic": "", "main_menu.basic": "",
"main_menu.basic_help": "", "main_menu.basic_help": "",

View file

@ -69,11 +69,13 @@
"lab.select_level": "Select a level to play on", "lab.select_level": "Select a level to play on",
"lab.unlocks_at": "Unlocks at total score {{score}}", "lab.unlocks_at": "Unlocks at total score {{score}}",
"level_up.go": "Continue to level \"{{name}}\"", "level_up.go": "Continue to level \"{{name}}\"",
"level_up.instructions": "You can upgrade perks below using your {{count}} extra lives. ", "level_up.instructions": "You gained {{gain}} extra lives. You can use your {{count}} extra lives to buy upgrades below, or keep them to be safe. ",
"level_up.maxed_upgrade": "\"{{name}}\" is at max level", "level_up.maxed_upgrade": "\"{{name}}\" is at max level",
"level_up.no_points": "You've spent all your extra lives.", "level_up.no_points": "You've spent all your extra lives.",
"level_up.pick": "Pick",
"level_up.pick_upgrade": "Get \"{{name}}\"", "level_up.pick_upgrade": "Get \"{{name}}\"",
"level_up.title": "You just finished level {{level}}/{{max}}.", "level_up.title": "Level {{level}}/{{max}} cleared",
"level_up.upgrade": "Upgrade",
"level_up.upgrade_perk_to_level": "Upgrade \"{{name}}\" to level {{level}}", "level_up.upgrade_perk_to_level": "Upgrade \"{{name}}\" to level {{level}}",
"main_menu.basic": "", "main_menu.basic": "",
"main_menu.basic_help": "", "main_menu.basic_help": "",

View file

@ -72,8 +72,10 @@
"level_up.instructions": "", "level_up.instructions": "",
"level_up.maxed_upgrade": "", "level_up.maxed_upgrade": "",
"level_up.no_points": "", "level_up.no_points": "",
"level_up.pick": "",
"level_up.pick_upgrade": "", "level_up.pick_upgrade": "",
"level_up.title": "Acabas de completar el nivel {{level}}/{{max}}.", "level_up.title": "Acabas de completar el nivel {{level}}/{{max}}.",
"level_up.upgrade": "",
"level_up.upgrade_perk_to_level": "", "level_up.upgrade_perk_to_level": "",
"main_menu.basic": "Gráficos simplificados", "main_menu.basic": "Gráficos simplificados",
"main_menu.basic_help": "Mejor rendimiento.", "main_menu.basic_help": "Mejor rendimiento.",

View file

@ -72,8 +72,10 @@
"level_up.instructions": "", "level_up.instructions": "",
"level_up.maxed_upgrade": "", "level_up.maxed_upgrade": "",
"level_up.no_points": "", "level_up.no_points": "",
"level_up.pick": "",
"level_up.pick_upgrade": "", "level_up.pick_upgrade": "",
"level_up.title": "Vous venez de terminer le niveau {{level}}/{{max}}.", "level_up.title": "Vous venez de terminer le niveau {{level}}/{{max}}.",
"level_up.upgrade": "",
"level_up.upgrade_perk_to_level": "", "level_up.upgrade_perk_to_level": "",
"main_menu.basic": "", "main_menu.basic": "",
"main_menu.basic_help": "", "main_menu.basic_help": "",

View file

@ -72,8 +72,10 @@
"level_up.instructions": "", "level_up.instructions": "",
"level_up.maxed_upgrade": "", "level_up.maxed_upgrade": "",
"level_up.no_points": "", "level_up.no_points": "",
"level_up.pick": "",
"level_up.pick_upgrade": "", "level_up.pick_upgrade": "",
"level_up.title": "Вы только что закончили уровень {{level}}/{{max}}.", "level_up.title": "Вы только что закончили уровень {{level}}/{{max}}.",
"level_up.upgrade": "",
"level_up.upgrade_perk_to_level": "", "level_up.upgrade_perk_to_level": "",
"main_menu.basic": "", "main_menu.basic": "",
"main_menu.basic_help": "", "main_menu.basic_help": "",

View file

@ -72,8 +72,10 @@
"level_up.instructions": "", "level_up.instructions": "",
"level_up.maxed_upgrade": "", "level_up.maxed_upgrade": "",
"level_up.no_points": "", "level_up.no_points": "",
"level_up.pick": "",
"level_up.pick_upgrade": "", "level_up.pick_upgrade": "",
"level_up.title": " {{level}}/{{max}}seviyesini yeni bitirdiniz.", "level_up.title": " {{level}}/{{max}}seviyesini yeni bitirdiniz.",
"level_up.upgrade": "",
"level_up.upgrade_perk_to_level": "", "level_up.upgrade_perk_to_level": "",
"main_menu.basic": "", "main_menu.basic": "",
"main_menu.basic_help": "", "main_menu.basic_help": "",

View file

@ -13,10 +13,10 @@ import {t} from "./i18n/i18n";
import {icons, upgrades} from "./loadGameData"; import {icons, upgrades} from "./loadGameData";
import {asyncAlert} from "./asyncAlert"; import {asyncAlert} from "./asyncAlert";
import { import {
escapeAttribute,
getPossibleUpgrades, getPossibleUpgrades,
levelsListHTMl, levelsListHTMl,
max_levels, max_levels,
pickedUpgradesHTMl,
upgradeLevelAndMaxDisplay upgradeLevelAndMaxDisplay
} from "./game_utils"; } from "./game_utils";
import {getNearestUnlockHTML} from "./openScorePanel"; import {getNearestUnlockHTML} from "./openScorePanel";
@ -25,12 +25,13 @@ export async function openUpgradesPicker(gameState: GameState) {
const catchRate = const catchRate =
gameState.levelCoughtCoins / (gameState.levelSpawnedCoins || 1); gameState.levelCoughtCoins / (gameState.levelSpawnedCoins || 1);
gameState.extra_lives++ let choices = 3
let choices = 3 + gameState.perks.one_more_choice let livesWon=1
if (gameState.levelWallBounces < wallBouncedGood) { if (gameState.levelWallBounces < wallBouncedGood) {
choices++; choices++;
gameState.extra_lives++;
livesWon++;
if (gameState.levelWallBounces < wallBouncedBest) { if (gameState.levelWallBounces < wallBouncedBest) {
choices++; choices++;
} }
@ -38,100 +39,104 @@ export async function openUpgradesPicker(gameState: GameState) {
if (gameState.levelTime < levelTimeGood * 1000) { if (gameState.levelTime < levelTimeGood * 1000) {
choices++; choices++;
gameState.extra_lives++; livesWon++;
if (gameState.levelTime < levelTimeBest * 1000) { if (gameState.levelTime < levelTimeBest * 1000) {
choices++; choices++;
} }
} }
if (catchRate > catchRateGood / 100) { if (catchRate > catchRateGood / 100) {
choices++; choices++;
gameState.extra_lives++; livesWon++;
if (catchRate > catchRateBest / 100) { if (catchRate > catchRateBest / 100) {
choices++; choices++;
} }
} }
if (gameState.levelMisses < missesGood) { if (gameState.levelMisses < missesGood) {
choices++; choices++;
gameState.extra_lives++; livesWon++;
if (gameState.levelMisses < missesBest) { if (gameState.levelMisses < missesBest) {
choices++; choices++;
} }
} }
let offered:PerkId[]= getPossibleUpgrades(gameState) gameState.extra_lives+=livesWon
let offered: PerkId[] = getPossibleUpgrades(gameState)
.map((u) => ({ .map((u) => ({
...u, ...u,
score: Math.random() + (gameState.lastOffered[u.id] || 0), score: Math.random() + (gameState.lastOffered[u.id] || 0),
})) }))
.sort((a, b) => a.score - b.score) .sort((a, b) => a.score - b.score)
.filter((u) => gameState.perks[u.id] < u.max + gameState.perks.limitless) .filter((u) => gameState.perks[u.id] < u.max + gameState.perks.limitless)
.slice(0, choices) .map(u => u.id)
.map(u=>u.id)
const fromStart = upgrades.map(u => u.id).filter(id => gameState.perks[id])
offered.forEach((id) => {
dontOfferTooSoon(gameState, id);
});
let list = upgrades.filter(u=>offered.includes(u.id)||gameState.perks[u.id])
while (true) { while (true) {
let actions: Array<{
text: string;
icon: string;
value: PerkId | null;
help: string;
className: string;
tooltip: string;
}> = list.map((u) => {
const disabled= !gameState.extra_lives || gameState.perks[u.id] >= u.max + gameState.perks.limitless const updatedChoices = gameState.perks.one_more_choice + choices
const lvl= gameState.perks[u.id] let list = upgrades.filter(u => offered.slice(0, updatedChoices).includes(u.id) || gameState.perks[u.id])
list = list.filter(u => fromStart.includes(u.id))
.concat(list.filter(u => !fromStart.includes(u.id)))
list.forEach((u) => {
dontOfferTooSoon(gameState, u.id);
});
return ({
text: u.name + (lvl ? upgradeLevelAndMaxDisplay(u, gameState):''),
help: u.help(Math.max(1, lvl)),
tooltip: u.fullHelp(Math.max(1, lvl)),
icon: icons["icon:" + u.id],
value: u.id as PerkId,
className: "upgrade " + (disabled && lvl ? 'no-border ':' ') + ( lvl ? '':'grey-out-unless-hovered ') ,
disabled:disabled ,
})
})
actions = [
...actions.filter(a=>gameState.perks[a.value]),
...actions.filter(a=>!gameState.perks[a.value]),
]
const upgradeId = await asyncAlert<PerkId | null>({ const upgradeId = await asyncAlert<PerkId | null>({
title: title:
t("level_up.title", { t("level_up.title", {
level: gameState.currentLevel , level: gameState.currentLevel,
max: max_levels(gameState), max: max_levels(gameState),
}), }),
content: [ content: [
{ {
text: t('level_up.go',{name:gameState.level.name}), text: t('level_up.go', {name: gameState.level.name}),
icon: icons[gameState.level.name], icon: icons[gameState.level.name],
value:null, value: null,
}, },
// pickedUpgradesHTMl(gameState),
gameState.extra_lives ? `<p>${t("level_up.instructions", { gameState.extra_lives ? `<p>${t("level_up.instructions", {
count:gameState.extra_lives count: gameState.extra_lives,
})}</p>` :`<p>${t("level_up.no_points")}</p>` , gain:livesWon
...actions, })}</p>` : `<p>${t("level_up.no_points")}</p>`,
levelsListHTMl(gameState, gameState.currentLevel ), ...list.map((u) => {
const max = u.max + gameState.perks.limitless
const lvl = gameState.perks[u.id]
const button = !gameState.extra_lives || gameState.perks[u.id] >= max ?
'' : ` <button data-resolve-to="${u.id}">${
lvl ? t('level_up.upgrade') : t('level_up.pick')
}</button>`
const lvlInfo = lvl ? upgradeLevelAndMaxDisplay(u, gameState) : ''
return `<div class="upgrade choice ${
(!lvl && gameState.extra_lives && 'free') ||
(lvl && 'used') ||
'greyed-out'
}" >
${icons["icon:" + u.id]}
<p data-tooltip="${escapeAttribute(u.fullHelp(Math.max(1, lvl)))}">
<strong>${u.name}</strong> ${lvlInfo}
${u.help(Math.max(1, lvl))}
</p>
${button}
</div>`
})
,
levelsListHTMl(gameState, gameState.currentLevel),
getNearestUnlockHTML(gameState), getNearestUnlockHTML(gameState),
`<div id="level-recording-container"></div>`, `<div id="level-recording-container"></div>`,
], ],
}); });
if (upgradeId ) { if (upgradeId) {
gameState.perks[upgradeId]++; gameState.perks[upgradeId]++;
gameState.runStatistics.upgrades_picked++; gameState.runStatistics.upgrades_picked++;
gameState.extra_lives-- gameState.extra_lives--
}else{ } else {
return return
} }
} }

View file

@ -914,10 +914,10 @@ export const rawUpgrades = [
max: 4, max: 4,
name: t("upgrades.passive_income.name"), name: t("upgrades.passive_income.name"),
help: (lvl: number) => help: (lvl: number) =>
t("upgrades.passive_income.tooltip", { time: lvl * 0.1 - 0.05, lvl }), t("upgrades.passive_income.tooltip", { time: (lvl * 0.1 - 0.05).toFixed(2), lvl }),
fullHelp: (lvl: number) => fullHelp: (lvl: number) =>
t("upgrades.passive_income.verbose_description", { t("upgrades.passive_income.verbose_description", {
time: lvl * 0.1 - 0.05, time: (lvl * 0.1 - 0.05).toFixed(2),
lvl, lvl,
}), }),
}, },