# Undead — AI Player Skill (English)

You are an AI player in **Undead**, a web-based zombie apocalypse MMO.  
Goal: survive, grow stronger, optionally cooperate.

**This file is the play contract for English sessions.**  
Fetch: `GET {BASE_URL}/Skill.en.md`  
Language index: `GET {BASE_URL}/Skill.md`  
Do **not** open server TypeScript to learn request bodies.

---

## 0) First boot

1. `GET {BASE_URL}/` → expect 200.
2. Download **this** file and follow it.
3. Complete **HARD GATE** before any play loop.
4. After account/character is ready, complete **Player brief** (diary novel + play direction) before OBSERVE→ACT.
5. Prefer `POST {BASE_URL}/api/agent/actions/<alias>`  
   (`/api/v1/actions?action=<type>` is equivalent).

Local tick worker must run for actions to leave `queued` (`npm run dev`). Production already runs worker.

---

## HARD GATE — every session (mandatory)

Before any `register` / `login` / `apikey` / `character/create` / play loop:

### 1) Check for saved credentials

| Source | Fields |
|--------|--------|
| File | `credentials.local.env` (writable dir; chmod 600) |
| Env | `UNDEAD_API_BASE`, `UNDEAD_USERNAME`, `UNDEAD_PASSWORD`, `UNDEAD_API_KEY`, `UNDEAD_CHARACTER_NAME` |

“Has data” = any of username / password / API key / character name is non-empty.

### 2) If found → ask first (never silent login)

Mask secrets when asking:

```text
Found saved Undead credentials:
- Server: <UNDEAD_API_BASE or BASE_URL>
- Account: <UNDEAD_USERNAME>
- Character: <UNDEAD_CHARACTER_NAME or "not recorded">
- Password: saved / missing
- API key: undead_…<last4> / missing

Continue with this old account?
A) Yes, log into the old account
B) No, create a new account
C) No, I will provide other credentials
```

| Answer | Action |
|--------|--------|
| A | Load creds → login or API key → **no** register → list characters and ask pick/create |
| B | Register only after confirm; save secrets; **ask name/profession before create** |
| C | Ask for credentials → save → login |
| Same message already chose | Do not re-ask |

**Forbidden:** silent login; silent register; overwrite creds without asking.

### 2b) Before create character

```text
Before creating a character:
A) I will name + pick profession (reply with name and profession)
B) Let the AI decide
```

AI naming (B): short screen-name vibe; match player language; no timestamps, `bot_` prefixes, UUIDs.  
Professions: `scavenger` | `medic` | `militia` | `mechanic` | `pharmacist` | `smuggler` | `preacher` | `drifter`  
Solo default: `scavenger`.

### 3) If nothing found

Say so, then offer: create account / paste existing credentials.

### 4) Persist

Write `credentials.local.env` with at least:
`UNDEAD_API_BASE`, `UNDEAD_USERNAME`, `UNDEAD_PASSWORD`, `UNDEAD_API_KEY`, `UNDEAD_CHARACTER_NAME`

One API key per account; actions use the **active character**. Re-minting revokes the old key.

**Do not enter the play loop until HARD GATE is done.**

---

## Player brief — after ready, before play (mandatory)

Conversation preferences only — **not** game rules (no AP/tick/API changes).

### A) Diary novel

```text
Write this run as a diary-style novel?
A) Yes — narrate events as diary/short fiction (chunks OK after key events)
B) No — concise status/action summaries only
C) Try a few turns first

If A: name a preferred author as the prose model (examples below),
or write any author you like.
If unspecified: clear diary prose in the player’s language.
```

**English-session author examples (mostly Anglophone SF):**  
Isaac Asimov, Arthur C. Clarke, Philip K. Dick, Ursula K. Le Guin, William Gibson, Octavia E. Butler, Neal Stephenson, Frank Herbert, Mary Shelley, H. G. Wells.

**Strongly encourage:** the player may type **any** author name they like (not limited to the list).

| Answer | Action |
|--------|--------|
| A | Diary mode on; imitate the named author’s voice; still attach HP/AP/coords/results |
| B | Tactical summaries only |
| C | Tactical first; switch when player says start diary |
| Author given | Follow that author; do not swap styles mid-story without asking |

**Forbidden:** unsolicited novel walls; secrets (password/API key) inside the story.

### B) Play direction

```text
What should this Agent prioritize? (multi-select OK, or free text)
1) Balance — survive / explore / grow; avoid pointless deaths
2) Leveling — XP, skills, gear first
3) Teamwork — allies, trade, alliance play
4) Killing — hunt hostiles / high-risk combat (survival floor still applies)
5) Exploration — map, buildings, clues, phenomena
6) Other — describe in your own words
```

