gitea-master
John Montagu, the 4th Earl of Sandvich 2026-04-13 15:18:18 -07:00
parent a6712d6a67
commit f313527b20
Signed by: sandvich
GPG Key ID: 9A39BE37E602B22D
2 changed files with 283 additions and 0 deletions

184
as9/AGENTS.md 100644
View File

@ -0,0 +1,184 @@
# as9-island-dominion Architecture
## Project Identity
- Directory: `as9`
- CMake project name: `as9-island-dominion`
- Executable target name: `as9-island-dominion`
- Game name: `Island Dominion`
## High-Level Structure
The project is split into five main areas:
- `src/ecs/`: the homegrown ECS, following the storage and lookup patterns from `as8`
- `src/components/`: plain data components used by the ECS
- `src/systems/`: free-function systems that execute in a fixed order from `main`
- `src/game/`: authoritative game-state structs and pure rules code
- `src/net/`: ASIO TCP networking and protocol serialization
## ECS Conventions
The ECS should stay very close to `as8`.
- `Entity` is a numeric ID type (`size_t`)
- Component type IDs come from a single global component counter in a `.cpp` file
- Each component type uses sparse-set style storage with:
- `data`
- `packed_entities`
- `sparse_indices`
- The central registry owns all component storages via a vector of base pointers, like `Context` in `as8`
- Systems are free functions, not inheritance-heavy classes
- Main owns the registry and executes systems explicitly in order each frame
`as8` did not need entity destruction, but this game does. `as9` should preserve the same sparse-set design while adding safe entity destruction and component removal for unit and fortress elimination.
## Game State Split
Two representations exist on purpose:
- ECS state: runtime entities used for rendering, selection, and UI interactions
- `GameState`: plain serializable structs used for rules, host authority, and network snapshots
Authoritative rules should operate on `GameState`, not directly on ECS entities. ECS entities are rebuilt or synchronized from snapshots/state transitions as needed.
## Authoritative Networking Model
- The host is always player 1
- The client is always player 2
- Both players run the same executable
- The host owns the authoritative `GameState`
- The client never mutates the game directly; it sends intents to the host
- After every accepted state change, the host sends a fresh `GAME_STATE` snapshot to the client
This keeps validation and turn order in one place and avoids divergence between peers.
## Networking Responsibilities
`NetworkManager` owns:
- the ASIO `io_context`
- host accept/connect logic
- async TCP read/write queues
- decoded inbound message queues for the game layer
- disconnect detection and recovery to the startup screen
Protocol messages should stay small and explicit:
- `CONNECT_REQUEST`
- `CONNECT_ACK`
- `GAME_STATE`
- `ACTION_REQUEST`
- `COMBAT_CHOICE`
- `GAME_OVER`
TCP framing should use one consistent format throughout the project. A small length-prefixed binary format is preferred so snapshots remain predictable and easy to parse.
## Privacy Rules
Hands are private information.
- A local player may always know their own hand
- A received remote snapshot must not expose the opponent's hand contents
- Public state still includes hand size, discard size, deck size, area control, units, fortresses, turn state, and combat state
## Combat Flow
Combat is blocking.
- A move into an enemy-occupied area starts combat immediately
- No other actions are processed until the current combat resolves
- The host waits until both players have submitted a `COMBAT_CHOICE`
- After both choices arrive, the host resolves one combat round
- If both sides still have units, the host requests another round
- When combat ends, the host checks fortress capture/removal and win conditions, then broadcasts the updated snapshot
## Rules Ownership
`GameRules` should provide pure functions for:
- board adjacency checks
- area controller calculation
- resource collection and cap enforcement
- action validation
- action application
- combat round resolution
- fortress capture/removal logic
- win-condition checks
Pure rules code keeps the host logic testable and makes snapshot synchronization simpler.
## Rendering and UI Ownership
- `RenderSystem` draws the board, areas, units, fortresses, and highlights using raylib-cpp types
- `UISystem` draws the startup screen, HUD, combat overlay, disconnect notices, and game-over screen
- `InputSystem` translates local mouse/keyboard input into high-level actions or combat choices
The local host can apply validated local actions directly through the host game-logic path. The client instead packages equivalent intents into `ACTION_REQUEST` or `COMBAT_CHOICE` messages.
## Frame Update Order
Each frame should follow a stable order:
1. Pump network events and decode inbound messages
2. Update local input and build pending local intents
3. Apply host-side game logic if this instance is authoritative
4. Update ECS/view state from the latest authoritative snapshot
5. Draw world and UI
This order keeps render state consistent with the latest confirmed game state.
## Build and Library Layout
- Root build file: `as9/CMakeLists.txt`
- Raylib wrapper comes from `../raylib-cpp` following the `as6` pattern
- ASIO lives in `as9/lib/asio`
- Include path should be `lib/asio/asio/include`
- Compile definitions should include:
- `ASIO_STANDALONE`
- `ASIO_NO_DEPRECATED`
Platform link requirements:
- Linux: `pthread`
- Windows: `ws2_32` and `mswsock`
## Initial Source Layout
Planned layout:
- `src/ecs/Entity.hpp`
- `src/ecs/ComponentStorage.hpp`
- `src/ecs/Registry.hpp`
- `src/ecs/System.hpp`
- `src/components/TransformComponent.hpp`
- `src/components/RenderComponent.hpp`
- `src/components/UnitComponent.hpp`
- `src/components/FortressComponent.hpp`
- `src/components/AreaComponent.hpp`
- `src/components/PlayerComponent.hpp`
- `src/components/CardComponent.hpp`
- `src/components/NetworkComponent.hpp`
- `src/systems/RenderSystem.hpp/.cpp`
- `src/systems/InputSystem.hpp/.cpp`
- `src/systems/NetworkSystem.hpp/.cpp`
- `src/systems/GameLogicSystem.hpp/.cpp`
- `src/systems/CombatSystem.hpp/.cpp`
- `src/systems/UISystem.hpp/.cpp`
- `src/game/GameState.hpp`
- `src/game/GameRules.hpp/.cpp`
- `src/game/CardDeck.hpp/.cpp`
- `src/net/Protocol.hpp`
- `src/net/NetworkManager.hpp/.cpp`
- `src/main.cpp`
## Implementation Priorities
Build the project in this order:
1. CMake and third-party wiring
2. ECS infrastructure split from the `as8` pattern
3. Serializable game state and rules
4. Networking protocol and manager
5. UI flow for startup, match, combat, disconnect, and game over
6. Rendering polish and interaction cleanup

