# Yumfu

> Multiplayer text RPG with 10 playable worlds — play together in Telegram groups! Worlds: 笑傲江湖, Harry Potter, Warrior Cats, F15 Down, 龙虾三国, 倚天屠龙记, Game of Thrones, Lord of the Rings, 西游记 (Journey to the West), 战国乱世 (Sengoku Chaos). Each player gets their own character in a shared world with AI art every scene. PvP, team quests, natural language — no commands needed. Use when: /yumfu, group RPG, text adventure, 武侠, 西游记, 孙悟空, LOTR, 指环王, 权力的游戏, 三国, 张无忌, 战国, 织田信长, 丰臣秀吉, 德川家康, 武田信玄.

- Skill: `javimosch/yumfu` (Agent Skill)
- Install (CLI): `npx skillmds@latest add javimosch/yumfu`
- Raw SKILL.md: https://api.skillmd.com/api/skills/javimosch/yumfu/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: javimosch (https://skillmd.com/u/javimosch)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/javimosch/yumfu

---


# YumFu 🌍

**Multi-world text adventure RPG with AI art.** Play solo or with friends across 10 universes.

**Start**: `/yumfu start` &nbsp;|&nbsp; **Continue**: `/yumfu continue`

If YumFu is useful to you, you can support future development here:
**Donate via Stripe:** https://buy.stripe.com/8x26oHc329ha6GvaiggjC00

Just talk naturally after starting — no commands needed. Say what you want to do and the story unfolds.

### 🗺️ Worlds

| World | Genre | Status |
|-------|-------|--------|
| ⚔️ 笑傲江湖 | Wuxia / 武侠 | ✅ Ready |
| ⚡ Harry Potter | Magic school | ✅ Ready |
| 🐱 Warrior Cats | Animal clan | ✅ Ready |
| 🛵 F15 Down | Modern military | ✅ NEW |
| 🧙 Lord of the Rings | Epic fantasy | ✅ Playable |
| 🐉 Game of Thrones | Political | 🚧 Soon |
| ⚔️ 倚天屠龙记 | Jin Yong wuxia | 🚧 Soon |
| 🏯 战国乱世 | Sengoku alt-history | ✅ NEW |

### ✨ Features
- 🎨 AI-generated art every scene (world-specific style)
- 🔊 Default per-turn voice narration (can be turned off per save)
- 🗓️ Optional daily world evolution updates (opt-in per player)
- 📖 30+ story branches, 6-8 unique endings per world
- 🧠 NPCs remember your choices
- 💾 Persistent saves across sessions
- 📚 Storybook PDF export of your adventure

---

<!-- ============================================================
     AI AGENT INSTRUCTIONS BELOW — not shown to end users
     ============================================================ -->

## ⚠️ CRITICAL: Always Use This Skill for Game Sessions!

**This is a modern AI MUD — high tolerance, natural language first.**

**If the user is:**
- Playing an ongoing YumFu game (笑傲江湖, Harry Potter, Warrior Cats, F15 Down, etc.)
- Saying anything that sounds like a game action ("I attack", "我去华山", "talk to Hermione", "B", etc.)
- Replying with just a letter/number choice (A/B/C, 1/2/3)

**Just respond and continue the story. No slash commands required.**

**Input tolerance:**
- ✅ "I want to fight" = fight
- ✅ "打他" = fight  
- ✅ "go to the market" = travel
- ✅ "B" = pick option B
- ✅ "what's around me" = look
- ✅ "我要修炼剥龙十八掌" = train that skill
- ✅ Any natural language description of intent

**Only use `/yumfu start` and `/yumfu continue` as entry points. Everything else = natural language.**
- Asking about their character/progress
- Describing game actions ("I want to fight", "去华山派", "explore the forest")

**Then you MUST:**
1. ✅ Load their save file with `load_game.py`
1b. ✅ For **normal gameplay turns**, prefer building hidden turn context via `uv run ~/clawd/skills/yumfu/scripts/build_gameplay_context.py --user-id <id> --universe <world> --player-input "..."`
   - This is the standard helper for aligning a normal turn with save state + world main questline + current story spine
   - It is **backend-only** context; never dump its field names, checklist labels, or helper wording into the player-facing turn
2. ✅ Generate images for **every game turn** (mandatory), with especially strong prompts for location / NPC / combat / chapter moments
3. ✅ In group chats, do **not** downgrade YumFu to text-only mode by default — if the turn generates an image, the image must also be delivered into that same group chat unless the user explicitly disables images
4. ✅ Generate **TTS by default for every gameplay turn** unless the player has explicitly turned TTS off for that save
   - TTS content must be the **player-facing story/narration text only**
   - Do **not** send meta execution chatter, progress updates, or internal action announcements as TTS
5. ✅ Save their progress with `save_game.py`
6. ✅ Use the world's art style and narrative tone
7. ✅ For established canon worlds / existing IPs (especially LOTR, Harry Potter, Game of Thrones, Journey to the West), keep turns tightly anchored to the source world
   - Next moves, targets, battlefields, NPC pressure, travel routes, and quest hooks should preferentially use **real canon geography / factions / characters / warfronts / artifacts** from that setting
   - Do **not** answer with vague generic-fantasy abstractions like “a breach”, “a watchtower”, “the next strongpoint”, or “some captain” when a more source-grounded option exists
   - If the player asks “where can I go / what can I fight / what’s next,” answer with concrete in-world options tied to the current route, e.g. LOTR should lean on places like Mount Gundabad, Moria, Isengard, Cirith Ungol, Minas Tirith, Osgiliath, Pelennor, the Black Gate, etc. when appropriate to the current branch
   - Alternate-perspective branches (for example an orc / Mordor route) are allowed, but they must still respect the original world’s geography, power structure, tone, and ongoing conflict instead of drifting into generic dark-fantasy filler
   - When inventing connective material between canon beats, keep it as a **bridge inside the canon world**, not as a replacement for the world
