Skip to content

About

Multiplayer-first terminal territorial strategy game built with OpenTUI, TypeScript, and Bun

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

conquest.sh

Multiplayer terminal Risk-style strategy game — play in your terminal, self-host in minutes.

CI License: MIT Bun 1.4.2 TypeScript OpenTUI Docker Protocol PRs Welcome

conquest.sh – active battle on Earth — Global Front


Feature Status

Feature Status
Multiplayer rooms (public & unlisted, join by code) ✅
Reconnect / session resume ✅
Earth-42 canonical world map (42 territories, 6 continents) ✅
Deploy / Attack / Fortify / Conquest moves ✅
Battle report panel (dice, losses, engagement totals) ✅
In-game event log & chat ✅
Rematches ✅
Turn timers & disconnect-forfeit ✅
Self-hosting (Docker Compose or standalone Bun) ✅
Risk cards ✅
Diplomacy 🚧
Dedicated chat view / DMs 🚧
Standard AI bots and Solo Practice ✅
Spectators 🚧
Persistent rooms / replays 🚧

Screenshots

Gallery

Home screen Home screen

Lobby — players and ready states Lobby

Active match — Earth-42, wide layout Ingame wide

Battle report panel after an attack Battle panel

Compact layout (small terminal) Compact layout

Match results screen Match results


Quickstart

Prerequisites

  • Bun (pinned to 1.4.2 via .bun-version)

1. Install Dependencies

bun install --frozen-lockfile

2. Start a Local Server

./conquest-server.sh

The server listens on port 4000 by default.

3. Connect a Client

./conquest.sh

Arrives at the multiplayer home screen. To skip the front door:

# Join an existing room by code
./conquest.sh --room ABCD --name "YourName"

# Connect to a remote server
./conquest.sh --server wss://conquest.example.com --room ABCD

Play with Bots

Choose Create Game, set Maximum Players to the total number of seats, then adjust Bot Seats. Bot seats count toward the room total, with at least one human seat reserved for the host. Choose Solo Practice with Ctrl+P to set an unlisted two-seat room with one bot. Create the room and mark yourself Ready to start.

4. Verify the Test Suite

bun run check

Runs the full test suite (game rules, map geometry, UI components, server networking, client reconnection) followed by TypeScript verification.


Self-Hosting

Option A: Docker Compose (Recommended)

docker compose up -d
docker compose logs -f
./conquest.sh --server localhost:4000

Data persists to the named conquest-data Docker volume (/data/conquest.sqlite).

Option B: Standalone Bun Server

./conquest-server.sh --port 4000 --name "My Battle Realm"

Configuration

CLI flags take precedence over environment variables.

CLI Flag Environment Variable Default Description
-p, --port CONQUEST_PORT 4000 Port to bind HTTP & WebSocket server
-n, --name CONQUEST_SERVER_NAME conquest.sh-server Server name shown in lobby and browser
-m, --map CONQUEST_MAP earth-42 Default map. Earth-42 is the only supported map before version 1.0.
-d, --db CONQUEST_DB_PATH :memory: SQLite session database path
--max-players CONQUEST_MAX_PLAYERS 4 Default max players per room
--max-rooms CONQUEST_MAX_ROOMS 500 Max concurrent rooms; create_room returns SERVER_FULL beyond this
--disconnect-grace CONQUEST_DISCONNECT_GRACE_MS 60000 Grace period (ms) before a disconnected active player's turn is auto-forfeited (0 = disabled)
--turn-timeout CONQUEST_TURN_TIMEOUT_MS 0 Per-turn time limit (ms); 0 = no limit. Expired turns are forfeited as timeout. Clients receive turnDeadlineAt for countdown display.
--abandon-timeout CONQUEST_ABANDON_TIMEOUT_MS 600000 ms before an active room with all players disconnected is removed (default 10 min)

Client server address resolution order: --server <host> → CONQUEST_SERVER env → localhost:4000.


Controls

Mouse

