wip 2
parent
a6712d6a67
commit
f313527b20
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
Loading…
Reference in New Issue