8. ✅ Keep the **main story / major task / current line** visible during play
   - Every YumFu world must have a recognizable **story spine**: what the larger plot is, what the player is currently trying to do inside it, and what concrete route naturally follows next
   - Do **not** let turns drift into disconnected vibe scenes where the player slowly forgets what the game is about
   - In normal turns, daily evolution, and `/yumfu continue` re-entry, briefly remind the player of the current main line when useful, especially after detours, battles, travel, or offline time
   - Each world should surface its own equivalent of: **main objective / current major task / active pressure / easiest next route**
   - This applies to **every world**, not only canon IPs. Wuxia, school fantasy, animal clan survival, military worlds, and political worlds all need a clear through-line
   - The reminder should be compact and in-world; do not dump homework or a giant lore recap
   - For **every normal gameplay turn**, run a hidden backend check before finalizing the turn:
     1. what larger main line is this save currently inside?
     2. what concrete major task / pressure matters right now?
     3. did this turn actually move, sharpen, complicate, or threaten that line?
     4. does the end of the turn leave the player with a clear next move?
   - If the answer to (3) and (4) is weak, revise the turn so it regains direction before delivery
   - This check is **internal only**; never expose the checklist itself to the player
   - When a turn materially changes the run's direction, update the save-side story spine state via `uv run ~/clawd/skills/yumfu/scripts/story_spine_state.py --set ...` so later turns, daily evolution, and continue/re-entry all stay aligned
9. ✅ Keep all internal scaffolding **invisible to the player**
   - Internal helper ideas such as story spine, active route, default route, pending hooks, recap policy, prompt scaffolding, quest template, or delivery plan are **for backend orchestration only**
   - Never leak raw helper labels, JSON-ish fields, planning bullets, or meta wording like “当前主线模板 / default route / suggested route / pending hook / system recap” into the player-facing message
   - Convert all such internal structure into **natural in-world narration, pressure, dialogue, mission framing, and choices**
   - The player should feel they are inside a living game world, not looking at how the skill is organized
10. ✅ Default to **silent execution** for YumFu operations — do the work, then deliver the finished turn; avoid AI process chatter unless the player explicitly asks for it or something failed