Action Effect
Click owned territory Select as deployment / attack source
Click adjacent enemy Set as attack target
Click friendly territory (connected) Set as fortify destination
Click [ Deploy ] Commit pending deployment
Click [ Attack ] Execute attack
Click [ Fortify ] Move troops to connected territory
Click [ Skip / End Turn ] Open phase-skip confirmation
Hover Preview territory intel, owner, and garrison

Keyboard

Key Action
Arrow Keys Spatial 2D navigation by territory centroid geometry
Tab / Shift+Tab Cycle selection across territories
N / Shift+N Cycle legal attack or fortify targets
[ / ] Decrease / increase deployment count
0 Set deployment count to one
D Deploy the chosen amount to the selected territory
A Attack targeted enemy territory
Left / Right, then Enter Choose and confirm troop move after conquest
F Fortify troops between connected friendly territories
E Skip attack phase or end turn (opens confirmation)
Enter Confirm armed action
Esc Cancel / clear selection
R Toggle ready in lobby
C Open in-game chat
Q Quit or return to previous screen
1–5 Switch bottom tabs (Map / Cards / Diplomacy / Chat / Help)
2 Open / close the Cards panel

Architecture

See docs/ARCHITECTURE.md for detailed technical specifications, the delta protocol, state-projection design, and map platform API.

Key design points:

  • Server-authoritative: Clients emit typed intents; the server validates, executes, and broadcasts events plus per-player projected state deltas (protocol v0.5.0).
  • Delta protocol: Each player receives only the fields of GameState relevant to their view. Unresolvable gaps trigger a full client:resync.
  • Seeded sfc32 RNG: Each match draws a fresh 16-byte seed from the OS CSPRNG. The seed drives territory shuffles and all dice rolls and stays server-only; clients never see it.
  • Responsive TUI: Three layout modes — wide (≥ 180 cols × 51 rows), standard, and compact — driven by OpenTUI (@opentui/core + @opentui/react).
  • Map platform: Logical topology is separate from terminal render variants. Earth-42 ships six render profiles (compact through ultra); maps are registered bundles.

Note

Persistence model: Client session tokens and player associations persist to SQLite. Active game state is maintained in server memory. Client disconnects and terminal restarts reconnect seamlessly, but ongoing games do not survive a full server process restart.


Adding a Map

Earth-42 is the only supported map before version 1.0. Additional playable maps are deferred until after that release. When map development resumes, define stable semantic territory IDs, names, regions, bonuses, and bidirectional adjacency; add authored render variants for useful terminal sizes; register the bundle in packages/map-engine; and test topology, geometry, and non-land routes.

See docs/ARCHITECTURE.md § 5 for the full API boundary.


Cards

When a room is created with Cards: Escalating mode, a standard territory deck (one card per territory, plus two wilds) is shuffled at match start.

Earning cards: A player who conquers at least one territory during their turn receives one card at the end of that turn (drawn face-down, hidden from other players).

Trading sets: Three-of-a-kind (Infantry / Cavalry / Artillery) or one of each count as a valid set. Wilds substitute for any symbol. Trading a set earns armies on an escalating schedule: 4 → 6 → 8 → 10 → 12 → 15, then +5 each trade thereafter. If either traded card matches a territory you own, you receive a +2 territory bonus on that territory.

Forced trades: A player who holds 5 or more cards at the start of their deployment phase, or who ends an elimination and captures cards bringing their hand to 6 or more, must trade immediately before proceeding. The earned armies are placed during the normal deployment step (or immediately if the forced trade occurs during the attack phase). Attacks and phase-skips are blocked until all forced-trade armies are deployed.

Options: Set cardMode to "escalating" (default when cards are enabled) or "off" when creating a room. The mode is shown in the room browser and carried through the full client → server path.


Roadmap

  • Diplomacy — in-game messaging, non-aggression pacts
  • Dedicated chat view / DMs
  • Spectator mode
  • Persistent rooms & replays

Contributing

See CONTRIBUTING.md for setup, test conventions, and the branch/PR flow.

Join the conquest.sh Discord to find players and share feedback. You can also open the invite from the client’s main menu with D.

Security

See SECURITY.md for responsible disclosure instructions.

License

MIT — see LICENSE.

About

Multiplayer-first terminal territorial strategy game built with OpenTUI, TypeScript, and Bun

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages