189 lines
7.0 KiB
Markdown
189 lines
7.0 KiB
Markdown
# Rats with Gats Remote Play (`pirats`)
|
||
|
||
A web-based remote play companion app for the tabletop roleplaying game **Rats with Gats** (where players roleplay as gunslinging pirate rats, or "Pi-Rats", in the magical land of Yeld). The application manages lobbies, character creation, card mechanics, scene phases, obstacles, challenges, and player voting. See [RULEBOOK.md](RULEBOOK.md) for the game rules.
|
||
|
||
It is built with a **FastAPI** + **SQLModel** (SQLite) backend and a **Svelte 5** single-page frontend (in `frontend/`), which polls the backend's JSON state endpoint for near-real-time updates.
|
||
|
||
---
|
||
|
||
## Features
|
||
|
||
- **Game Lobby:** Create games and join as players via a unique game ID.
|
||
- **Character Creation:**
|
||
- Fill out the character profile (appearance, smell, catchphrase).
|
||
- Delegate custom "Like/Hate" relationship questionnaire cards to other crewmates (answering them for each other!).
|
||
- Draft three "Secret Pirate Techniques" which are automatically shuffled and swapped among players.
|
||
- Bind swapped techniques to Face Cards (Jack, Queen, King) for play.
|
||
- **Dynamic Card Mechanics:**
|
||
- Automated 54-card deck shuffling and card drawing.
|
||
- Automatically matches card suits to thematic obstacles (Clubs for combat, Spades for stealth/cunning, Hearts for social/morale, Diamonds for nautical/athletics).
|
||
- **Scene Management:**
|
||
- Assign roles (Pi-Rats or "The Deep" narrator).
|
||
- Dynamic challenge creation linking multiple active obstacles.
|
||
- Automatically handles card matching colors/values, automatic success when playing Face Card techniques, and Joker card triggers to discard/replace obstacles.
|
||
- **Between-Scenes Voting:**
|
||
- Vote on crewmates to rank up.
|
||
- Toggle personal objectives (Get a Gat, Earn a Name, Die like a Pirate).
|
||
|
||
---
|
||
|
||
## Installation & Running
|
||
|
||
This project supports standard Python package tools as well as Nix flakes.
|
||
|
||
### Option 1: Standard Python Installation
|
||
|
||
#### Prerequisites
|
||
- Python >= 3.9
|
||
- Virtual environment tool (optional but recommended)
|
||
|
||
#### 1. Setup Virtual Environment (Optional)
|
||
```bash
|
||
python -m venv .venv
|
||
source .venv/bin/activate
|
||
```
|
||
|
||
#### 2. Install Package
|
||
Install the package and its dependencies in editable mode:
|
||
```bash
|
||
pip install -e .
|
||
```
|
||
|
||
#### 3. Run the App
|
||
Launch the FastAPI server using the installed package entrypoint:
|
||
```bash
|
||
pirats --host 0.0.0.0 --port 8000 --reload
|
||
```
|
||
Alternatively, run it with `uvicorn`:
|
||
```bash
|
||
uvicorn pirats.main:app --host 0.0.0.0 --port 8000 --reload
|
||
```
|
||
|
||
Once running, access the web UI at [http://localhost:8000](http://localhost:8000).
|
||
|
||
#### Configuration (environment variables)
|
||
|
||
| Variable | Default | Purpose |
|
||
| --- | --- | --- |
|
||
| `DATABASE_URL` | `sqlite:///./rats_with_gats.db` | SQLAlchemy database URL. |
|
||
| `PIRATS_LOG_FILE` | _(unset)_ | If set, also write logs to this file (rotating, 10 MB × 5 backups). Logs always go to stderr regardless. |
|
||
| `PIRATS_LOG_LEVEL` | `INFO` | Minimum log severity (`DEBUG`/`INFO`/`WARNING`/`ERROR`/`CRITICAL`). |
|
||
| `PIRATS_DEV_MODE` | _(unset = on)_ | Default Dev Mode for new games. Unset is treated as a local checkout (on); set to `0`/`false` to disable. |
|
||
| `PIRATS_PURGE_ENABLED` | `true` | Periodically purge old finished/inactive games. |
|
||
| `PIRATS_PURGE_INTERVAL_HOURS` | `24` | How often the purge task runs. |
|
||
| `PIRATS_PURGE_FINISHED_DAYS` | `14` | Purge games that finished more than this many days ago. |
|
||
| `PIRATS_PURGE_INACTIVE_DAYS` | `30` | Purge games with no activity for this many days. |
|
||
| `PIRATS_MAX_BODY_BYTES` | `1048576` | Reject request bodies larger than this (HTTP 413). |
|
||
|
||
---
|
||
|
||
### Option 2: Using Nix Flakes
|
||
|
||
If you use the Nix package manager, this repository provides a complete environment.
|
||
|
||
#### 1. Enter the Development Shell
|
||
Includes Python, all runtime dependencies, and testing tools (`pytest`):
|
||
```bash
|
||
nix develop
|
||
```
|
||
|
||
#### 2. Run the Application
|
||
Run the package directly from the flake:
|
||
```bash
|
||
nix run . -- --host 0.0.0.0 --port 8000
|
||
```
|
||
|
||
#### 3. Build the Application Package
|
||
```bash
|
||
nix build .
|
||
```
|
||
The executable will be located in `./result/bin/pirats`.
|
||
|
||
---
|
||
|
||
## Deploying as a NixOS Service
|
||
|
||
The Nix flake exposes a NixOS module that configures the application to run as a systemd service with appropriate sandboxing.
|
||
|
||
Add this flake to your system configuration and configure the service:
|
||
|
||
```nix
|
||
services.pirats = {
|
||
enable = true;
|
||
host = "127.0.0.1";
|
||
port = 8000;
|
||
databasePath = "/var/lib/pirats/rats_with_gats.db";
|
||
logFile = "/var/log/pirats/pirats.log"; # rotating; stderr also goes to the journal
|
||
logLevel = "info";
|
||
openFirewall = false; # Set to true to open ports in the firewall
|
||
purge = {
|
||
enable = true; # periodically remove old finished/inactive games
|
||
intervalHours = 24;
|
||
finishedDays = 14; # purge games finished more than 14 days ago
|
||
inactiveDays = 30; # ...or with no activity for 30 days
|
||
};
|
||
};
|
||
```
|
||
|
||
The service writes its log to `logFile` (under the systemd-managed `/var/log/pirats`
|
||
`LogsDirectory`, so the sandboxed `DynamicUser` can write to it) and additionally
|
||
to the systemd journal via stderr (`journalctl -u pirats`).
|
||
|
||
---
|
||
|
||
## Running Tests
|
||
|
||
Tests are written using `pytest`.
|
||
|
||
### Running with Pip
|
||
```bash
|
||
pytest
|
||
```
|
||
|
||
### Running with Nix
|
||
```bash
|
||
nix develop --command pytest
|
||
```
|
||
|
||
---
|
||
|
||
## Project Structure
|
||
|
||
```
|
||
pirats/
|
||
├── pyproject.toml # Python package metadata and dependencies
|
||
├── flake.nix # Nix package (incl. frontend build), dev shell, NixOS service module
|
||
├── tests/
|
||
│ └── test_game.py # Game logic and CRUD test suite (pure-crud, no HTTP for most)
|
||
├── frontend/ # Svelte 5 + Vite SPA
|
||
│ └── src/
|
||
│ ├── pages/ # Routes: Home, Join, Dashboard (game UI), Admin
|
||
│ ├── components/ # One component per game phase, Card.svelte, and scene/ (ScenePhase sub-panels)
|
||
│ └── lib/ # api.js (fetch wrapper), cards.js (card display helpers), suggestions.js (Suggest-button pools)
|
||
└── src/
|
||
└── pirats/ # FastAPI backend package
|
||
├── main.py # App setup, /api/game create/join/state endpoints, CLI entrypoint
|
||
├── models.py # SQLModel tables (Game, Player, Obstacle, Challenge, Vote, GameEvent)
|
||
├── cards.py # Card parsing, deck building, obstacle table from the rulebook
|
||
├── crud.py # Facade re-exporting all crud_* modules
|
||
├── crud_*.py # Game logic by phase: base (deck/hands/rank), character, scene, challenge, upkeep
|
||
├── routes_*.py # Thin API routers by phase, mounted under /api
|
||
└── static/ # Built frontend lands here (gitignored; populated by the Nix build)
|
||
```
|
||
|
||
### Frontend Development
|
||
|
||
Start the backend and Vite dev server together from the repository root. Pressing Ctrl-C stops both:
|
||
|
||
```bash
|
||
./dev.sh
|
||
```
|
||
|
||
To run only the frontend, start the backend separately on port 8000, then run:
|
||
|
||
```bash
|
||
cd frontend && npm install && npm run dev
|
||
```
|
||
|
||
Vite proxies `/api` to the backend on port 8000.
|