Karetní hra · Přispěvatelka

Bang!
Online

Digitalizace klasické westernové karetní hry. 8 commitů na herní logice a kartách hrdinů v TypeScript monorepu s tRPC a WebSockety.

Bang! Online je digitální verze klasické westernové karetní hry. TypeScript monorepo s end-to-end type safety (klient importuje tRPC AppRouter přímo ze serveru), real-time herní stav přes WebSocket subscriptions. Work in progress, deploy konfigurovaný pro Railway.

Moje role byla Přispěvatelka — 8 commitů za jeden týden intenzivního vývoje (18.–25. 2. 2026), zaměřených na herní mechaniku, karty hrdinů a UI synchronizaci s herním stavem. Celkem net +2 780 řádků kódu.

Role Přispěvatelka (8 commitů)
Typ Karetní hra · WIP
Období Únor 2026
Technologie
TypeScript React 19 Vite 6 tRPC v11 WebSocket subscriptions Drizzle ORM better-sqlite3 pnpm workspaces Railway deploy

Monorepo se třemi balíčky: shared (čistý funkcionální game engine + card registry bez build kroku), server (tRPC + HTTP + WebSocket, in-memory GameManager) a client (React 19 SPA přes Vite, @trpc/react-query, inline styling bez CSS souborů).

Engine je čistá funkce bez vedlejších efektů — každá akce vrací nový state. To umožňuje deterministickou synchronizaci přes WebSocket a snadné testování. Karty jsou registry s objekty canPlay + execute pro každý typ.

Všech 8 mých commitů obsahuje změny v shared/src/game-engine.ts — netto +1 038 řádků. Co jsem přidávala:

  • Šerif hraje první — oprava pořadí kola, šerif nesmí být přeskočen.
  • Session persistence — když hráč obnoví stránku, dohraje od místa, kde přestal. currentPlayerIndex opraven, aby seděl po rejoin.
  • Simultánní reakce — karty Indians a Gatling stříkají na všechny hráče najednou. Implementace fronty paralelních reakcí (každý hráč musí odpovědět Bangem nebo Missed!).
  • Multi-reaction continuation po schopnostech — když uprostřed simultaneous reakce hráč zemře a aktivuje schopnost (El Gringo, Bart Cassidy), reakční fronta musí pokračovat, ne resetovat.
  • Manual checks pro dynamite a jail — losovací mechaniky (dynamit vybuchne na ♠2–9), kde hráč musí potvrdit výsledek. Nelze auto-resolve, protože pravidla povolují schopnosti měnit kartu.
  • Beer save — pokud hráč obdrží smrtelné poškození, může zahrát Beer a vrátit se na 1 life. Engine zachytí beer_save fázi a počká na rozhodnutí.
  • Manual barrel / Jourdonnais — některé schopnosti vyžadují potvrzení (chceš použít barel?), nepřebíjí se automaticky.

shared/src/card-registry.ts — registry akčních karet a schopností hrdinů. Konkrétně jsem přidávala:

  • El Gringo — když mu někdo dá poškození, ukradne mu kartu z ruky.
  • Bart Cassidy — pokaždé když dostane poškození, líže kartu.
  • Black Jack — když lízne ♥ nebo ♦, lízne další kartu.
  • Jourdonnais — má virtuální barel pro Bang reakci.
  • Vulture Sam — když hráč zemře, Sam si vezme jeho karty (s debug loggingem pro edge case).
  • Bandit kill reward — šerif zabije zločince a líže 3 karty (i během simultaneous reakce z Indians/Gatling).
  • Dynamit / vězení — losovací karty s vlastním turn flow.
  • Beer save logika — pivo jako záchrana před smrtí.

client/src/components/Game.tsx jsem upravovala ve všech 8 commitech, největší změna v 014d400 (+890 řádků) — UI pro beer save, manual barrel/Jourdonnais, winner display se jmény hráčů místo jen rolí.

  • Session persistence v localStorage — jméno hráče a session token přežijí refresh, nemusíš se znovu připojovat.
  • Discard pile display v Board.tsx — vidíš poslední odhozenou kartu.
  • Weapon range visibility — kdo na koho dosáhne výstřelem.
  • Reaction prompt s plnými hodnotami — tlačítka pro reakce ukazují suit a value, ne jen typ karty.
  • Eliminated player display — vidíš, kdo padl a v jaké roli.
  • Card highlighting s 3 s timeoutem — nově lízlá karta blikne, ale po 3 vteřinách zmizí (fix: po opakovaných úpravách se highlight nemazal).
  • Error display — chyby z engine jdou do alertů, ne jen do konzole.
  • Autofocus v Lobby — input pro jméno hráče je rovnou aktivní.

Stav uprostřed kaskády reakcí.

Indians/Gatling spustí frontu paralelních reakcí. Když jeden hráč v reakci zemře a tím aktivuje schopnost (El Gringo, Bart), engine musí pamatovat, kde v reakční frontě byl a po vyřešení schopnosti pokračovat. Bez AbilityReturnContext v typech by se hra zasekla nebo přeskočila tah.

Manual vs. automatic resolution.

Některé karty (dynamit, vězení, barel) jsou losovací — engine ví výsledek z balíčku, ale pravidla povolují schopnosti změnit kartu, takže výsledek musí potvrdit hráč. Nemůžu jen auto-resolve; engine přechází do manual_check fáze a čeká.

Rozšiřování type modelu bez breaking changes.

Game state je sdílený mezi serverem a klientem přes type import. Každá nová fáze (beer_save, manual checks, multi-reaction info) rozšiřuje union typy — musí to projít TS check na obou stranách a klient musí render umět zpracovat neznámou fázi.

Real-time sync přes tRPC subscriptions.

WebSocket subscription posílá nový state po každé akci. Server je in-memory (žádná DB), takže každý event musí být deterministický a pořadí akcí v GameManager bez race conditions.

Z git logu autora oschwubova@gmail.com:

8 commitů za 8 dní
+2 780 net řádků (3 307 / −527)
8/8 commitů v game engine
6/8 commitů v card registry
5 karet hrdinů implementováno
3 balíčky monorepa (shared / server / client)