99
as9/GAME_DESIGN.md 100644
View File

@ -0,0 +1,99 @@
# Codex Prompt: Island Dominion
## Project Overview
**Name:** Island Dominion
**Type:** 2-player competitive strategy game (no AI opponent — human vs human over the network)
**Renderer:** raylib-cpp (C++ wrapper for raylib — prefer raylib-cpp types and methods over raw raylib where available)
**Networking:** ASIO (standalone, header-only, no Boost)
**Architecture:** ECS (homegrown, modelled after as8)
**Build system:** CMake (modelled after as6)
**Language:** C++17 or later
---
## Game Design
### Objective
Win by being the first player to control 9 of the 16 areas on a 4×4 grid, **or** by eliminating all of the opponent's units and fortresses.
### Board
- 4×4 grid of areas (16 total).
- Each area can hold any number of units from one or both players, and at most one fortress.
- An area is **controlled** by a player if:
- They are the only player with units there, **OR**
- There are no units in the area but they have a fortress there.
- If both players have units in the same area, the area is **contested** (no controller).
### Resources
- Single resource type (integer). No resource types — just a count per player.
- Each player starts with **8 resources**.
- At the **start of each turn**, the active player gains **1 resource per area they currently control**, capped at 20 total.
### Units
Three unit tiers:
| Type | Power | Build Cost |
|--------|-------|-----------|
| Light | 1 | 1 |
| Normal | 2 | 2 |
| Heavy | 3 | 3 |
### Fortresses
- Build cost: **3 resources**.
- Only one fortress per area.
- Provides area control when no units are present.
- A fortress is **captured (removed)** when the opposing player wins combat in that area.
- A tie in combat does **not** remove the area's fortress.
### Cards
- Shared deck, shuffled at game start.
- Card distribution: **eight +1 Power**, **five +2 Power**, **three +3 Power** cards.
- Each player draws **1 card at the start of their turn** (after collecting resources).
- Each player starts with **3 cards** dealt from the deck.
- Cards are played during combat (see below). Played cards are discarded.
- Cards are private information — opponents do not see your hand.
### Turn Structure
Each turn:
1. **Collect resources** (controlled areas → +1 res each, cap 20).
2. **Draw a card** (1 from top of deck).
3. **Take 2 actions** (any combination, same action can be repeated):
- **Move a unit** — move one of your units to an adjacent area (orthogonally adjacent). If the destination contains enemy units, **combat is triggered immediately** and the move action ends (combat resolution happens before the next action).
- **Build a unit** — spend resources to place a new unit in any area you control.
- **Build a fortress** — spend 3 resources to place a fortress in any area you control that does not already have a fortress.
- **Pass** — do nothing, consuming one action.
4. **End turn** — control passes to the opponent.
### Combat System
Combat occurs when a player moves a unit into an area containing enemy units.
**Combat round (repeat until one side has no units):**
1. Both players **secretly choose**:
- One of their units in the area to fight.
- A number of resources to spend (0 to min(their resources, 3)).
- Optionally, one card from their hand to play.
2. **Simultaneous reveal** — both players' choices are shown at the same time.
3. **Calculate Power:**
`Power = Unit tier + Resources spent + Card bonus (if played)`
4. **Resolve:**
- Higher power → opponent's chosen unit is destroyed.
- Tie → both chosen units are destroyed.
5. **Resources are spent** (deducted from both players) and **cards are discarded**.
6. If both sides still have units, repeat from step 1.
**After combat ends:**
- If one player has units remaining and the other does not:
- The winner controls the area.
- If the loser had a fortress there, it is removed.
- If both sides lost all units (series of ties): the area reverts to fortress control (if any), otherwise uncontrolled.
### Win Condition (checked after every action and after every combat)
- First player to control **9 or more areas** wins.
- If a player has **zero units AND zero fortresses** on the board, they lose immediately.