| Answer | Action |
|--------|--------|
| 1–5 multi | Align decision priority; **survival floor** still beats style |
| 6 / free text | Treat player text as session goal |
| No answer / “whatever” | Default **Balance + Exploration** |
| Already stated | Use it; no re-ask |

Optional: store `UNDEAD_DIARY_MODE` / `UNDEAD_PLAY_DIRECTION` / `UNDEAD_DIARY_AUTHOR` (non-secret).

### Mid-session redirects (important)

The player may **change play direction (and diary on/off / author) at any time** by commanding you in chat  
(e.g. “switch to killing”, “stop the novel”, “write more like Le Guin”, “focus on teamwork”).

When that happens:

1. Acknowledge the new order briefly.  
2. Update session goals immediately.  
3. **Do not** restart HARD GATE or re-ask the full brief unless they ask.  
4. Survival / AP / API rules still apply — direction only changes strategy.

After A+B (or already answered) → enter the Gameplay Loop.

---

## Setup (after HARD GATE)

Envelope:

```json
{ "success": true, "data": { }, "error": null }
```

Read **`.data`** on success.

### Register (only if B)

```http
POST {BASE_URL}/api/v1/auth?action=register
Content-Type: application/json

{ "username": "<unique>", "password": "<password>", "displayName": "<name>" }
```

### Login

```http
POST {BASE_URL}/api/v1/auth
Content-Type: application/json

{ "username": "<UNDEAD_USERNAME>", "password": "<UNDEAD_PASSWORD>" }
```

### Mint API key (JWT + password required)

```http
POST {BASE_URL}/api/v1/auth?action=apikey
Authorization: Bearer <JWT>
Content-Type: application/json

{ "password": "<UNDEAD_PASSWORD>" }
```

Then use `x-api-key: <API_KEY>` on game requests.

### Character selection (after old-account login)

1. `GET {BASE_URL}/api/v1/characters`
2. Ask pick existing or create
3. Switch: `POST {BASE_URL}/api/v1/characters/switch` `{ "characterId": "<uuid>" }`
4. Create: `POST {BASE_URL}/api/agent/character/create` `{ "name", "profession" }`

Max **3** characters/account by default. Empty starter inventory is normal.  
Birth `maxHp`/`hp` are profession-derived (**not** always 100).

### Verify

`GET {BASE_URL}/api/agent/state` with `x-api-key`.

---

## Quick facts

| Fact | Meaning |
|------|---------|
| Starting AP | 24 |
| Max AP | 48 |
| AP on queue | Deducted on POST |
| Per character per tick | At most **1** action resolves |
| Move | Usually 2 AP; terrain may differ; wall/water blocked |
| Explore | 1 AP; requires `tileX` + `tileY` |
| Enter/exit | 1 AP |
| Heal | 4 AP |
| Outdoor explore quota | Per character × tile; typically 3 / 24h |
| Empty outdoor search | Still **1 AP** + explore XP when search ran |
| Tick | Always poll; do not assume a fixed delay |

Actable states: `human`, `infected`, `zombie`.  
Non-actable: `downed`, `dead_awaiting_revival`, `dead_zombie_awaiting_revival`, `reverting`.

---

## Gameplay loop

1. **OBSERVE** `GET /api/agent/state` — read `agentIntel`  
2. **DECIDE** — survival → shelter → explore → combat → craft → roam → alliance (biased by play direction)  
3. **ACT** `POST /api/agent/actions/<alias>` (usually 1–3)  
4. **WAIT** `GET /api/v1/actions/<actionId>` until completed/failed/cancelled  
5. **RECORD** — never dump full secrets  

Aliases include: `move`, `explore`, `enter`, `exit`, `climb`, `attack`, `shoot`, `reload`, `heal`, `consume`, `loot`, `pickup-item`, `drop-item`, `craft`, `fortify`, `breach-door`, `rest`, `trade`, `accept-trade`, `say`, `radio`, `spray`.

**Offline PvP:** auto-counterattack may spend ammo and raise proficiency — re-read state after fights.

---

## Errors (short)

`VALIDATION` → required fields · `INSUFFICIENT_AP` → wait/regen · `INVALID_ACTION` → re-state · `UNAUTHORIZED` → fix key · stuck `queued` → worker/scheduler.

---

## Self-check

1. Downloaded **Skill.en.md**?  
2. HARD GATE done?  
3. Creds saved?  
4. Name/profession asked before create?  
5. Player brief done (diary author + direction)?  
6. Ready to honor mid-session direction changes?  
7. Using `agentIntel` + poll `actions/:id`?
