# BiTRIS – webes port > **English:** a faithful browser port of **BiTRIS 1.55** (1989–1991, Jan Egner & Leo Moll, YeaSoft), the > two-player Tetris for DOS. Plain HTML + JavaScript, no build step: open `index.html` or host the folder on any > static web server. The game runs on an emulated 80×25 text screen with the VGA font, the original timing, > the PC-speaker tune and the quirks of the Turbo Pascal source. Keys: left player `F` `G` `H` + `Tab`/`Space`, > right player `4` `5` `6` + `Enter`/`0`, `Esc` pauses, `Esc` `Esc` quits. Original source and license (MIT): > . A [YeaSoft/bitris](https://github.com/YeaSoft/bitris) repóban közzétett Turbo Pascal 5.5-ös forrás böngészőben futó, a lehető leghűbb átirata. Nem újraértelmezés: a `BITRIS.PAS` eljárásai egy az egyben kerültek át JavaScriptbe, és ugyanarra a 80×25-ös szöveges képernyőre rajzolnak, amit a DOS-os eredeti a `B800:0000` videómemóriában tartott. A menük, a súgó, a szerzői-jogi képernyő, a Top 100 és a játéktábla **karakterre és színattribútumra azonos** az eredetivel – ezt automatikus teszt ellenőrzi a DOSBoxban futó `BITRIS.EXE` képernyőképei ellen (lásd lent). ## Indítás - **Legegyszerűbb:** a mappában `npm start` (Windowson elég egy dupla kattintás a `serve.cmd`-re), aztán . Csak Node.js 20+ kell hozzá, más függőség nincs; a `tools/serve.js` egy apró statikus kiszolgáló. Kiírja a gép hálózati címét is (`http://192.168.x.x:8098`): ugyanazon a Wi-Fi-n a telefon vagy a tablet is ezt nyitja meg, így az érintő-vezérlők valódi eszközön próbálhatók. Leállítás: Ctrl-C (vagy az ablak bezárása). - Bármilyen más statikus kiszolgáló is jó (`python -m http.server 8098`, GitHub Pages, Cloudflare Pages…): nincs build, nincs szerveroldal, a mappa feltölthető úgy, ahogy van. - Fájlból (dupla kattintás az `index.html`-re) is elindul, de a kiszolgáló a biztos út: a böngészők a helyi fájlokat egyre szigorúbban kezelik, és telefonról csak hálózaton át érhető el. - Tesztek: `npm test` (Node 20+, csak a beépített `node:test`). A hanghoz a böngészőnek kell egy billentyűleütés vagy kattintás (ez böngésző-szabály; az `Esc` önmagában nem számít, de a következő gomb vagy kattintás már igen); a fejlécben ki is kapcsolható. A `4:3` gomb a korabeli monitor képarányát (720×400 → 4:3) és a négyzetes képpontokat váltja, a `Fullscreen` teljes képernyőt ad, a `Reset Top 100` a böngészőben mentett toplistát törli. ## Közzététel (Cloudflare Pages) A játék tisztán statikus (HTML, CSS, JS; a Top 100 a böngészőben marad), szerveroldal nem kell hozzá, a Cloudflare Pages ingyenes csomagja bőven elég. `npm run dist` a `dist/` mappába gyűjti, ami a kiszolgáláshoz kell (lap, stílus, szkriptek, licenc, ez a README), a tesztek, eszközök és képernyőképek nélkül. - **Wranglerrel** (Node van, mást nem kell telepíteni): egyszer `npx wrangler login` (böngészőben engedélyezed), aztán `npm run deploy` – összeállítja a `dist/`-et és feltölti a `bitris` nevű Pages-projektbe (első alkalommal rákérdez, hogy létrehozza-e). A cím `https://.pages.dev`, a projekt neve a `package.json` `deploy` sorában cserélhető. - **API-tokennel**, ha a böngészős bejelentkezés nem megy (víruskereső vagy tűzfal megfogja a `localhost:8976`-os visszahívást): az `env.example`-t másold `.env` néven, és írd bele a tokent (*Account / Cloudflare Pages / Edit* jogosultság) meg a fiókazonosítót. A Wrangler a mappa `.env` fájlját magától beolvassa; a `.env` nincs a gitben, és a `dist/`-be sem kerül. - **Kézzel**: a Cloudflare vezérlőpulton Workers & Pages → Create → Pages → Upload assets, és a `dist/` mappát húzod be. Build parancs és build-könyvtár nem kell. - **Git-kapcsolattal** (akár privát GitHub-repóból): Framework preset *None*, build command üres, build output directory `/`. Ekkor a teljes repó kerül ki (a `test/`, `tools/` és `docs/` is, ez csak pár száz KB). Saját domain a projekt *Custom domains* lapján adható hozzá. A `dist/_headers` a README-t és a licencet szövegként adja ki, hogy a böngésző megjelenítse, ne letöltse. ## A tribute-intró Betöltés után a gép „kikapcsolva” áll: egy sötét képernyő kér egy billentyűt vagy egy koppintást a képernyőre. Ez a bekapcsoló, és egyben ez adja meg a böngészőnek azt a felhasználói jelzést, ami nélkül a hangszóró nem szólalhat meg (böngésző-szabály; az `Esc`-et nem számítják, ezért azt a kapcsoló nem fogadja el). Utána a játék elé egy rövid, a nyolcvanas évek végi PC-intrók stílusában készült bevezető kerül ([js/demo.js](js/demo.js)): memória-számláló és DOS-prompt, csillagmező, a `BITRIS.TXT` élén álló YEAsoft- logó egy végigfutó fényes csíkkal, írógépen pötyögött ajánlás a szerzőknek és a kollégiumi (SCH 1407) BiTRIS-partik emlékére, futószöveg a sor alján, közben az eredeti dallam **kánonban**: mintha a szoba két gépén futna a játék, a második két és fél ütemmel (tíz negyeddel, 4,4 másodperccel) később lép be, a két gép a sztereóképben balra és jobbra (a játékban magában egyetlen hangszóró szól, ahogy az eredetiben). Ugyanazon a 80×25-ös szöveges képernyőn fut, mint a játék, 18,2 képkocka/mp-vel (az időzítő-megszakítás üteme). **Bármely billentyű átugorja**; fél perc után magától továbbmegy, és az eredeti `LeoClrScr` spirál-törléssel adja át a helyet a főmenünek. Csak az oldal betöltésekor játszódik le: a játékból kilépve az újraindítás egyenesen a főmenübe visz. `?nointro` nélküle indít (ez a címsorban marad, újratöltéskor is érvényes); a fejléc `Intro` gombja újra lejátssza, és ki is veszi a `nointro`-t a címből. ## Billentyűk és beállítások | | bal játékos | jobb játékos | | --- | --- | --- | | balra | `F` | `4` (számbillentyűzeten is) | | forgatás | `G` | `5` | | jobbra | `H` | `6` | | ejtés | `Tab` vagy `Szóköz` | `Enter` vagy `0` | `Esc` szünet, szünetben `Esc` kilép a menübe. A főmenü az eredeti: `M` zene, `S` elválasztó, `R` véletlen kockák, `L` kezdőszint (0–400), `G` szemétszint (0–15), `H` súgó, `T` Top 100, `C` szerzői jogok, `P` vagy `Enter` játék, `Esc` kilépés („Hope to see you again soon…”, bármely billentyű újraindít). **Telefonon, tableten** (durva mutatóeszköz vagy mobil böngésző esetén magától, különben a fejléc `Pad` gombjával vagy `?touch=1`-gyel) a két alsó sarokban egy-egy kis vezérlő jelenik meg: bal oldalt a bal játékosé (◄ ↻ ► és ejtés), jobb oldalt a jobb játékosé. A bal vezérlő tetején `ESC` és egy ⌨ gomb, ami a készülék billentyűzetét hozza elő a menü betűihez, a szintbeíráshoz és a nevekhez; a jobb vezérlő tetején `ENTER` (játék indítása, megerősítés). A nyomva tartott irány úgy ismétel, mint a billentyűzeten (fél másodperc után 10,9/mp); forgatás és ejtés érintésenként egyet lép. Fekvő tájolás és teljes képernyő ajánlott ([js/touch.js](js/touch.js)). Az eredeti parancssori kapcsolók URL-paraméterként élnek tovább: `?L=300` kezdőszint, `?G=5` szemét, `?M=OFF` zene nélkül, `?PL=Leo_Moll&PR=Jan_Egner` alapértelmezett nevek a toplistához (aláhúzás = szóköz), `?NOCOLOR` a monokróm színkészlet. ## Mi van benne ``` index.html, style.css a lap: vászon 4:3-ban, gombok, billentyű-táblázat js/kernel.js a „DOS”: virtuális óra, Delay/ReadKey generátorokkal, BIOS billentyűpuffer (15), 18,2 Hz-es időzítő-megszakítás (INT 1Ch), PC-speaker port js/crt.js 80×25 szöveges videómemória + a Turbo Pascal CRT (Write ablakkal, görgetéssel, GotoXY, ClrScr, TextColor) és a YEAIO rajzoló eljárásai (WriteAT, Box, NormBox) js/game.js BITRIS.PAS sorról sorra: PaintBrick, CheckBrick, KillLine, AddQuad, Main, menük, súgó, Top 100, névbekérés (YEAIO Get/NumGet/GetYN) js/demo.js a tribute-intró (POST, csillagmező, logó, írógép, scroller, zene) js/muz.js a MUZAK unit: bájtkódos dallam-értelmező az időzítő-megszakításból js/muzdata.js az eredeti BITRIS.MUZ (2643 bájt) base64-ben js/hiscore.js, js/seed.js Top 100 a localStorage-ban; induláskor az 1.55-tel szállított BITRIS.TTL nyolc bejegyzése (Leo Moll / Jan Egner 1992, …) js/pas.js Pascal-segédek (Strg, StrZ, SNorm, Val) és a Turbo Pascal 5.5 Random js/cp437.js, js/font.js CP437 ↔ Unicode, VGA 8×16 betűkészlet js/render.js vászon-rajzoló: 9×16-os cellák, 16 szín, villogó attribútum, villogó kurzor, egész számú elő-nagyítás + bilineáris (DOSBox „sharp bilinear”) js/audio.js PC-speaker: egy négyszögjel, PIT-osztóra kerekített frekvenciával js/input.js billentyűzet → BIOS-kód, saját typematic ismétlés (500 ms, 10,9/s) test/ node:test: CRT, zene, menü, játékmenet, toplista + képernyő-összevetés tools/ capture_reference.py (DOSBox referenciaképek), ttl_decode.py, font_from_dosbox.py, smoke.js (fej nélküli végigjátszás), snapshot.js (PNG képernyőképek Node-ból) docs/ képernyőképek (snapshot.js készíti) ``` ### Hogyan fut az eredeti egyenes vonalú kód böngészőben Az eredeti program `Delay()`-ben és `ReadKey`-ben blokkol. Itt minden ilyen eljárás generátor: `yield 4` a `Delay(4)`, `yield KEY` a `ReadKey`. A `kernel` egy virtuális órához képest hajtja őket: az óra csak várakozás közben halad, ezért az időzítés független a gép sebességétől, és a 4 ms-os főciklus, a `(450-Level) SHR 1` számláló, a 42 ms-os sorkitörlés-szünet vagy az 1 ms-es lépésű GAME OVER hangcsúszás pontosan az eredeti. Fej nélkül (Node) ugyanez a motor fut a tesztekben, képernyő és hang nélkül. ### Hűség-ellenőrzés `tools/capture_reference.py` a DOSBox Staging REST API-ján át végigjárja az eredeti `BITRIS.EXE` menüit (a billentyűket a BIOS-pufferbe írja), és 14 képernyő 4000 bájtos videómemória-képét menti a `test/fixtures/` alá. A `test/fixtures.test.js` ugyanazokat a billentyűket adja a portnak, és cellánként összeveti a karaktert és az attribútumot: főmenü, négy súgóoldal, billentyűtérkép, szerzői jogok, Top 100 három oldala, játéktábla (a véletlen tartalmú játékmező kitakarva), szünet-ablak. Mind a 14 egyezik. ## Mi tér el szándékosan - **Dátum a Top 100-ban:** az eredeti `Year-1900`-at ír két jegyre, ami 2000 után három jegy lenne és csonkolódna; itt az évszám utolsó két jegye jelenik meg. Minden más formátum (`DD.MM.YY HH.MM`) az eredeti. - **Toplista-fájl:** `BITRIS.TTL` helyett `localStorage` (kulcs `bitris.ttl`, JSON). Az induló lista a kiadással szállított fájl tartalma, a `tools/ttl_decode.py`-jal visszafejtve. - **Billentyűzet-LED-ek:** a nyitó ablak alatt az eredeti a NumLock/CapsLock/ScrollLock LED-eket villogtatja a három hanggal együtt; böngészőből nem lehet. A NumLock-ot a játék bekapcsolná – itt a számbillentyűzet mindig számjegyet ad. - **Sebesség-csalás-figyelő:** a `TestDelay`/„PUNISHING_MODE” (processzor-órajel-váltás elleni védelem) és a hozzá tartozó szidó képernyő értelmetlen, kimaradt; a `Delay(42)` szünet, amit mérésre használt, megmaradt. - **Monokróm:** a `/NOCOLOR` színkészlet megvan (`?NOCOLOR`), de MDA-kártyát nem emulálunk, színes képernyőn jelenik meg. - **Rejtett tab:** ha a lap háttérbe kerül, a játék áll (a böngésző nem ad képkockát), nem ugrik előre. Ami **nem** lett „kijavítva”, mert az eredeti így viselkedik: a játék akkor ér véget, ha **mindkét** játékos felért; a kieséskor a frissen érkező kocka a törlő lépése miatt lyukat üthet a másik torony tetejébe; az elválasztó sortörléskor lejjebb csúszik; a `NormBox` keretének bal oldala dupla, a jobb szimpla vonal; az `Esc` a szintbekérésben 0-ra állítja a kezdőszintet; a Top 100 századik sora `00`-ként sorszámozódik. Ha jól szórakozol vele: [Buy me a coffee](https://buymeacoffee.com/hilluter) ☕ ## Betűkészlet, zene, licenc - A kód MIT (lásd `LICENSE`), az eredeti játék szintén MIT a YeaSoft repóban; a játékbeli szövegek, a dallam és a toplista az eredeti kiadásból valók. - A 8×16-os glifek az IBM VGA szöveges módjának betűkészlete, a DOSBox Staging 0.83 emulált videó-BIOS-ából kiolvasva (`tools/font_from_dosbox.py`); ugyanazt látod, mint az emulátorban. Ha más forrásból származó készletet szeretnél (például VileR *Ultimate Oldschool PC Font Pack*-jének `Px437 IBM VGA 8x16`-ját, CC BY-SA 4.0), a `js/font.js` 4096 bájtos bittérképe cserélhető. - `BITRIS.MUZ`: a MUZCOMP-pal fordított dallam, benne a Leo Moll-féle utasításkészlet (ismétlés, ugrás, regiszterek, sebesség). A hangjegyek frekvenciáit a MUZAK unit táblázata adja; a `b` a német jelölés szerint B-t (azaz b-moll hangot, 11-es hangjegyet) jelent, ahogy a forrásban is.