Багфикс: квест «забросы», HUD монет, нагрузка после босс-обрыва
- questHit('casts') вызывался без condFn: TypeError на каждом забросе
с активным квестом — квест не рос, persist()/checkAchievements()
в doCast() пропускались (счётчик забросов терялся при перезагрузке)
- награда квеста и утешение near-miss не обновляли счётчик монет в HUD
- фазовый обрыв босса теперь сбрасывает tension: «обрыв фазы без штрафа»
больше не превращается в настоящий обрыв при зажатом пальце
- регресс-проверки в tests/test.js (секция 9l), итого 58
This commit is contained in:
+4
-2
@@ -412,6 +412,7 @@ function questHit(tpl,condFn,delta){
|
||||
if(q.prog>=q.goal){
|
||||
q.prog=q.goal; q.done=true;
|
||||
save.coins+=q.reward; save.questsDoneTotal++;
|
||||
updateHUD(); // награда может прийти на забросе (вне catchFish) — счётчик монет обновить сразу
|
||||
sfx('coin');
|
||||
toast('Квест выполнен: '+questText(q)+' +'+q.reward+' 🪙');
|
||||
checkAchievements(); // quests_5
|
||||
@@ -668,7 +669,7 @@ function doCast(){
|
||||
castT=0; state='CAST'; sfx('cast');
|
||||
save.casts++;
|
||||
newDayCheck();
|
||||
questHit('casts');
|
||||
questHit('casts',()=>true); // condFn обязателен: без него questHit падает с TypeError
|
||||
checkAchievements();
|
||||
persist();
|
||||
}
|
||||
@@ -722,7 +723,7 @@ function updateReel(dt){
|
||||
stateBoss=false; bossPhase=0; // M4: босс тоже может уйти — босс-бой окончен
|
||||
const nm=Math.floor(reel.w*sp.price*0.1);
|
||||
if(nm>0){
|
||||
save.coins+=nm; persist();
|
||||
save.coins+=nm; persist(); updateHUD();
|
||||
toast('Сбежала! '+sp.emoji+' '+sp.name+' '+reel.w.toFixed(1)+' кг · +'+nm+' 🪙');
|
||||
}else{
|
||||
toast('Сбежала! '+sp.emoji+' '+sp.name+' '+reel.w.toFixed(1)+' кг');
|
||||
@@ -847,6 +848,7 @@ function updateGame(dt){
|
||||
if(stateBoss && bossPhase<3){
|
||||
// M4: босс-обрыв — не штраф: автоматом следующая (глубже) фаза, без ввода
|
||||
reel.d=(bossPhase===1?0.6:1.0)*reel.d0; // фаза2: d=0.6·d0, фаза3: d=1.0·d0
|
||||
reel.tension=0; // фазовый обрыв сбрасывает нагрузку, иначе «беспошлинный» обрыв ведёт к настоящему
|
||||
bossPhase++;
|
||||
state='REEL';
|
||||
}else{
|
||||
|
||||
@@ -645,6 +645,96 @@ const sleep = ms => new Promise(r => setTimeout(r, ms));
|
||||
pickSpecies = window.__m4Pick;
|
||||
});
|
||||
|
||||
// --- 9l. Регрессии багфиксов спринта 3 ---
|
||||
// (1) квест «Сделай N забросов»: questHit('casts') вызывался без condFn и падал
|
||||
// TypeError на каждом забросе — квест не рос, а persist()/checkAchievements()
|
||||
// в doCast() пропускались (счётчик забросов терялся при перезагрузке)
|
||||
await page.evaluate(() => {
|
||||
save.quests = { date: todayStr(), list: [{ tpl: 'casts', param: 0, goal: 1, prog: 0, done: false, reward: 60 }] };
|
||||
save.streak = { last: todayStr(), days: 1, shieldWeek: null }; // стрик «сегодня» — не искажает монеты
|
||||
save.coins = 100;
|
||||
state = 'IDLE'; reel = null; stateBoss = false; bossPhase = 0; biteFish = null;
|
||||
});
|
||||
const castsQBefore = await page.evaluate(() => ({ casts: save.casts }));
|
||||
const peBeforeCastsQ = pageErrors.length;
|
||||
await page.mouse.move(195, 600);
|
||||
await page.mouse.down(); await sleep(450); await page.mouse.up();
|
||||
await waitState(page, 'WAIT');
|
||||
const castsQ = await page.evaluate(() => ({
|
||||
prog: save.quests.list[0].prog,
|
||||
done: save.quests.list[0].done,
|
||||
coins: save.coins,
|
||||
casts: save.casts,
|
||||
lsCasts: JSON.parse(localStorage.getItem('fishing-save-v1')).casts,
|
||||
hud: document.getElementById('coins').textContent,
|
||||
}));
|
||||
ok('багфикс квест «забросы»: квест растёт и выполняется на забросе (+60 🪙), без TypeError, заброс записан в сейв',
|
||||
castsQ.prog === 1 && castsQ.done === true && castsQ.coins === 160
|
||||
&& castsQ.casts === castsQBefore.casts + 1 && castsQ.lsCasts === castsQ.casts
|
||||
&& pageErrors.length === peBeforeCastsQ,
|
||||
JSON.stringify({ castsQ, pe: pageErrors.length - peBeforeCastsQ }));
|
||||
// (2) награда квеста на забросе — вне catchFish: HUD монет должен обновиться сразу
|
||||
ok('багфикс HUD квеста: счётчик монет обновлён сразу после выполнения квеста на забросе',
|
||||
castsQ.hud === '🪙 ' + castsQ.coins, castsQ.hud);
|
||||
|
||||
// (2b) near-miss: утешение +10% цены тоже начисляется вне catchFish — HUD актуален
|
||||
await page.mouse.move(195, 600);
|
||||
await page.mouse.down(); await sleep(450); await page.mouse.up();
|
||||
await waitState(page, 'WAIT');
|
||||
await page.evaluate(() => { biteTimer = 0.05; });
|
||||
await waitState(page, 'BITE', 4000);
|
||||
await page.mouse.down(); await page.mouse.up();
|
||||
await waitState(page, 'REEL');
|
||||
await page.evaluate(() => {
|
||||
reel.w = 5; // фиксируем вес — утешение детерминированно и больше нуля
|
||||
reel.phase = 'pull'; reel.phaseT = 9999;
|
||||
reel.d = reel.d0 * 1.38;
|
||||
});
|
||||
await waitState(page, 'WAIT', 15000);
|
||||
const nmHud = await page.evaluate(() => ({
|
||||
coins: save.coins,
|
||||
hud: document.getElementById('coins').textContent,
|
||||
}));
|
||||
ok('багфикс HUD near-miss: после «Сбежала! +N 🪙» счётчик монет актуален',
|
||||
nmHud.hud === '🪙 ' + nmHud.coins, JSON.stringify(nmHud));
|
||||
|
||||
// (3) босс-бой: фазовый обрыв должен сбрасывать накопленную нагрузку —
|
||||
// иначе «обрыв фазы без штрафа» с tension≈0.9·line тут же рвал шнур по-настоящему
|
||||
await page.evaluate(() => {
|
||||
forceBoss = true; SHINY_CHANCE = 0;
|
||||
window.__pick2 = pickSpecies; pickSpecies = () => SPECIES.find(s => s.id === 'sturge');
|
||||
state = 'IDLE'; reel = null; stateBoss = false; bossPhase = 0; biteFish = null;
|
||||
save.quests = { date: todayStr(), list: [] };
|
||||
});
|
||||
await page.mouse.move(195, 600);
|
||||
await page.mouse.down(); await sleep(450); await page.mouse.up();
|
||||
await waitState(page, 'WAIT');
|
||||
await page.evaluate(() => { biteTimer = 0.05; });
|
||||
await waitState(page, 'BITE', 4000);
|
||||
await page.mouse.down(); await page.mouse.up();
|
||||
await waitState(page, 'REEL');
|
||||
await page.evaluate(() => {
|
||||
reel.d = 2; reel.phase = 'calm'; reel.phaseT = 9999;
|
||||
reel.tension = reel.line * 0.9; // рыба тянула почти до предела
|
||||
});
|
||||
await page.mouse.down();
|
||||
await waitState(page, 'SNAP', 5000);
|
||||
// палец НЕ отпускаем: после авто-возврата в REEL нагрузка должна стартовать с нуля
|
||||
const bossPh = await page.evaluate(() => new Promise(res => {
|
||||
const iv = setInterval(() => {
|
||||
if (state === 'REEL') { clearInterval(iv); res({ st: state, ph: bossPhase, boss: stateBoss, tension: reel.tension, line: reel.line }); }
|
||||
else if (state === 'SNAP' && !stateBoss) { clearInterval(iv); res({ st: 'REAL SNAP' }); }
|
||||
}, 10);
|
||||
}));
|
||||
await page.mouse.up();
|
||||
ok('багфикс босс-обрыв фазы: после авто-возврата в REEL нагрузка сброшена (tension≈0), бой продолжается',
|
||||
bossPh.st === 'REEL' && bossPh.boss === true && bossPh.ph === 2 && bossPh.tension < bossPh.line * 0.1,
|
||||
JSON.stringify(bossPh));
|
||||
await page.evaluate(() => {
|
||||
forceBoss = false; SHINY_CHANCE = 0.03; pickSpecies = window.__pick2;
|
||||
state = 'IDLE'; reel = null; stateBoss = false; bossPhase = 0; biteFish = null;
|
||||
});
|
||||
|
||||
// --- 10. Ошибки консоли ---
|
||||
ok('нет ошибок JS (pageerror)', pageErrors.length === 0, pageErrors.join(' | '));
|
||||
ok('нет ошибок консоли', consoleErrors.length === 0, consoleErrors.join(' | '));
|
||||
|
||||
Reference in New Issue
Block a user