Rapikan integrasi Tahap 2: catatan Yang baru memuat HUD, VS, dan layar hasil; tes arcade menunggu layar VS (bukan tidur tetap); catatan mesin

This commit is contained in:
rizkyaz0 2026-10-03 08:24:58 +07:00
parent 00771939ff
commit 4743c24246
3 changed files with 10 additions and 4 deletions

View File

@ -5,8 +5,12 @@
date berbentuk 'YYYY-MM-DD'; items berupa kalimat pendek berbahasa Indonesia untuk pemain, bukan catatan teknis. */ date berbentuk 'YYYY-MM-DD'; items berupa kalimat pendek berbahasa Indonesia untuk pemain, bukan catatan teknis. */
window.CHANGELOG = [ window.CHANGELOG = [
{ {
version: '0.4', date: '2026-10-03', title: 'Wajah baru menu', version: '0.4', date: '2026-10-03', title: 'Wajah baru menu dan layar pertandingan',
items: [ items: [
'Meter ultimate di bawah bar HP: terisi mengikuti cooldown, berkilau dan berlabel SIAP saat bisa dipakai, lalu jadi bar waktu mode saat mode pasca-ultimate aktif. Lawan punya versi ringkasnya.',
'Layar VS sebelum ronde 1: dua potret berhadapan dengan kutipan pembuka tiap petarung. Klik, Spasi, Enter, atau Esc untuk melewatinya.',
'Layar hasil baru: pemenang tampil besar dengan kutipan, rincian koin per baris, empat statistik, dan tombol Main lagi, Pilih ulang, Ke toko, Menu utama. Akhir Arcade dan Survival memakai tampilan yang sama.',
'Menu jeda (Esc) berisi Daftar gerakan: kontrol dasar, nama serangan dan skill karakter beserta cooldown, gerakan perintah, dan mode karakter.',
'Latar menu utama kini kolase tujuh petarung Konoha Fighting dengan gerak pelan, tidak lagi memakai gambar bawaan game asal.', 'Latar menu utama kini kolase tujuh petarung Konoha Fighting dengan gerak pelan, tidak lagi memakai gambar bawaan game asal.',
'Layar loading menampilkan kutipan acak yang berganti setiap kali game dibuka.', 'Layar loading menampilkan kutipan acak yang berganti setiap kali game dibuka.',
'Daftar "Yang baru" di layar About, plus pemberitahuan singkat satu kali saat ada pembaruan.', 'Daftar "Yang baru" di layar About, plus pemberitahuan singkat satu kali saat ada pembaruan.',

View File

@ -18,6 +18,8 @@ Game fighting 2D canvas, tanpa dependensi dan tanpa langkah build. Semua teks un
- `touch.js`: kontrol sentuh; tombol memanggil `__game.input(key, down)`. - `touch.js`: kontrol sentuh; tombol memanggil `__game.input(key, down)`.
- `brand.js` (`window.Brand`) + `content/loading.js` (`window.LOADING_QUOTES`) + `content/changelog.js` (`window.CHANGELOG`): dimuat di `index.html` tepat setelah kartu `#boot`, sebelum `precache.js`. Kutipan acak (tidak pernah sama dengan yang terakhir, kunci `konoha.loadquote`; `?quote=N` memaksa) tampil di `#boot .boot-quote` dan `#load-state .load-quote`. "Yang baru": `Brand.decorate(root, screen)` dipanggil `menu.js` di akhir `render()`; layar `about` mendapat panel `.whatsnew-panel` dan tautan kredit, layar `home` memicu toast `.brand-toast` satu kali bila versi teratas CHANGELOG berbeda dari `localStorage['konoha.changelog.seen']` (pemain tanpa simpanan `konoha.save.v1` tidak diberi toast). Menambah pembaruan: sisipkan objek baru di AWAL `content/changelog.js` dengan version lebih besar. Berkas `content/*.js` ikut `tools/build_precache.py`. - `brand.js` (`window.Brand`) + `content/loading.js` (`window.LOADING_QUOTES`) + `content/changelog.js` (`window.CHANGELOG`): dimuat di `index.html` tepat setelah kartu `#boot`, sebelum `precache.js`. Kutipan acak (tidak pernah sama dengan yang terakhir, kunci `konoha.loadquote`; `?quote=N` memaksa) tampil di `#boot .boot-quote` dan `#load-state .load-quote`. "Yang baru": `Brand.decorate(root, screen)` dipanggil `menu.js` di akhir `render()`; layar `about` mendapat panel `.whatsnew-panel` dan tautan kredit, layar `home` memicu toast `.brand-toast` satu kali bila versi teratas CHANGELOG berbeda dari `localStorage['konoha.changelog.seen']` (pemain tanpa simpanan `konoha.save.v1` tidak diberi toast). Menambah pembaruan: sisipkan objek baru di AWAL `content/changelog.js` dengan version lebih besar. Berkas `content/*.js` ikut `tools/build_precache.py`.
- Latar menu utama dan About: `menu.js` `collageHtml()` menyusun tujuh potret `assets/menu/<id>-select.webp` (lima di layar sentuh) menjadi kolase CSS (`.hc-*` di bagian "Merek" paling bawah `menu.css`). Gerak berhenti lewat kelas `.bg-still` pada `#front-menu` (`FrontEnd.syncBackground()`: Pengaturan terbuka, tab tersembunyi, saklar "Animasi latar menu", `prefers-reduced-motion`). Video dan gambar bergaya game asal (`home-factions.webp`, `home-factions-loop.mp4`, `home-art.webp`) tidak dipakai lagi tetapi berkasnya masih ada (dan ikut daftar precache). - Latar menu utama dan About: `menu.js` `collageHtml()` menyusun tujuh potret `assets/menu/<id>-select.webp` (lima di layar sentuh) menjadi kolase CSS (`.hc-*` di bagian "Merek" paling bawah `menu.css`). Gerak berhenti lewat kelas `.bg-still` pada `#front-menu` (`FrontEnd.syncBackground()`: Pengaturan terbuka, tab tersembunyi, saklar "Animasi latar menu", `prefers-reduced-motion`). Video dan gambar bergaya game asal (`home-factions.webp`, `home-factions-loop.mp4`, `home-art.webp`) tidak dipakai lagi tetapi berkasnya masih ada (dan ikut daftar precache).
- `vs.js` (`window.VS`, `window.ResultView`) + `vs.css` + `content/quotes.js` (`window.QUOTES`: intro/win/lose per karakter): layar VS dan layar hasil. `startMatch({..., vs: true | {label, p2}})` menampilkan layar VS 2,2 dtk (hanya mode versus; latihan tidak); selama itu `vsHold` di game.js menahan `advanceMatch` dan cue 'Round 1' keluar tepat sekali saat VS selesai atau dilewati (klik/Spasi/Enter/Esc setelah 0,38 dtk). `startMatch` tanpa `vs` berperilaku seperti dulu. `menu.js` screen `result` memakai `ResultView.view/mount` (layar lama jadi cadangan); `Meta.award` menyimpan rincian di `Meta.lastAward`; `Meta.nextFight`/`finishRun` memakai VS dan layar hasil yang sama. Pemilih kutipan `VS.quote(id, 'intro'|'win'|'lose')` memakai pengacak kosmetik terpisah. API uji: `__game.vsActive()`, `__game.vsSkip()`.
- HUD (game.js): meter ultimate `#ult-player`/`#ult-enemy` (`updateUltMeters`; mengisi/SIAP/waktu mode dari `modeOf`, `bwx.rage`, bentuk FENR; DOM hanya ditulis saat tampilan berubah). Menu jeda `#pause-panel` dua panel; `buildMoveList()` membangun ulang Daftar gerakan tiap `setPaused(true)`, pilihan lipat diingat di `localStorage['konoha.moveList']`.
- `assets/<id>/` atlas sprite (15 state), `manifest.js` (data + metrik), `ui/`; `work/` (di repo induk, luar folder ini) berisi pipeline pembuat karakter. - `assets/<id>/` atlas sprite (15 state), `manifest.js` (data + metrik), `ui/`; `work/` (di repo induk, luar folder ini) berisi pipeline pembuat karakter.
- `precache.js`/`files.json`: **dibuat otomatis** oleh `tools/build_precache.py` — jangan diedit atau di-commit oleh cabang fitur; perintahkan integrator membangun ulang. - `precache.js`/`files.json`: **dibuat otomatis** oleh `tools/build_precache.py` — jangan diedit atau di-commit oleh cabang fitur; perintahkan integrator membangun ulang.
@ -27,7 +29,7 @@ Game fighting 2D canvas, tanpa dependensi dan tanpa langkah build. Semua teks un
`__game.hitDummy`, `__game.feel` dan `__game.feelState()` membuka tabel rasa kena, status K.O./angka untuk `tests/t1-feel.mjs`. `__game.fx.snapshot()` melaporkan keadaan efek (bayangan, genangan api, DoT, aba-aba, proyektil beserta gaya/umur) untuk skenario uji. Untuk uji deterministik set `__game.manual = true` dulu; kalau tidak, loop waktu nyata ikut memajukan simulasi saat screenshot. `__game.hitDummy`, `__game.feel` dan `__game.feelState()` membuka tabel rasa kena, status K.O./angka untuk `tests/t1-feel.mjs`. `__game.fx.snapshot()` melaporkan keadaan efek (bayangan, genangan api, DoT, aba-aba, proyektil beserta gaya/umur) untuk skenario uji. Untuk uji deterministik set `__game.manual = true` dulu; kalau tidak, loop waktu nyata ikut memajukan simulasi saat screenshot.
## Alat uji headless ## Alat uji headless
`node tests/harness.mjs smoke` — 7 karakter × easy/hard melawan CPU, gagal bila ada galat halaman. `node tests/harness.mjs tests/foo.mjs` — menjalankan skenario: `export default async ({ page, game, errors, characters }) => hasil` (`game(fn, arg)` = `page.evaluate`). Screenshot: `await page.screenshot({path})` lalu `Read` gambar. `tests/t1-fx.mjs` melepas semua jurus enam karakter berbasis data dari kedua sisi (env `FX_SHOTS` = folder screenshot, `FX_ONLY` = regex nama jurus). Node dan Playwright sudah terpasang; tidak perlu `npm install`. `tests/t2-brand.mjs` (env `BRAND_SHOTS`, `BRAND_ONLY=text|quote|log|menu|flow|docs`) menguji sisa nama game asal di seluruh layar, kutipan loading, Yang baru dan toast, serta latar kolase. `node tests/harness.mjs smoke` — 7 karakter × easy/hard melawan CPU, gagal bila ada galat halaman. `node tests/harness.mjs tests/foo.mjs` — menjalankan skenario: `export default async ({ page, game, errors, characters }) => hasil` (`game(fn, arg)` = `page.evaluate`). Screenshot: `await page.screenshot({path})` lalu `Read` gambar. `tests/t1-fx.mjs` melepas semua jurus enam karakter berbasis data dari kedua sisi (env `FX_SHOTS` = folder screenshot, `FX_ONLY` = regex nama jurus). Node dan Playwright sudah terpasang; tidak perlu `npm install`. `tests/t2-hud.mjs` (env `HUD_ONLY=meter|enemy|cpu|pause|layout`) menguji meter ultimate dan menu jeda; `tests/t2-vsresult.mjs` (env `VSR_SHOTS`, `VSR_ONLY=quotes|vs|skip|abort|result|run|ui|phone`) menguji layar VS, layar hasil, dan kutipan. `tests/t2-brand.mjs` (env `BRAND_SHOTS`, `BRAND_ONLY=text|quote|log|menu|flow|docs`) menguji sisa nama game asal di seluruh layar, kutipan loading, Yang baru dan toast, serta latar kolase.
## Aturan kerja ## Aturan kerja
- Jangan memakai `Math.random`/`Date.now` untuk logika yang memengaruhi hasil pertandingan bila ada pengacak `random()` bawaan (benih tetap). - Jangan memakai `Math.random`/`Date.now` untuk logika yang memengaruhi hasil pertandingan bila ada pengacak `random()` bawaan (benih tetap).

View File

@ -188,8 +188,8 @@ export default async ({ page, game, errors, characters }) => {
await wait(450); await shot('vs-arcade'); await game(() => window.__game.vsSkip()); await wait(450); await shot('vs-arcade'); await game(() => window.__game.vsSkip());
await finish('player', 2).then(() => null).catch(() => null); await finish('player', 2).then(() => null).catch(() => null);
await wait(100); await wait(100);
// setelah menang jeda 2,6 detik lalu lawan berikut (VS lagi) // setelah menang jeda 2,6 detik lalu lawan berikut (VS lagi); jam jeda mulai saat K.O. di dalam finish, jadi tunggu layarnya muncul (bukan tidur tetap)
await wait(2800); s = await vsState(); await page.waitForSelector('#vs-screen', { timeout: 6000 }).catch(() => null); s = await vsState();
ok('arcade: menang -> lawan 2 muncul dengan layar VS', s.el && /LAWAN 2 \/ 6/.test(await game(() => document.querySelector('#vs-screen .vs-top')?.textContent || '')), s); ok('arcade: menang -> lawan 2 muncul dengan layar VS', s.el && /LAWAN 2 \/ 6/.test(await game(() => document.querySelector('#vs-screen .vs-top')?.textContent || '')), s);
await game(() => window.__game.vsSkip()); await game(() => window.__game.vsSkip());
await finish('enemy'); await finish('enemy');