From a231d821ca43ce8fc84129d112c41769bd110c24 Mon Sep 17 00:00:00 2001 From: Brian Fertig Date: Sun, 7 Jun 2026 18:59:57 -0600 Subject: [PATCH] **feat: add Tri-Ominoes game with AI opponents** MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce Tri-Ominoes, a triangular grid tile-placement game for 2–4 players. The implementation includes a pure rules engine (`TriominoesLogic`), triangular grid geometry and data (`TriominoesData`), a Phaser scene (`TriominoesGame`), and a heuristic AI with 5 skill levels (`TriominoesAI`). Key features: - Corner-matching tile placement on an equilateral triangular grid - Scoring with pip sums, hexagon-closing bonuses, and going-out rewards - Draw-from-pool and pass mechanics with forced pass when blocked - Animated AI tile placement from opponent portraits - Board panning and re-centering for large play areas - Game-over modal with final scores and history posting Also updates the game registry, scene dispatch, opponent select skill controls, and adds two new character portraits (beth, blackwind). --- public/assets/images/game-icons.png | Bin 185829 -> 188888 bytes public/assets/images/game-icons.psd | Bin 492689 -> 500630 bytes public/assets/images/originals/beth.png | Bin 0 -> 1771083 bytes public/assets/images/originals/blackwind.png | Bin 0 -> 2003771 bytes public/src/games/triominoes/TriominoesAI.js | 45 ++ public/src/games/triominoes/TriominoesData.js | 97 +++ public/src/games/triominoes/TriominoesGame.js | 759 ++++++++++++++++++ .../src/games/triominoes/TriominoesLogic.js | 242 ++++++ public/src/main.js | 2 + public/src/scenes/GameRoomScene.js | 2 +- public/src/scenes/OpponentSelectScene.js | 2 +- server/games/registry.js | 1 + 12 files changed, 1148 insertions(+), 2 deletions(-) create mode 100644 public/assets/images/originals/beth.png create mode 100644 public/assets/images/originals/blackwind.png create mode 100644 public/src/games/triominoes/TriominoesAI.js create mode 100644 public/src/games/triominoes/TriominoesData.js create mode 100644 public/src/games/triominoes/TriominoesGame.js create mode 100644 public/src/games/triominoes/TriominoesLogic.js diff --git a/public/assets/images/game-icons.png b/public/assets/images/game-icons.png index 60c159714546e6842082f8878d34b0ce1f504d6a..56c1268a0eb83d2e240358d31341fd5be0c8bd4b 100644 GIT binary patch delta 28408 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