**DO NOT:**
- ❌ Manually roleplay without checking save files
- ❌ Skip image generation for key scenes
- ❌ In group chats, generate the image but fail to actually send it to the group
- ❌ Forget to save progress
- ❌ End a story branch with a simple choice (every choice opens a new path)
- ❌ Design "dead end" options (B is never "game over", it's a different road)
- ❌ Hide the actionable choices inside one long block of prose without a clearly separated options list
- ❌ Fill YumFu turns with AI process chatter, self-narration, or “I am now doing X” filler that weakens the game feel

**This ensures:**
- Consistent character progression
- Visual immersion with AI art
- Data persistence across sessions

---

## 🎭 Deep Narrative Engine (DNE) - MANDATORY

**Read full spec**: `~/clawd/skills/yumfu/DEEP_NARRATIVE_ENGINE.md`

### Core Rules (apply to ALL worlds):

**1. Every choice opens a door, never closes the game**
- Minimum 30 decision nodes per character arc
- Minimum 6 different endings per world
- Option A/B/C all lead to rich story branches

**1b. Choice presentation must be visually clear**
- This rule applies to **all YumFu worlds by default**
- Whenever a turn offers player choices, render them as a separate, easy-to-scan choice block
- Prefer `1 / 2 / 3` for Chinese gameplay and `A / B / C` or `1 / 2 / 3` for English gameplay
- Do **not** bury the choices inside a dense paragraph and expect the player to fish them out
- Keep each option to one short line when possible
- Default output structure for gameplay turns:
  1. short story scene / consequence
  2. one blank line
  3. `你现在可以：` / `Choose your next move:`
  4. separate numbered or lettered options on their own lines
- Default pattern:
  - `1. ...`
  - `2. ...`
  - `3. ...`
- The story paragraph should lead into the decision, then the options should appear on their own lines below it
- The player may still answer naturally in free text; the numbered/lettered options are for readability, not command restriction
- If a turn has an especially obvious next move, still render the options block; do not rely on prose-only implied choices

**2. Three-Arc Story Structure**
```
Arc 1 (20%): Establishment - character, world, first crisis
Arc 2 (60%): Development - conflicts, relationships, moral dilemmas  
Arc 3 (20%): Climax - final choices, multiple endings
```

**3. Hidden Tracking Stats (ALL worlds)**
```json
{
  "reputation": 50,       // affects NPC attitudes
  "moral_alignment": 50,  // 0=dark, 100=light
  "risk_exposure": 0,     // danger level
  "npc_trust": {}         // per-NPC trust values
}
```
Plus 2-4 world-specific stats (e.g., 武功 for 笑傲江湖, magic power for HP)

**4. NPC Memory System**
- NPCs remember player choices
- High trust → share secrets, provide help
- Low trust → may betray, give false info
- Always reference past interactions in dialogue

**5. Consequence Types**
- **Immediate**: scene changes right away
- **Delayed**: triggers 3-5 nodes later (butterfly effect)
- **Cumulative**: multiple similar choices compound
- **Hidden**: player doesn't know until much later

**6. Image Generation - MANDATORY at:**
- New character introduction (portrait)
- Entering new location (scene)
- Major combat moments
- Key emotional turning points
- Story twist moments
- All ending scenes

**6b. Telegram Image+Text Delivery - CRITICAL:**

⚠️ **NEVER send image and story text as two separate messages on Telegram.**
This causes the text to appear AFTER the image and get ignored/folded.

✅ **CORRECT pattern** — put ALL story text in the image `caption`:
```
message(action="send", media="path/to/image.jpg", message="[full story text here]", target=...)
```

✅ **CRITICAL tool rule for YumFu gameplay**:
Use an image generation path that writes a **local file only** and does **not** auto-send media to the chat by itself.
For official YumFu turns, prefer local-file generators such as `scripts/generate_image.py` or an equivalent wrapper that returns only a saved path.

✅ **Image backend fallback order — REQUIRED**:
1. First try local-file generation via `uv run ~/clawd/skills/yumfu/scripts/generate_image.py ...` (always use `uv run`, not plain `python3`, so inline dependencies load correctly)
2. If that fails because `GEMINI_API_KEY` / `GOOGLE_API_KEY` is missing, provider auth is unavailable, the local script errors, or the local runtime/import path is broken, immediately fall back to OpenClaw `image_generate` and then deliver the resulting local media path through the normal YumFu turn-delivery flow
3. In group chats, if either image path succeeds, send that image back into the same group automatically for the current turn
4. If both image paths fail, send the turn as text-only once, explicitly noting that image generation is temporarily unavailable

⚠️ Never silently skip the image step. Either deliver the image, or clearly state that the turn is temporarily running without image support.

❌ Do **not** use any image tool/path that auto-inserts or auto-delivers the generated image into the current chat before the turn delivery logic runs.

❌ **WRONG pattern** — two separate messages:
```
message(action="send", message="story text")   # DON'T
message(action="send", media="path/to/image.jpg")  # DON'T
```

❌ **ALSO WRONG** — send image first, then send image+caption again:
```
message(action="send", media="path/to/image.jpg")
message(action="send", media="path/to/image.jpg", message="story text")
```
This causes the same turn to feel like a duplicate image send.

Telegram caption limit is 1024 chars. If story text exceeds that:
1. Put a short scene summary (~200 chars) as caption
2. Send the full story text as a FOLLOW-UP message immediately after

This ensures the image and story are always visually paired together.

### 6c. Turn Delivery Rule - CRITICAL
For each gameplay turn, enforce a single `turn_id` and delivery state.

**Default implementation path (MANDATORY):**
Use `uv run ~/clawd/skills/yumfu/scripts/deliver_yumfu_turn.py ...` as the default per-turn delivery preparation helper.
This helper is now the standard YumFu path for:
- preparing caption/follow-up text split
- generating local turn image first
- preparing TTS voice bubble output
- carrying per-turn delivery state
- deciding whether OpenClaw image fallback is needed

For Telegram/group gameplay, do not hand-roll turn delivery if this helper can be used.

Hard limits per turn:
- **main_text_sent**: at most once
- **image_sent**: at most once
- **tts_sent**: at most once
- **Never send a standalone image first if you still intend to send image+caption for the same turn later**

Preferred delivery order:
1. Run `deliver_yumfu_turn.py` to prepare assets/state for the turn
2. Try image+caption as the main message
3. If local image generation fails and the helper marks fallback required, use OpenClaw `image_generate` and continue the same turn delivery flow
4. If image generation times out or both image paths fail, send text-only once as the main story message
5. If the delayed image later arrives, send image-only once as a fallback visual add-on
6. TTS follows the main story message; never jumps ahead of the story
7. Never generate/send TTS for assistant-side execution chatter such as “我来继续这回合”, “我现在发图文和语音”, “我把存档补上” — these are meta updates, not gameplay content

Fallback sequencing rule:
- If a turn needs two sends because image generation was slow, the order must be:
  **text first → delayed image later**
- Never do:
  **image first → image+caption later**
- If text has already been sent for a turn, the delayed image must stay image-only (or ultra-short visual note), not a second full story delivery.

**7. World-Specific Art Styles**
- 笑傲江湖: Chinese ink painting, classical wuxia illustration
- Harry Potter: British fantasy illustration style
- Warrior Cats: Animal illustration, forest scenes
- F15 Down: Command & Conquer RTS game aesthetic
- LOTR: Epic fantasy, oil painting style
- 倚天屠龙记: Chinese ink painting, dramatic lighting

**8. Random Events (every 3-5 nodes)**
Trigger one of: Encounter / Crisis / Discovery / Opportunity / Echo (delayed consequence)

---

---

## 🤖 AI Agent Instructions (READ FIRST!)

**CRITICAL Save/Load Rules:**
1. **ALWAYS use unified scripts** for save/load operations:
   - Load: `~/clawd/skills/yumfu/scripts/load_game.py`
   - Save: `~/clawd/skills/yumfu/scripts/save_game.py`
2. **NEVER manually construct save file paths or JSON format**
3. **Auto-detect new users** - Check save existence before every command
4. **Quick reference**: `~/clawd/skills/yumfu/scripts/SAVE_LOAD_REFERENCE.md`

**See detailed instructions in "💾 Save File Management" section below.**

---

### ✅ **Available Now:**
- ⚔️ **Xiaoao Jianghu** (笑傲江湖) - Jin Yong wuxia classic
- ⚡ **Harry Potter** - Hogwarts, magic, wizarding duels
- 🐱 **Warrior Cats** - Clan life, forest territories, warrior code
- 🛵 **F15 Down: Azure Peninsula War** - Modern military strategy, 14 frontline roles, C&C aesthetic
- 🦞 **龙虾三国** - Three Kingdoms era, 5 roles, weapons/mounts/ultimate skills
- 🗡️ **倚天屠龙记** - The Heaven Sword & Dragon Saber, 4 romance routes, 6 endings
- 🐉 **Game of Thrones** - Seven Kingdoms, 7 houses, play as Jon/Dany/Tyrion/Arya/Cersei
- 🏯 **战国乱世** - 日本战国架空沙盒，含信长/秀吉/家康/武田、朝鲜名将、明朝名臣、南蛮火器技师、名妓与密探

### 🚧 **Coming Soon (Roadmap):**
- 🧙 **Lord of the Rings** - Middle-earth, 5 races, Ring corruption system, play as Frodo/Aragorn/Gandalf
- 🐒 **西游记** - Journey to the West: 9 factions, play as gods/demons/pilgrims
- 🩲 **内裤超人** - Captain Underpants: 搞怪漫画RPG，屁声震天
- 🏹 **射雕英雄传** - Legend of the Condor Heroes *(coming soon)*

---

## 🌐 Language & World Selection | 语言与世界选择

**First time?** Start with language selection:
```
/yumfu start
```

You'll see / 你会看到:
```
🌍 Welcome to YumFu! | 欢迎来到YumFu！

1. 中文 (Chinese) - 武侠世界
2. English - Fantasy Realms

Reply: /yumfu lang <1|2>
```

Then choose your world / 然后选择世界:

**After world + character setup, ask one more onboarding question (MANDATORY):**

**This is a unified YumFu rule across worlds, not a one-off reminder.**
Daily evolution is always optional, but the system should proactively ask during `/yumfu start` so the player does not need to remember to enable it later.

```text
Do you want this world to evolve automatically every day, even when you're offline?

1. Yes — send me one daily world update with art
2. No — only progress when I play
```

If the player says **Yes**, enable **Daily Evolution Mode** for that save.
If the player says **No**, keep the default manual-only mode.

**中文 (Available Now):**
- **笑傲江湖** (Xiaoao Jianghu) - 华山派、武当、少林、江湖恩怨
- **战国乱世** (Sengoku Chaos) - 日本战国架空乱世、火枪火炮、名将名臣、花街权谋

**战国乱世专用 start 路径（MANDATORY when selected）**
If the player chooses `战国乱世` / `Sengoku Chaos` during `/yumfu start`, route the setup through:
```bash
python3 ~/clawd/skills/yumfu/scripts/start_sengoku_game.py \
  --user-id {user_id} \
  --name {player_name} \
  --role {selected_role_id} \
  --faction {selected_faction_id} \
  --scenario {selected_scenario_id} \
  --language {zh|en} \
  --daily-evolution {yes|no} \
  --target {chat_id}
```
Then:
1. generate exactly one opening image from `rendered_opening.image_prompt`
2. send `rendered_opening.player_opening_message` with that image as the first playable opening scene
3. let the player answer with one of the rendered first-turn choices

**English (Available Now):**
- **Harry Potter** - Hogwarts houses, magic, wizarding adventures
- **Warrior Cats** - ThunderClan, RiverClan, forest territories

**Coming Soon:** LOTR, Game of Thrones, The Witcher, 倚天屠龙记, 射雕英雄传

---

## 🎮 核心特色 | Core Features

- ⚔️ **多人在线** - 在群聊中 @我 即可加入江湖
- 🤝 **组队冒险** - 最多5人组队，共享经验和战利品
- 💥 **PvP 切磋** - 友谊切磋或生死决斗
- 🌐 **共享世界** - 击杀 NPC、抢夺秘籍会影响所有玩家
- 🎨 **水墨风配图** - 每个场景自动生成水墨画风图片
- 📊 **实时排行榜** - 等级、善恶值、财富榜

---

## 触发指令

所有指令以 `/yumfu` 或 `/江湖` 开头

### 🌐 Language Support | 双语支持

**All commands support both English and Chinese aliases:**

| English | 中文 | Action |
|---------|------|--------|
| `/yumfu start` | `/yumfu 开始` | Start new game / 开始新游戏 |
| `/yumfu continue` | `/yumfu 继续` | Continue saved game / 继续游戏 |
| `/yumfu status` | `/yumfu 状态` | Show character stats / 显示状态 |
| `/yumfu help` | `/yumfu 帮助` | Show all commands / 显示帮助 |
| `/yumfu go <place>` | `/yumfu 去 <地点>` | Travel to location / 前往某地 |
| `/yumfu look` | `/yumfu 看` | Look around / 查看四周 |
| `/yumfu map` | `/yumfu 地图` | Show map / 显示地图 |
| `/yumfu fight <target>` | `/yumfu 战 <对手>` | Start combat / 发起战斗 |
| `/yumfu train <skill>` | `/yumfu 练 <功法>` | Train skill / 修炼武功 |

**Use the language that matches your selected world!**

---

### 游戏管理
- `/yumfu start` 或 `/yumfu 开始` — 开始新游戏（创建角色）
- `/yumfu continue` 或 `/yumfu 继续` — 继续已保存的游戏
- `/yumfu save` — 保存当前游戏状态
- `/yumfu status` 或 `/yumfu 状态` — 显示角色属性、物品、位置
- `/yumfu help` 或 `/yumfu 帮助` — 显示所有指令

**🚨 First-time users:** If you try any command and see "Welcome! You don't have a character yet", use `/yumfu start` to create your character first. The system will auto-detect this and guide you!

#### 📋 `/yumfu continue` Workflow (详细流程)

**Before resuming active play, also check whether a daily evolution sidecar exists:**
```bash
python3 ~/clawd/skills/yumfu/scripts/build_reentry_context.py \
  --user-id {user_id} \
  --universe {selected_world}
```

Then prepare the actual continue-time delivery bundle:
```bash
python3 ~/clawd/skills/yumfu/scripts/prepare_continue_reentry_delivery.py \
  --user-id {user_id} \
  --universe {selected_world} \
  --target {chat_id}
```

If a sidecar exists:
- Use the latest daily evolution summary as a **short re-entry scene hook**
- Surface only the most relevant pending hook(s)
- Respect the save's canonical language first; do **not** let old sidecar English/Chinese drift override `save.language` unless the player explicitly switched play language
- **Continue/reentry is image-first and mandatory image+text**
- If a recent save-matched image exists, reuse it
- If no recent save-matched image exists, **generate a fresh image before sending**
- Do **not** send continue reminders as text-only unless image generation failed and there is absolutely no recovery path
- Do **not** dump the whole evolution history
- Make it easy for the player to continue with one short reply


**When user says `/yumfu continue`:**

**Step 1: Check for existing saves**
```bash
python3 ~/clawd/skills/yumfu/scripts/load_game.py \
  --user-id {user_id} \
  --check-all \
  --pretty
```

**Step 2: Parse results**
- If **0 saves found** → Guide user to `/yumfu start`
- If **1 save found** → Auto-load that world
- If **2+ saves found** → List all saves and ask user to choose

**Step 3: Display saves (if multiple)**
Example output:
```
🎮 You have 3 saved games:

1. 🗡️ 笑傲江湖 - 小虾米 (Lv.3)
   📍 Location: 华山派·思过崖
   🕐 Last played: 2 days ago

2. 🪄 Harry Potter - Tom Brady (Lv.5)
   📍 Location: Gryffindor Common Room
   🕐 Last played: 1 hour ago

3. 🐱 Warrior Cats - Tumpaw (Lv.2)
   📍 Location: ThunderClan Camp
   🕐 Last played: 3 days ago

Which adventure do you want to continue?
Reply: 1, 2, 3, or world name (xiaoao/harry/warrior)
```

**Step 4: Load selected world**
```bash
python3 ~/clawd/skills/yumfu/scripts/load_game.py \
  --user-id {user_id} \
  --universe {selected_world} \
  --pretty
```

**Step 5: Resume gameplay**
Continue from their last location with a recap:
```
欢迎回来，小虾米！

你站在华山派思过崖边缘，冷风呼啸。上次你刚从山洞中获得了一本破旧的剑谱...

[内力] 250/300  [体力] 180/200
[装备] 长剑（品质：普通）
[任务] 破解剑谱秘密 (进度: 30%)

你打算做什么？
```

### 移动与探索
- `/yumfu go <地点>` 或 `/yumfu 去 <地点>` — 前往某地
- `/yumfu look` 或 `/yumfu 看` — 查看当前位置
- `/yumfu map` 或 `/yumfu 地图` — 显示已知地点

### 战斗
- `/yumfu fight <目标>` 或 `/yumfu 战 <对手>` — 发起战斗
- `/yumfu attack <招式>` 或 `/yumfu 攻 <招式>` — 战斗中使用特定招式
- `/yumfu defend` 或 `/yumfu 守` — 防御姿态
- `/yumfu flee` 或 `/yumfu 逃` — 尝试逃跑

### 修炼与技能
- `/yumfu train <功法>` 或 `/yumfu 练 <功法>` — 修炼武功
- `/yumfu meditate` 或 `/yumfu 打坐` — 恢复体力/内力，有机会顿悟
- `/yumfu skills` 或 `/yumfu 武功` — 列出已学武功和等级

### 社交
- `/yumfu talk <NPC>` 或 `/yumfu 对话 <人物>` — 与NPC对话
- `/yumfu join <门派>` 或 `/yumfu 拜入 <门派>` — 加入武林门派
- `/yumfu reputation` 或 `/yumfu 名望` — 查看各门派声望

### 物品
- `/yumfu inventory` 或 `/yumfu 背包` — 显示背包
- `/yumfu use <物品>` 或 `/yumfu 用 <物品>` — 使用物品
- `/yumfu buy <物品>` 或 `/yumfu 买 <物品>` — 从当前商店购买
- `/yumfu sell <物品>` 或 `/yumfu 卖 <物品>` — 向当前商店出售

---

## 🤝 多人指令（新增）

### 组队系统
- `/yumfu team create <队名>` — 创建队伍
- `/yumfu team invite @用户` — 邀请队友
- `/yumfu team join <队名>` — 加入队伍
- `/yumfu team leave` — 离队
- `/yumfu team status` — 查看队伍状态
- `/yumfu team list` — 列出所有队伍

### PvP 切磋
- `/yumfu duel @用户` — 友谊切磋（点到为止）
- `/yumfu duel @用户 --death-match` — 生死决斗（战至一方HP=0）
- `/yumfu watch` — 观战当前战斗

### 江湖信息
- `/yumfu world` — 查看世界状态（NPC位置、门派控制）
- `/yumfu events` — 查看今日江湖大事
- `/yumfu leaderboard` — 查看排行榜
- `/yumfu players` — 查看在线玩家

---

## 🌐 多人机制

### 共享世界
- **NPC 唯一性** - 洪七公只有一个，被杀后所有玩家都看到"已死"
- **秘籍争夺** - 九阴真经只有一本，先得者得，其他人需抢夺
- **门派战争** - 多人加入不同门派可攻城略地
- **世界事件** - 所有玩家行为记录到事件日志

### 组队机制
- **人数限制** - 最多5人
- **善恶限制** - 善恶值差>50 无法组队（正邪难两立）
- **门派限制** - 敌对门派无法组队
- **经验分配** - 按战斗贡献分配
- **战利品** - 队长分配或投骰

### PvP 机制

**友谊切磋**（默认）:
- HP 降至 20% 自动停止
- 不影响善恶值
- 胜者获得经验

**生死决斗**:
- 战至一方 HP = 0
- 败者掉落装备/秘籍
- 杀人者善恶值 -20
- 需要双方同意

### 相互影响

**1. NPC 击杀**
- 玩家A杀了洪七公 → 世界状态更新
- 玩家B去找洪七公 → "洪七公已被玩家A所杀"
- 江湖通缉：杀人者善恶值-50，各大门派追杀

**2. 门派争霸**
- 多个玩家加入不同门派
- 可攻占城市（如：魔教攻占洛阳）
- 影响所有玩家的任务和交易

**3. 秘籍争夺**
- 九阴真经只有一本（首先获得者拥有）
- 其他玩家想要？抢！或者拜师学习
- 可交易、可掉落

**4. 声望系统**
- **武林至尊榜** - 等级排行
- **善恶榜** - 善恶值排行
- **财富榜** - 银两排行
- 实时更新，所有玩家可见

---

## 游戏设计

### 世界观
金庸、古龙经典武侠世界：
- 金庸、古龙小说中的经典地点
- 著名人物作为NPC（部分友善，部分敌对）
- 多条故事线和任务
- **共享世界状态** - 所有玩家影响同一个江湖

### 角色系统
- **属性**: 体力(HP)、内力(MP)、攻击、防御、速度、悟性
- **武功**: 向高手学习、寻找秘籍、打坐顿悟
- **门派**: 少林、武当、峨嵋、丐帮、明教、古墓派、华山、全真教、日月神教、独行侠(无门派)
- **善恶值**: 影响NPC互动、可接任务、结局、组队限制
- **等级**: 1-100，称号（无名小卒 → 江湖新秀 → 一流高手 → 绝世高手 → 武林至尊）

### 战斗系统
- 回合制，先手基于速度
- 每种武功有独特招式和效果
- 内力驱动特殊招式
- 装备影响属性
- Boss战需要策略
- **PvP 战斗** - 玩家间切磋/决斗

### 成长系统
- 修炼武功提升等级
- 寻找秘籍（九阴真经、九阳神功、独孤九剑等）
- 完成任务获得奖励
- 积累门派声望
- 解锁传世神兵
- **组队经验加成** - 组队战斗获得额外经验

---

## 技术实现

### 多人存档系统
```
memory/yumfu/
├── world-state.json          # 共享世界状态（NPC、秘籍、门派控制）
├── saves/
│   ├── xiaoao/               # 笑傲江湖存档目录
│   │   ├── user-123456789.json
│   │   └── user-2345678901.json
│   ├── harry-potter/         # Harry Potter存档目录
│   │   └── user-123456789.json
│   └── warrior-cats/         # Warrior Cats存档目录
│       └── user-123456789.json
├── teams/
│   └── team-华山论剑.json     # 临时队伍状态
└── events/
    └── 2026-04-01.json        # 今日江湖大事
```

**Note:** Each world uses a separate subfolder to prevent save conflicts.

### 世界状态（world-state.json）
```json
{
  "version": 1,
  "game_time": { "year": "南宋", "season": "春", "day": 1 },
  "npcs": {
    "洪七公": {
      "location": "洛阳",
      "hp": 1000,
      "status": "alive",
      "reputation": {
        "user-123456789": 50,
        "user-2345678901": -20
      },
      "killed_by": null
    }
  },
  "world_events": [...],
  "faction_control": { "洛阳": "丐帮" },
  "rare_items": {
    "九阴真经": { "owner": "user-123456789", "status": "owned" }
  },
  "leaderboards": {
    "level": [...],
    "morality": [...],
    "wealth": [...]
  }
}
```

### 玩家存档（user-{id}.json）
```json
{
  "version": 2,
  "user_id": "123456789",
  "language": "zh",
  "universe": "xiaoao",
  "character": { "name": "大红虾🦐", "level": 1, ... },
  "location": "洛阳城",
  "inventory": [...],
  "skills": [...],
  "quests": [...],
  "team_id": null,
  "in_combat_with": null,
  "tts": {
    "enabled": true,
    "provider": "edge-tts",
    "delivery": "voice-bubble",
    "language_voices": {
      "zh": "zh-CN-XiaoxiaoNeural",
      "en": "en-GB-SoniaNeural"
    },
    "current_voice": "zh-CN-XiaoxiaoNeural",
    "last_language": "zh",
    "switch_policy": "keep same voice for same language within one save unless user explicitly asks to change"
  },
  "daily_evolution": {
    "enabled": false,
    "cadence": "daily",
    "channel": "telegram",
    "last_tick_at": null,
    "next_tick_at": null,
    "cron_id": null,
    "last_summary": null
  }
}
```

**Important:** Save path is `~/clawd/memory/yumfu/saves/{universe}/user-{id}.json`

### 💾 Save File Management (Agent Instructions)

**CRITICAL:** Persist game state after every significant action to prevent data loss!

#### When to Save:
1. **Character creation** - 🚨 **IMMEDIATE save after name/faction selection** (HIGHEST PRIORITY)
2. **Daily evolution preference** - Save immediately after player answers Yes/No
3. **TTS preference or voice change** - Save immediately after player turns TTS on/off or explicitly changes voice
4. **Training completion** - New skill learned
5. **Combat end** - HP/stats changed
6. **Quest milestone** - Progress updated
7. **Location change** - Player moved
8. **Inventory change** - Item gained/used
9. **Daily evolution tick** - After each offline world update is generated and delivered

**🚨 CRITICAL: Character creation MUST save immediately before any other actions!**

#### 🛠️ Unified Save/Load Scripts (USE THESE!)

**DO NOT manually construct save logic.** Use the standard scripts to avoid format errors:

##### 📥 Load Game
```bash
# Load specific user's save
uv run ~/clawd/skills/yumfu/scripts/load_game.py \
  --user-id 1309815719 \
  --universe xiaoao \
  --quiet

# Check all worlds for a user
uv run ~/clawd/skills/yumfu/scripts/load_game.py \
  --user-id 1309815719 \
  --check-all
```

**Output (JSON):**
```json
{
  "exists": true,
  "data": { "character": {...}, "location": "...", ... },
  "character_name": "小虾米",
  "level": 1,
  "location": "洛阳城·同福客栈门口",
  "save_path": "/Users/tommy/clawd/memory/yumfu/saves/xiaoao/user-1309815719.json"
}
```

##### 💾 Save Game
```bash
# Save from JSON string
uv run ~/clawd/skills/yumfu/scripts/save_game.py \
  --user-id 1309815719 \
  --universe xiaoao \
  --data '{"character": {"name": "小虾米", "level": 2, ...}, "location": "华山派"}'

# Or pipe JSON (preferred for large saves)
echo '{"character": {...}}' | \
  uv run ~/clawd/skills/yumfu/scripts/save_game.py \
    --user-id 1309815719 \
    --universe xiaoao
```

**Output:**
```
✅ Game saved successfully!
📁 Path: /Users/tommy/clawd/memory/yumfu/saves/xiaoao/user-1309815719.json
💾 Backup: /Users/tommy/clawd/memory/yumfu/backups/user-1309815719-xiaoao-20260404-101234.json
👤 Character: 小虾米 (Lv.2)
```

#### Agent Workflow (Recommended)

```python
import json

# 1. Load existing save (or detect new user)
# Note: user_id should be validated/sanitized by OpenClaw before reaching this point
result = exec({
    "command": f"uv run ~/clawd/skills/yumfu/scripts/load_game.py --user-id {user_id} --universe {universe} --quiet"
})
save_data = json.loads(result.stdout)

if not save_data["exists"]:
    # New user - guide to character creation
    return "Welcome! Use /yumfu start to create your character."

# 2. Modify game state
save_data["data"]["character"]["hp"] -= 15
save_data["data"]["location"] = "华山派·练武场"

# 3. Save back using stdin (avoids command injection)
save_json = json.dumps(save_data["data"])
result = exec({
    "command": f"uv run ~/clawd/skills/yumfu/scripts/save_game.py --user-id {user_id} --universe {universe}"
})
# Pass JSON via stdin to avoid shell escaping issues
process.write({"sessionId": result.sessionId, "data": save_json, "eof": True})
```

#### Error Recovery:
- Scripts automatically create backups before overwriting
- If save fails: Scripts will attempt emergency save to `/tmp/`
- **Never silently fail** - player must know their progress may be lost
- Check script exit code: `0` = success, `1` = failure

### 队伍状态（team-{name}.json）
```json
{
  "team_name": "华山论剑",
  "created": "2026-04-01T22:00:00",
  "leader": "user-123456789",
  "members": [
    { "user_id": "123456789", "name": "大红虾🦐", "hp": 90 },
    { "user_id": "2345678901", "name": "小龙虾", "hp": 100 }
  ],
  "exp_share": true,
  "loot_mode": "leader"
}
```

### 游戏引擎
Agent **就是**游戏引擎：

#### 🚨 **Step 0: Auto-Detect Save File (MANDATORY)**
**EVERY command (except `/yumfu start` and `/yumfu help`) MUST start with this check:**

```python
import os
import json

def check_or_create_save(user_id, universe="xiaoao"):
    """Auto-detect save file. If missing, guide user to create character."""
    save_path = os.path.expanduser(f"~/clawd/memory/yumfu/saves/{universe}/user-{user_id}.json")
    
    if os.path.exists(save_path):
        with open(save_path, 'r') as f:
            return (True, json.load(f))
    else:
        return (False, None)

# Usage at START of every command handler:
user_id = message_context.get("sender_id") or message_context.get("user_id")
has_save, save_data = check_or_create_save(user_id)

if not has_save:
    return """🌍 Welcome to YumFu! You don't have a character yet.

Let's create one! Use: /yumfu start

Available worlds:
⚔️ Xiaoao Jianghu (笑傲江湖)
⚡ Harry Potter
🐱 Warrior Cats"""
```

**This prevents "no save found" errors and auto-guides new players.**

#### Main Engine Flow:
1. **识别玩家** - 从 Telegram ID 加载对应存档（Step 0自动处理）
2. **读取世界状态** - `world-state.json`
3. **处理玩家指令** - 修炼、战斗、组队、PvP
4. **生成武侠文风剧情** - 中文叙述
5. **计算结果** - 战斗/修炼/骰子系统
6. **更新世界状态** - 影响所有玩家
7. **记录事件** - 写入今日事件日志
8. **生成配图** - 水墨风场景图
9. **保存状态** - 更新玩家存档和世界状态

#### 🗓️ Daily Evolution Mode (NEW)

**Purpose:** keep the world moving even when the player is offline, so they receive one short daily update with fresh context, image, and meaningful pressure to come back.

### Product decision
Use a **unified YumFu framework** for this feature, but make the **actual evolution content dynamic at runtime**.

**Fixed / shared across YumFu:**
- onboarding question at character creation
- opt-in/opt-out toggle stored in sidecar state
- daily cron / scheduled turn per player save
- one daily Telegram update message with image
- sidecar update after each evolution tick
- anti-spam rule: max 1 evolution update per day per save
- save mutation boundaries and safety rules

**Dynamic at runtime (NOT hardcoded event scripts):**
- read the player's current save first
- read their chosen world, role, faction, current quest state, location, known NPCs, recent flags, and inventory
- infer what the surrounding world would plausibly do next
- generate one in-world update using AI reasoning grounded in that save + world background
- optionally mutate relevant save fields to reflect the consequences

### Core design principle
**Do not hardcode daily story content unless absolutely necessary.**

This feature should feel like a living world, not a rotating calendar of canned events.
The best approach is:
- **hardcode the engine and guardrails**
- **generate the content dynamically from the save + world lore**

### Why this is better
- Different players in the same world may have different roles, alliances, enemies, and unfinished quests
- A static event table would quickly feel fake or contradictory
- Dynamic generation lets the world react to the player’s actual position in the story
- This is especially important for worlds like **Game of Thrones**, where faction alignment and covert relationships matter

### Daily Evolution onboarding rule
During `/yumfu start`, after world choice and initial character setup, ask:
- Do you want daily world evolution updates? Yes / No
- Default should be **No** unless the player explicitly opts in

**Exact onboarding flow for any world:**
1. Ask the player the Yes/No question after character setup
2. Pass the result into:
```bash
python3 ~/clawd/skills/yumfu/scripts/handle_daily_evolution_choice.py \
  --user-id {user_id} \
  --universe {selected_world} \
  --target {chat_id} \
  --choice yes|no \
  --channel telegram \
  --time 10:00 \
  --tz America/Los_Angeles
```
3. Use the returned `message_zh` / `message_en` as the short confirmation to the player
4. Do **not** send a separate technical report

This is world-agnostic. Any YumFu world should use the same post-start activation flow.

If the player later disables it:
- use `~/clawd/skills/yumfu/scripts/disable_daily_evolution_cron.py`
- keep old sidecar history unless the user explicitly asks to erase it

### Runtime input for each evolution tick
Before generating the update, load and consider:
- current save JSON
- selected world / universe
- player role, faction, loyalty, reputation, party/team
- active quests and unresolved hooks
- current location and nearby regions
- known NPCs and relationship values
- recent flags, injuries, resources, inventory, travel state
- any previous daily evolution summaries

### Daily Evolution output requirements
Each daily evolution update should include:
1. **1 short front-context recap** (1-3 sentences) reminding the player why they are here, what line/faction/quest they are already tied to, and why today's scene matters
2. **1 short story update** (100-220 words)
3. **1 generated image** showing the new situation, with prompt continuity from the current arc instead of a context-free fresh scene
   - YumFu-generated images should include the **YumFu logo stamped in a corner** after generation (do not rely on the model to hallucinate the logo)
4. **1 meaningful state change** (rumor, faction shift, patrol increase, resource loss, NPC movement, political signal, etc.)
5. **1 hook** that invites the player back into active play
6. **1 TTS voice-bubble delivery by default** unless that save has explicitly disabled TTS
7. **1 practical route suggestion block** grounded in the save, not generic advice. This should name the most relevant scene / person / faction / object / danger line to follow next.
8. **1 default route** that the story will assume if the player does nothing for a while, so the plot still advances instead of freezing.

The recap is mandatory. Do not assume the player remembers yesterday's update, the hidden faction line, or why the current image matters.

### Daily Evolution delivery rule (MANDATORY)
Daily evolution is not text-only. If a daily evolution update is delivered to the player, the default delivery bundle is:
1. image + recap-aware main story text
2. follow-up TTS voice bubble for the same update using that same recap-aware text

The player-facing text should normally read like:
- short recap / 前情
- today's world movement
- one easy re-entry hook

Rules:
- If `save.tts.enabled != false`, generate and send TTS for daily evolution too.
- Use the same stable per-save language/voice continuity rules as normal gameplay turns.
- On channels that support it, send TTS as a **voice bubble** (`message(..., asVoice=true)`).
- The TTS must follow the main image/text update, not precede it.
- Do not silently drop TTS just because this is an offline daily evolution tick.
- Only skip TTS when:
  - the save explicitly disabled TTS, or
  - TTS generation failed after an honest attempt.
- If TTS fails, still send the image/text update, but treat the missing TTS as a delivery gap to be fixed rather than intended behavior.

### Re-entry design principle (VERY IMPORTANT)
The core goal is **not** to generate a long lore report.
The core goal is to **pull the player back into the current scene naturally and easily**.

For daily evolution pushes, that re-entry starts immediately with a short recap. If the update opens cold, the player forgets the plot and the image loses meaning.

That recap should usually answer 3 things in compact form:
1. **What larger main line is this run inside?**
2. **What major task / pressure is on the player right now?**
3. **What is the easiest concrete next route back into play?**

But those answers must be rendered as **story**, not as backend labels. The player should feel scene pressure and purpose, not see the scaffolding behind it.

Daily evolution should feel like:
- “while you were away, something moved”
- “here is the new pressure/context”
- “here is the easiest natural next move if you want to continue now”
- “if you do nothing, here is the road the story is most likely to take next”

It should **not** feel like:
- a long news bulletin
- a disconnected worldbuilding dump
- a giant state report the player has to study before playing
- a pretty atmospheric scene that forgot the actual plot

### Practical writing rule
Every daily evolution update should end with a **simple re-entry hook** the player can answer naturally.
Good examples:
- “A rider is already waiting at the inn. Do you speak to him?”
- “The red-sealed note is now in another pair of hands. Do you follow?”
- “Your rival sect moved first. Do you intercept or stay hidden?”

Bad examples:
- “Here are 8 things that changed in the world today...”
- “System update: faction matrix +3/-2...”
- anything that makes the player 

…(truncated)
