176 lines
8.5 KiB
Markdown
176 lines
8.5 KiB
Markdown
# Super Auto Pets: The Board Game — Online
|
||
|
||
A web app for playing the Super Auto Pets board game remotely. 1v1 for now;
|
||
the engine is built to grow to more players. Play a friend by room code, or
|
||
play solo against a computer opponent (easy / medium / hard).
|
||
|
||
## Stack
|
||
|
||
- **Backend**: Go (stdlib-first). Pure game engine in `internal/game`,
|
||
WebSocket sync via `coder/websocket`, persistence as JSON blobs in SQLite
|
||
(`modernc.org/sqlite`, no cgo).
|
||
- **Frontend**: React + Vite + TypeScript in `web/`. DOM/CSS card rendering
|
||
and battle animations.
|
||
- **Tasks**: [mise](https://mise.jdx.dev) (`mise.toml`).
|
||
|
||
## Quick start
|
||
|
||
```sh
|
||
mise run install-web # once: npm install
|
||
mise run serve # build frontend + server, run on :8080
|
||
```
|
||
|
||
Open http://localhost:8080, host a game, and join from another browser (or
|
||
incognito window) with the 5-letter code.
|
||
|
||
### Development
|
||
|
||
```sh
|
||
mise run dev # Go server on :8080 + Vite hot reload on :5173
|
||
mise run test # Go tests (game engine)
|
||
mise run check # go vet + frontend type-check
|
||
```
|
||
|
||
During development open the Vite URL (http://localhost:5173); it proxies
|
||
`/api` (including the WebSocket) to the Go server.
|
||
|
||
## Configuration
|
||
|
||
Set via environment or a `.env` file (see `.env.example`):
|
||
|
||
| Variable | Default | Purpose |
|
||
| ------------ | ---------- | ------------------------------------ |
|
||
| `DATA_DIR` | `data` | Directory holding the SQLite DB |
|
||
| `PORT` | `8080` | HTTP port |
|
||
| `STATIC_DIR` | `web/dist` | Built frontend to serve |
|
||
|
||
## Rules implemented
|
||
|
||
Six rounds, each with its own shop tier deck. Per round:
|
||
|
||
1. **Shop** — each player has 3 gold and players alternate actions: **buy**
|
||
one of 4 face-up cards (1 gold — the only action that costs anything);
|
||
**sell** any number of hand cards for free (each becomes an 🍎 apple, +1
|
||
power food, and Sell effects fire); or **trade in** 3 same-suit pets (the
|
||
Triple action, also free) to pick 1 of the top 2 cards of the next tier's
|
||
deck — Triple effects fire on the traded cards and the received pet's Buy
|
||
effect fires. **Passing** is a final action, only legal at 5 pets or
|
||
fewer: it forfeits remaining gold and ends that player's shopping for the
|
||
round. The shop closes once everyone has passed.
|
||
2. **Arrange** — Battle Prep effects fire first (e.g. Giraffe hands out
|
||
apples), then players secretly order their decks. Food cards apply to the
|
||
next pet after them; trailing foods are wasted. A pet only benefits from
|
||
its last-applied **perk** (e.g. Honey, Garlic).
|
||
3. **Battle** — automatic stack machine. Cards reveal off the top of each
|
||
deck until a pet is in play. Play effects fire on reveal (rocks roll a d6
|
||
with faces 0/0/1/1/2/2 and hit the opposing pet before the clash; Skunk
|
||
strips foods; Wolverine steals apples; Chili mills the enemy deck). The
|
||
two pets simultaneously deal their full power to each other as damage
|
||
markers; a pet with markers ≥ power faints (attack never drops while
|
||
wounded). Faint effects push summons onto either deck, recycle apples
|
||
(Dodo), set aside delayed/recurring/conditional rock volleys (Badger,
|
||
Blowfish, Snake, Crocodile), raise auras (Turkey, Mammoth), or arm a
|
||
team shield (Turtle). Survivors that took damage fire Hurt effects
|
||
(Peacock, Camel, Gorilla). Shields (Turtle/Gorilla/Melon) block whole
|
||
hits, Garlic shaves 1 per attack, and Scorpion KOs anything its clash
|
||
attack manages to hurt. Hippo heals when enemies faint; Rhino rocks each
|
||
enemy pet as it's played. A clash that changes nothing ends the battle
|
||
as a stalemate draw. Last player able to field a pet wins: 1 trophy for
|
||
rounds 1–5, 2 for round 6. Draws award nothing.
|
||
|
||
Apples and bees are **temporary**: they leave your deck after the battle.
|
||
Most trophies after round 6 wins.
|
||
|
||
## Packs
|
||
|
||
Three card packs are playable, chosen by the host in the lobby. Each pack is
|
||
six tiers, one per round, and every pet ships as two copies.
|
||
|
||
### Turtle pack
|
||
|
||
| Tier | Pets | Food |
|
||
| ---- | ---- | ---- |
|
||
| 1 | Ant, Cricket, Duck, Otter, Mosquito, Fish | — |
|
||
| 2 | Worm, Flamingo, Peacock, Swan, Rat, Spider | Honey |
|
||
| 3 | Dog, Dolphin, Giraffe, Camel, Sheep, Dodo, Badger | Garlic |
|
||
| 4 | Squirrel, Turtle, Rooster, Bison, Blowfish, Skunk, Hippo | Pineapple |
|
||
| 5 | Monkey, Rhino, Crocodile, Scorpion, Seal, Shark, Turkey | Chili |
|
||
| 6 | Gorilla, Fly, Leopard, Mammoth, Cat, Snake, Wolverine | Melon |
|
||
|
||
### Golden pack
|
||
|
||
| Tier | Pets | Food |
|
||
| ---- | ---- | ---- |
|
||
| 1 | Groundhog, Pied Tamarin, Chipmunk, Cone Snail, Bulldog, Opossum | — |
|
||
| 2 | Black-Necked Stilt, Lizard, Hercules Beetle, Stoat, Desert Rain Frog, Honduran White Bat | — |
|
||
| 3 | Guinea Fowl, Surgeon Fish, Osprey, Anteater, Bear, Royal Flycatcher, Flea | Avocado |
|
||
| 4 | Saiga Antelope, Vaquita, Poison Dart Frog, Manta Ray, Slug, Cockatoo, Manatee | Potato |
|
||
| 5 | Nyala, Nurse Shark, Giant Isopod, Blue-Ringed Octopus, Raccoon, Fire Ant, Macaque | Durian |
|
||
| 6 | Highland Cow, Wildebeest, Grizzly Bear, Catfish, Komodo, Bird of Paradise, German Shepherd | Tomato |
|
||
|
||
The Golden pack adds mechanics the Turtle pack doesn't have:
|
||
|
||
- **Trumpets** — an ephemeral battle resource pets earn and spend mid-fight.
|
||
- **Golden Retriever** — once per battle, a side that runs out of cards but
|
||
still holds Trumpets fields one, its power equal to those Trumpets.
|
||
- **Avocado** — a persistent set-aside token you can discard in place of gold.
|
||
- **Nurse Shark** — on entry it spends every Trumpet it can (up to 3),
|
||
throwing two rocks at the enemy per Trumpet spent.
|
||
- **Cockatoo** — a shop-time reveal, plus Manta Ray's free first buy,
|
||
Blue-Ringed Octopus' per-buy apples, and more.
|
||
|
||
### Unicorn pack
|
||
|
||
| Tier | Pets | Food |
|
||
| ---- | ---- | ---- |
|
||
| 1 | Alchemedes, Cuddle Toad, Pengobble, Barghest, Basilisk, Baku | — |
|
||
| 2 | Thunderbird, Gargoyle, Frost Wolf, Mothman, Nightcrawler, Bigfoot | Fairy Dust |
|
||
| 3 | Fur-Bearing Trout, Calygreyhound, Tatzelwurm, Skeleton Dog, Mandrake, Lucky Cat, Slime | Water of Youth |
|
||
| 4 | Roc, Chimera, Kraken, Unicorn, Abomination, Rootlin, Fairy | Health Potion |
|
||
| 5 | Kitsune, Pixiu, Red Dragon, Amalgamation, Vampire Bat, Werewolf, Loveland Frogman | Big Mana Potion |
|
||
| 6 | Sleipnir, Sea Serpent, Bakunawa, Manticore, Team Spirit, Behemoth, Quetzalcoatl | Cornucopia |
|
||
|
||
The Unicorn pack adds two mechanics the others don't have:
|
||
|
||
- **Mana** — a **persistent** resource (unlike ephemeral Trumpets): pets earn
|
||
it in the shop (Cuddle Toad, Thunderbird, Roc) and in battle (Alchemedes,
|
||
Fur-Bearing Trout, Kitsune, Tatzelwurm per rock blank), and spend it to power
|
||
abilities (Pengobble, Gargoyle, Sea Serpent, Bakunawa; Sleipnir's very Power
|
||
equals your Mana). It carries over between rounds until spent, so you can bank
|
||
it up.
|
||
- **Ailments** — temporary debuff cards attached to a pet during battle,
|
||
removed at round end like apples. **Spooked** lowers the pet's clash attack
|
||
(−1 each, min 0); **Exposed** raises the damage it takes per hit (+1 each).
|
||
They stack, can be added to the enemy pet or dropped on top of the enemy deck
|
||
(Frost Wolf, Slime, Kraken, Red Dragon). **Baku** shrugs off the first one it
|
||
takes, **Unicorn** turns the next friendly one into apples, and **Manticore**
|
||
makes enemy ailments count for more.
|
||
- Plus a **game-wide discard pile** the higher tiers reach into (Chimera,
|
||
Abomination), pet-recycling (Fairy, Loveland Frogman's bounce), and shop
|
||
tricks — Bigfoot's deck peek, Water of Youth's upgrade, Quetzalcoatl's reveal.
|
||
|
||
## Layout
|
||
|
||
```
|
||
cmd/server/ entrypoint
|
||
internal/game/ rules engine (pure, fully tested)
|
||
internal/ai/ computer opponent (decides from a player View only)
|
||
internal/server/ HTTP + WebSocket rooms; drives bot turns
|
||
internal/store/ SQLite persistence
|
||
internal/env/ .env loading
|
||
web/ React frontend
|
||
```
|
||
|
||
## The computer opponent
|
||
|
||
Any seat can be a bot (`Player.IsBot`); humans and bots are interchangeable
|
||
to the engine, which is what will let future >2-player games mix them
|
||
freely. The AI in `internal/ai` never touches the `Game` — it decides from a
|
||
`game.View`, the same per-player state a human client is sent, plus a
|
||
persisted memory of public observations (battle lineups, the event log, shop
|
||
row changes). It cannot see your deck order, hidden trade picks, or the
|
||
shuffled shop decks. It scores candidate moves by Monte-Carlo battle
|
||
rollouts (`game.SimulateBattle`) against sampled guesses of your deck and
|
||
ordering, blended with a long-term deck-value heuristic; difficulty tunes a
|
||
softmax over the scored moves plus the rollout budget.
|