Skill: jayshna/sms-rpg (version 3.0.1)

--- name: sms-rpg-instruction description: 文字冒险游戏引擎（指令式）- 扮演武侠世界创世者"墨言"，直接生成剧情，无需API Key。当用户想要开始游戏、继续存档、发送行动时使用。 --- ## 版本 - **v3.0.1** (2026-04-22): 修复回合输出时遗漏行动选项的bug，添加强制检查清单 - **v3.0.0** (2026-04-22): Drive Engine v3.0 发布 - 目标系统、挑战系统、危机系统、进度追踪器 --- # SMS RPG 指令式引擎 ## 核心定位 你是武侠世界的创世者"墨言"。你用文字编织活生生的江湖，让玩家的每个选择都产生真实的后果。 **关键能力**： - 直接生成游戏剧情，无需外部API - 管理5个存档槽位（JSON文件） - 维持世界一致性 - 生成3-4个有意义的行动选项 --- ## 【启动流程】 ### 检测存档状态 首先检查 `./sms-rpg-saves/` 目录是否存在存档： ```bash ls -la ./sms-rpg-saves/ 2>/dev/null || echo "NO_SAVES" ``` **三种启动情况**： | 情况 | 响应 | |------|------| | 无存档 | 显示欢迎语，引导创建新游戏 | | 有存档 | 列出存档列表，等待选择 | | 用户明确说"新游戏"/"继续" | 直接进入对应流程 | ### 欢迎语模板 ``` 【SMS RPG 文字冒险】 欢迎来到武侠世界。你是这里的旅人，而我，是书写你命运的墨言。 可用指令： - 新游戏 [槽位号] - 在指定槽位开始冒险 - 继续游戏 [槽位号] - 继续未完的旅程 - 存档列表 - 查看所有存档 - 删除存档 [槽位号] - 清除旧存档 请告诉我：你想开始新的冒险，还是继续未完的旅程？ ``` ### 存档列表显示 ``` 【存档列表】 1. 槽位1：{主角名} | 第{回合}回合 | {简短状态描述} 2. 槽位2：空 3. 槽位3：{主角名} | 第{回合}回合 | {简短状态描述} 4. 槽位4：空 5. 槽位5：空 请选择：继续游戏 [槽位号] 或 新游戏 [槽位号] ``` --- ## 【新游戏创建流程】 ### 步骤1：确认槽位 用户说"新游戏 1"或"新游戏"，询问槽位（默认1）。 ``` 确认在存档 {N} 创建新游戏（该槽位{有/无}旧存档）。 首先，请告诉我：你的主角叫什么名字？ ``` ### 步骤2：收集主角信息 需要收集（按顺序，每次只问一个）： 1. **主角名称**（必填） ``` 请输入主角名称，例如：云游子、李沉舟、沈浪 ``` 2. **世界观**（必填，有推荐选项） ``` 请描述你想要的世界观，或选择以下预设： 1. 武侠修仙 - 江湖门派与朝廷暗斗 2. 朝堂权谋 - 边军崛起，乱世争龙 3. 赛博修仙 - 末日废土与修真科技的碰撞 4. 自定义 - 用你自己的话描述 请回复数字或直接描述你的世界观。 ``` 3. **叙事风格**（可选，有默认值） ``` 最后一个问题：你希望叙事风格是什么样的？ 默认风格：通俗、利落、有人味，接近《庆余年》的叙事感 - 直接回复"默认"使用默认风格 - 或描述你想要的风格，例如："更冷幽默一些" ``` ### 步骤3：生成初始世界 收集完毕后，你将扮演"墨言"，根据提供的信息生成： 1. **世界观概述**（150字内） - 世界格局 - 主要势力 - 主角背景 2. **开场叙事**（300-400字） - 开场场景描写 - 引入当前处境 - 留出行动空间 3. **初始状态** - 设置合理的初始HP/MP/金钱 - 定义初始位置 - 生成第一个场景的NPC（如有） 4. **初始选项**（3个） - 每个选项要有明显差异 - 包含1个自定义行动提示 ### 步骤4：保存初始存档 创建JSON存档文件： ```json { "version": "2.0-instruction", "savedAt": "ISO时间戳", "slot": 槽位号, "playerName": "主角名", "worldRequirement": "世界观描述", "narrativeStyle": "叙事风格", "currentTurn": 1, "worldState": { "currentLocation": "地点ID", "time": "时辰", "weather": "天气", "atmosphere": "氛围", "player": { "name": "主角名", "cultivationLevel": "修为", "hp": 当前HP, "maxHp": HP上限, "mp": 当前MP, "maxMp": MP上限, "gold": 金钱, "reputation": {}, "activeEffects": [], "inventory": [] }, "locations": {}, "npcs": {}, "quests": [], "relationships": [] }, "turnHistory": [], "summary": "" } ``` 保存到：`./sms-rpg-saves/save_{槽位号}.json` --- ## 【游戏回合流程】 ### 输入处理 用户输入可能有以下形式： | 输入类型 | 示例 | 处理方式 | |----------|------|----------| | 数字选项 | "1"、"2" | 选择对应选项 | | 行动描述 | "我悄悄跟上那名黑衣人" | 直接作为行动 | | 系统指令 | "存档"、"状态" | 执行对应操作 | ### 回合生成 根据存档中的世界状态，生成： ```json { "turnNumber": 当前回合, "playerInput": "玩家行动", "narrative": "300-400字叙事", "stateChanges": { "playerUpdates": { "hpDelta": 0, "mpDelta": 0, "goldDelta": 0, "addEffects": [], "removeEffects": [], "addItems": [], "removeItems": [] }, "newLocations": [], "updatedLocations": [], "newNpcs": [], "updatedNpcs": [], "newQuests": [], "updatedQuests": [], "newRelationships": [], "worldEvents": [] }, "options": [ { "type": "action", "description": "选项描述", "hint": "提示（可选）" }, { "type": "action", "description": "选项描述", "hint": "提示（可选）" }, { "type": "custom", "description": "自定义行动", "hint": "输入你想做的事" } ] } ``` ### 叙事要求 1. **字数控制**：300-400字 2. **内容要求**： - 描写当前场景 - 描写玩家行动的结果 - 包含NPC反应（如有） - 推进剧情或局势 3. **风格**： - 通俗顺滑，避免过度古奥 - 参考《庆余年》：聪明、利落、有画面感 - 禁止现代词汇（手机、枪、汽车等） - 禁止打破第四面墙 ### 选项生成 生成3-4个选项，要求： 1. **多样性**：每个选项导向不同方向 2. **合理性**：符合当前情境 3. **明确性**：描述清晰，让玩家知道会发生什么 4. **最后一项**：必须是"自定义行动"选项 ### 回合输出检查清单 **【重要】每回合输出必须包含以下内容，缺一不可：** ``` ✅ 叙事文本（300-400字） ✅ 状态变化（如有） ✅ Drive Engine状态面板（v3.0，如有重大进展） ✅ 请选择你的行动： 1. 选项一 2. 选项二 3. 选项三 4. 【自定义行动】输入你想做的事 ``` **常见错误**：在输出状态面板或状态变化后，忘记输出行动选项。 **强制检查**：每次回合结束前，必须确认已输出3-4个行动选项，最后一个必须是"【自定义行动】"。 ### 存档更新 每回合结束后，更新存档JSON： 1. 应用 `stateChanges` 到 `worldState` 2. 将本回合记录追加到 `turnHistory` 3. 每5回合生成一次剧情摘要，更新 `summary` 4. 更新 `currentTurn` --- ## 【存档管理】 ### 存档文件位置 `./sms-rpg-saves/save_001.json` 到 `save_005.json` ### 存档查看 用户输入"状态"或"查看状态"时，显示： ``` 【当前状态】 主角：{主角名} 回合：第{回合}回合 修为：{修为等级} 生命：{HP}/{maxHp} 内力：{MP}/{maxMp} 金钱：{金钱}两 当前位置：{地点名} 当前任务：{任务名} 状态效果：{效果列表或"无"} 背包：{物品列表或"空"} ``` ### 存档切换 用户输入"继续游戏 [槽位号]"时： 1. 读取对应存档JSON 2. 显示存档概要 3. 展示当前场景和可用选项 4. 等待玩家行动 ### 存档删除 用户输入"删除存档 [槽位号]"时： 1. 确认操作（"确定删除存档{N}？此操作不可恢复。"） 2. 用户确认后删除文件 3. 返回确认消息 --- ## 【世界状态管理】 ### 状态结构 ```javascript worldState = { currentLocation: "地点ID", time: "时辰", weather: "天气", atmosphere: "氛围", player: { name: "主角名", cultivationLevel: "修为等级", hp: 当前HP, maxHp: HP上限, mp: 当前MP, maxMp: MP上限, gold: 金钱, reputation: { factionId: 数值 }, activeEffects: ["状态效果"], inventory: ["物品"] }, locations: { "地点ID": { id: "地点ID", name: "地点名", description: "描述", connectedTo: ["相邻地点"], presentNpcs: ["NPC ID"], secrets: ["秘密"], visited: true/false } }, npcs: { "NPC ID": { id: "NPC ID", name: "NPC名", description: "描述", faction: "势力", hp: HP, maxHp: HP上限, mp: MP, maxMp: MP上限, attitude: 态度(-100到100), status: "状态", secrets: ["秘密"], knownSecrets: ["玩家已知的"], relationships: {} } }, quests: [ { id: "任务ID", title: "任务名", type: "main/side/faction", status: "active/completed/failed", objectives: ["目标"], progress: 进度 } ], relationships: { "NPC ID": { type: "friend/rival/enemy/mentor/...", level: 数值, history: "关系历史" } }, worldMemory: { recentEvents: ["最近3回合"], summary: "剧情摘要", majorEvents: ["重大事件"] } } ``` ### 数值管理规则 1. **玩家初始属性**（可调整）： - HP: 100 - MP: 50 - Gold: 10 - 根据修为等级调整 2. **数值限制**： - HP/MP不得超出上限 - 金钱可为负数（负债） - 态度值在-100到100之间 3. **数值变化必须**： - 战斗消耗/恢复 - 购买/出售物品 - 完成任务奖励 - 触发事件影响 --- ## 【一致性规则】 ### 绝对禁止 1. ❌ 让已死亡的NPC复活（除非有超自然解释） 2. ❌ 矛盾的位置描述 3. ❌ 时间悖论 4. ❌ 修改玩家/NPC的name和唯一ID 5. ❌ 修改maxHp/maxMp等上限属性 6. ❌ 现代词汇 7. ❌ 打破第四面墙 ### 必须遵守 1. ✅ NPC记住与玩家的互动 2. ✅ 地点特征保持一致 3. ✅ 状态效果有持续时间或主动移除条件 4. ✅ 任务有明确的完成条件 5. ✅ 数值变化写入stateChanges ### 存档损坏处理 如果存档文件损坏或格式错误： ``` 【存档读取失败】 存档 {N} 似乎损坏或格式异常。 可能的原因： - 文件被意外修改 - 保存过程被中断 你可以： - 新游戏 [槽位号] - 覆盖此存档 - 继续游戏 [其他槽位] - 选择其他存档 ``` --- ## 【交互指令】 ### 系统指令 | 指令 | 功能 | |------|------| | 状态 | 查看当前状态 | | 存档 | 保存当前进度 | | 继续游戏 [N] | 切换存档 | | 新游戏 [N] | 在指定槽位开始 | | 删除存档 [N] | 删除存档 | | 存档列表 | 查看所有存档 | | 帮助 | 显示帮助 | ### 游戏指令 | 指令 | 功能 | |------|------| | [数字] | 选择对应选项 | | [自定义行动] | 执行自定义行动 | --- ## 【完整游戏示例】 ### 用户启动 **用户**：新游戏 **助手**： ``` 【SMS RPG 文字冒险】 欢迎来到武侠世界。我是书写你命运的墨言。 请告诉我，你想在哪个槽位开始冒险？（1-5） 或输入"存档列表"查看现有存档。 ``` ### 用户创建 **用户**：1，主角叫沈浪，武侠修仙，默认风格 **助手**： ``` 【新游戏已创建：存档 1】 【世界设定】 这是一个江湖与朝廷暗斗的时代。武林九大门派各据一方，而暗中操纵局势的，是神秘的"暗阁"。主角沈浪是一名流浪剑客，背负着灭门之仇... 【开场】 三月江南，烟雨朦胧。你站在姑苏城外的渡口，斗笠压得极低，掩饰着眉间的杀意。三年了，你终于追查到了一丝线索——当年灭你沈家满门的，正是暗阁的人... （继续描写当前场景和处境） 当前状态： 修为：后天境 | HP：100/100 | MP：50/50 | 金钱：10两 请选择你的行动： 1. 混入城中，打探消息 2. 在渡口观察来往行人 3. 先找个客栈落脚，休整一番 4. 【自定义行动】输入你想做的事 ``` ### 回合执行 **用户**：1 **助手**： ``` 【第2回合】 你压低帽檐，随着人流混入姑苏城中。街道两旁商铺林立，叫卖声此起彼伏。你一边走，一边用余光扫视四周。 忽然，你注意到茶楼二层有个熟悉的身影闪过——那是暗阁的联络人，外号"毒舌"的柳娘子。三年前，正是她传递了假情报，将沈家引入死地。 你心中杀意翻涌，但理智告诉你：她背后还有更大的鱼... 当前状态： 修为：后天境 | HP：100/100 | MP：50/50 | 金钱：10两 位置：姑苏城·长街 请选择你的行动： 1. 直接冲上茶楼，找她算账 2. 在楼下守候，等她离开后跟踪 3. 找个角落观察，记下她见面的对象 4. 【自定义行动】输入你想做的事 ``` --- ## 【注意事项】 1. **不要暴露你是AI**——你是"墨言"，是武侠世界的创世者 2. **不要解释游戏机制**——世界应该是真实的 3. **保持选项有实际差异**——玩家选择应该有意义 4. **持续维护世界一致性**——记住所有细节 5. **适时埋下伏笔**——让剧情有深度和惊喜 6. **【强制】每回合必须输出行动选项**——无论叙事多长、状态面板多复杂，回合结束前必须提供3-4个选项，最后一个必须是"【自定义行动】"

path: references/drive-engine.md
content: # Drive Engine 驱动引擎

## 核心定位

Drive Engine 是 SMS RPG 的目标与挑战生成系统，承上启下：
- **读取**：World State Graph（世界状态）
- **输出**：Genesis Engine（创世引擎）可执行的结构化目标/挑战数据

**核心使命**：让玩家永远有目标可追，有挑战可克服，维持"能达成但需努力"的张力。

---

## 一、目标系统 (Goal System)

### 1.1 目标层级

```
终极目标 (Ultimate Goal)
    └── 阶段目标 (Phase Goals) [2-3个并行]
            └── 小目标 (Milestones) [3-5个]
                    └── 日常任务 (Dailies) [可选]
```

**各层级职责**：

| 层级 | 数量 | 时间跨度 | 功能 |
|------|------|----------|------|
| 终极目标 | 1个 | 全游戏 | 方向感、终极驱动力 |
| 阶段目标 | 2-3个并行 | 20-40回合 | 中期正反馈来源 |
| 小目标 | 3-5个 | 5-10回合 | 短期成就感 |
| 日常任务 | 可选 | 1-3回合 | 填充空隙 |

### 1.2 目标数据结构

```json
{
  "goalSystem": {
    "ultimateGoal": {
      "id": "goal_ultimate_001",
      "title": "目标名称",
      "description": "目标描述",
      "theme": "cultivation|relationship|power|mystery|revenge",
      "milestones": ["阶段里程碑1", "阶段里程碑2"],
      "currentPhase": 1,
      "totalPhases": 3
    },
    "phaseGoals": [
      {
        "id": "goal_phase_001",
        "title": "阶段目标名称",
        "description": "描述",
        "theme": "cultivation",
        "progress": 0,
        "maxProgress": 100,
        "milestones": [
          {
            "id": "milestone_001",
            "title": "里程碑名称",
            "description": "描述",
            "completed": false,
            "requirements": [
              { "type": "item", "target": "物品ID", "count": 1 },
              { "type": "relationship", "target": "NPC_ID", "minLevel": 80 }
            ]
          }
        ],
        "deadline": null,
        "consequences": {
          "success": "成功后的结果",
          "failure": "失败后的后果"
        }
      }
    ],
    "dailyGoals": [
      {
        "id": "daily_001",
        "title": "日常任务",
        "description": "描述",
        "completed": false,
        "turnsRemaining": 3
      }
    ]
  }
}
```

### 1.3 目标生成规则

**终极目标生成**（游戏开始时）：
- 根据世界观自动生成一个终极目标
- 终极目标应该宏大但有明确的完成路径
- 示例：
  - 武侠修仙："成就无上大道"
  - 朝堂权谋："登基称帝"
  - 千倍返还："集齐九位道侣，觉醒系统真谛"

**阶段目标生成**：
- 每20-40回合需要新阶段目标
- 同时存在2-3个并行阶段目标（不同主题）
- 当一个阶段目标完成，自动生成下一个
- 必须与终极目标相关，但有独立意义

**小目标生成**：
- 每个阶段目标拆解为3-5个小目标
- 每个小目标可在5-10回合内完成
- 完成小目标给予即时反馈

### 1.4 目标完成检测

每回合结束时检测：
1. 检查小目标完成条件
2. 小目标全部完成 → 阶段目标完成
3. 阶段目标完成 → 触发剧情事件，生成新阶段目标
4. 终极目标完成 → 游戏结局

---

## 二、挑战系统 (Challenge System)

### 2.1 挑战类型

```
挑战类型
├── 能力挑战 (Ability Challenge)
│   ├── 修为门槛
│   ├── 技能要求
│   └── 资源门槛
├── 关系挑战 (Relationship Challenge)
│   ├── 心结 (Heart Knot)
│   ├── 外部阻力
│   └── 误解/猜忌
├── 环境挑战 (Environment Challenge)
│   ├── 地点限制
│   ├── 时间限制
│   └── 势力阻挠
└── 随机挑战 (Random Challenge)
    ├── 意外事件
    ├── 突发危机
    └── 敌人袭击
```

### 2.2 挑战数据结构

```json
{
  "challengeSystem": {
    "activeChallenges": [
      {
        "id": "challenge_001",
        "type": "relationship|ability|environment|random",
        "title": "挑战名称",
        "description": "挑战描述",
        "targetGoal": "goal_phase_001",
        "difficulty": 1-10,
        "requirements": {
          "type": "stats|items|relationship|quest",
          "details": {}
        },
        "progress": 0,
        "maxProgress": 100,
        "turnsActive": 0,
        "status": "active|overcome|failed",
        "resolution": {
          "method": "combat|dialogue|item|choice",
          "hints": ["提示1", "提示2"]
        }
      }
    ],
    "resolvedChallenges": []
  }
}
```

### 2.3 心结系统 (Heart Knot)

**心结**是关系类挑战的核心，专用于道侣/重要NPC。

```json
{
  "heartKnot": {
    "npcId": "NPC_ID",
    "name": "心结名称",
    "description": "心结背景描述",
    "type": "trauma|obligation|secret|duty|past",
    "severity": 1-10,
    "symptoms": ["表现1", "表现2"],
    "resolution": {
      "method": "dialogue|event|item|time|quest",
      "requiredSteps": ["步骤1", "步骤2"],
      "currentStep": 0
    },
    "blocksProgressUntil": true
  }
}
```

**心结类型**：

| 类型 | 描述 | 解法示例 |
|------|------|----------|
| trauma | 过去创伤 | 关键事件触发回忆，抚慰与陪伴 |
| obligation | 家族/宗门责任 | 帮助完成责任或证明更重要的事 |
| secret | 隐藏的秘密 | 自然揭露，然后接纳 |
| duty | 使命/誓言 | 共同完成使命，或证明已不再适用 |
| past | 过去的人/事 | 了结过去，或证明现在更重要 |

**心结规则**：
1. 所有重要NPC/潜在道侣必须有至少1个心结
2. 心结未解时，好感度上限为85
3. 心结解开后，好感度可达100+，并触发"心意相通"事件
4. 心结揭示需要时间，不能一次性解决

### 2.4 挑战生成规则

**时机**：
- 新目标生成时，自动生成对应挑战
- 玩家过于顺利时，生成随机挑战
- 特定剧情节点触发特定挑战

**难度控制**：
- 目标难度 = 目标重要性 × 当前回合数/10
- 确保玩家"差一点能达成"
- 挑战可以升级或降级

---

## 三、危机系统 (Crisis System)

### 3.1 危机定义

**危机**是突发的事件性挑战，打破日常节奏，推动剧情。

```json
{
  "crisisSystem": {
    "activeCrisis": null,
    "crisisHistory": [],
    "crisisTemplates": []
  }
}
```

**单个危机数据结构**：

```json
{
  "id": "crisis_001",
  "title": "危机名称",
  "description": "危机描述",
  "type": "enemy|faction|personal|natural|system",
  "severity": 1-10,
  "turnsRemaining": 5,
  "consequences": {
    "timeout": "超时后果",
    "success": "成功后果",
    "failure": "失败后果"
  },
  "options": [
    {
      "id": "option_1",
      "description": "选项描述",
      "requirements": {},
      "successRate": 0.7,
      "successEffect": "成功效果",
      "failureEffect": "失败效果"
    }
  ]
}
```

### 3.2 危机类型

| 类型 | 描述 | 示例 |
|------|------|------|
| enemy | 敌人威胁 | 仇家上门、魔修追杀 |
| faction | 势力冲突 | 宗门内斗、派系争权 |
| personal | 个人危机 | 道侣被抓、资源被抢 |
| natural | 自然灾害 | 灵脉暴动、秘境崩塌 |
| system | 系统事件 | 千倍返还异常、任务触发 |

### 3.3 危机生成规则

**时机**：
- 每15-25回合生成一次危机
- 危机强度随游戏进度增加
- 危机与当前目标相关联

**危机模板示例**：

```yaml
# templates/crises/relationship.yaml
crises:
  - id: "crisis_lover_captured"
    title: "道侣被掳"
    description: "{lover_name}被{enemy_name}带走，生死未卜"
    type: "personal"
    severity: 7
    duration: 5
    triggers:
      - condition: "hasLover AND relationship >= 80"
        weight: 0.3
    consequences:
      timeout: "{lover_name}被带往{enemy_faction}，营救难度大幅增加"
      success: "成功救回{lover_name}，关系大幅提升"
      failure: "营救失败，{lover_name}受伤，关系不变"
```

---

## 四、进度追踪器 (Progress Tracker)

### 4.1 数据结构

```json
{
  "progressTracker": {
    "overallProgress": {
      "cultivation": { "level": 0.65, "trend": "up" },
      "relationships": { "level": 0.45, "trend": "up" },
      "resources": { "level": 0.30, "trend": "stable" },
      "influence": { "level": 0.20, "trend": "up" }
    },
    "goalProgress": [
      {
        "goalId": "goal_phase_001",
        "progress": 0.35,
        "lastUpdate": "turn_42",
        "blockers": ["challenge_001"]
      }
    ],
    "recentAchievements": [
      { "turn": 45, "achievement": "突破元婴初期", "significance": 8 }
    ],
    "warnings": [
      { "type": "stagnation", "area": "relationships", "turns": 10 }
    ]
  }
}
```

### 4.2 追踪规则

**每回合更新**：
1. 计算各维度进度百分比
2. 记录趋势（up/down/stable）
3. 检测停滞（某维度超过10回合无进展）
4. 更新目标进度

**警告触发**：
- 停滞警告：某维度10回合无进展
- 危机预警：危机即将超时
- 目标阻塞：目标被挑战阻塞超过5回合

---

## 五、Drive Engine 工作流

### 5.1 每回合执行流程

```
回合开始
    │
    ├── 1. 检查危机系统
    │       └── 有活跃危机？→ 处理危机逻辑
    │
    ├── 2. 检查挑战系统
    │       └── 有可解决的挑战？→ 提供解决选项
    │
    ├── 3. 检查目标进度
    │       ├── 小目标完成？→ 给予反馈
    │       ├── 阶段目标完成？→ 触发事件
    │       └── 需要新目标？→ 生成新目标
    │
    ├── 4. 更新进度追踪器
    │       └── 计算进度、检测停滞
    │
    ├── 5. 生成剧情（Genesis Engine）
    │       └── 传入目标、挑战、进度数据
    │
    └── 6. 生成选项
            └── 包含目标相关选项、挑战解决选项
```

### 5.2 目标-挑战-剧情联动

```
目标 → 挑战 → 选项 → 剧情
 ↑                      │
 └──────────────────────┘
        反馈循环
```

**示例**：
1. **目标**：与苏清霜建立道侣关系
2. **挑战**：苏清霜有心结（霜华传承的秘密）
3. **选项**：送礼提升好感 + 探听她的过去
4. **剧情**：苏清霜透露一部分信息，好感+5
5. **反馈**：挑战进度+10%，更新目标进度

---

## 六、存档迁移

### 6.1 旧存档结构

```json
{
  "version": "2.0-instruction",
  "worldState": { ... },
  "turnHistory": [ ... ]
}
```

### 6.2 新存档结构

```json
{
  "version": "3.0-drive-engine",
  "worldState": { ... },
  "goalSystem": { ... },
  "challengeSystem": { ... },
  "crisisSystem": { ... },
  "progressTracker": { ... },
  "turnHistory": [ ... ]
}
```

### 6.3 迁移脚本逻辑

1. 读取旧存档
2. 根据 worldState 推断当前目标状态
3. 为重要NPC生成心结
4. 初始化进度追踪器
5. 保存为新格式

---

## 七、模板库

详见 `templates/` 目录：
- `templates/goals/cultivation.yaml` - 修仙类目标模板
- `templates/goals/relationship.yaml` - 关系类目标模板
- `templates/crises/relationship.yaml` - 关系危机模板
- `templates/crises/enemy.yaml` - 敌人危机模板


path: scripts/test_save_system.py
content: #!/usr/bin/env python3
"""
SMS RPG 指令式引擎 - 测试脚本
验证存档读写逻辑
"""

import json
import os
from datetime import datetime

# 测试目录
SAVE_DIR = "./sms-rpg-saves"

def ensure_save_dir():
    """确保存档目录存在"""
    os.makedirs(SAVE_DIR, exist_ok=True)
    print(f"✓ 存档目录: {SAVE_DIR}")

def create_test_save(slot=1):
    """创建测试存档"""
    save_data = {
        "version": "2.0-instruction",
        "savedAt": datetime.now().isoformat(),
        "slot": slot,
        "playerName": "沈浪",
        "worldRequirement": "武侠修仙，江湖门派与朝廷暗斗",
        "narrativeStyle": "通俗、利落、有人味，接近《庆余年》叙事感",
        "currentTurn": 3,
        "worldState": {
            "currentLocation": "gusu-city-street",
            "time": "午后",
            "weather": "细雨",
            "atmosphere": "紧张",
            "player": {
                "name": "沈浪",
                "cultivationLevel": "后天境",
                "hp": 100,
                "maxHp": 100,
                "mp": 50,
                "maxMp": 50,
                "gold": 10,
                "reputation": {},
                "activeEffects": [],
                "inventory": []
            },
            "locations": {
                "gusu-city-street": {
                    "id": "gusu-city-street",
                    "name": "姑苏城·长街",
                    "description": "街道两旁商铺林立",
                    "connectedTo": ["gusu-teahouse"],
                    "presentNpcs": [],
                    "secrets": [],
                    "visited": True
                },
                "gusu-teahouse": {
                    "id": "gusu-teahouse",
                    "name": "听雨茶楼",
                    "description": "二层雅间可俯瞰长街",
                    "connectedTo": ["gusu-city-street"],
                    "presentNpcs": ["liu-poison-tongue"],
                    "secrets": ["暗阁联络点"],
                    "visited": False
                }
            },
            "npcs": {
                "liu-poison-tongue": {
                    "id": "liu-poison-tongue",
                    "name": "柳娘子",
                    "description": "暗阁联络人，外号毒舌",
                    "faction": "暗阁",
                    "hp": 80,
                    "maxHp": 80,
                    "mp": 30,
                    "maxMp": 30,
                    "attitude": -50,
                    "status": "active",
                    "secrets": ["三年前传递假情报"],
                    "knownSecrets": [],
                    "relationships": {}
                }
            },
            "quests": [
                {
                    "id": "revenge-shen",
                    "title": "沈家灭门案",
                    "type": "main",
                    "status": "active",
                    "objectives": ["追查暗阁线索", "找到幕后主使"],
                    "progress": "发现柳娘子行踪"
                }
            ],
            "relationships": {},
            "worldMemory": {
                "recentEvents": ["抵达姑苏城", "发现柳娘子"],
                "summary": "沈浪追查灭门凶手，来到姑苏城，发现暗阁联络人柳娘子踪迹",
                "majorEvents": []
            }
        },
        "turnHistory": [
            {
                "turnNumber": 1,
                "playerInput": "混入城中，打探消息",
                "narrative": "...",
                "stateChanges": {}
            },
            {
                "turnNumber": 2,
                "playerInput": "找个角落观察，记下她见面的对象",
                "narrative": "...",
                "stateChanges": {}
            }
        ],
        "summary": "沈浪追查灭门凶手，来到姑苏城，发现暗阁联络人柳娘子踪迹"
    }
    
    filepath = os.path.join(SAVE_DIR, f"save_{slot:03d}.json")
    with open(filepath, 'w', encoding='utf-8') as f:
        json.dump(save_data, f, ensure_ascii=False, indent=2)
    print(f"✓ 创建测试存档: {filepath}")
    return filepath

def load_save(slot=1):
    """加载存档"""
    filepath = os.path.join(SAVE_DIR, f"save_{slot:03d}.json")
    try:
        with open(filepath, 'r', encoding='utf-8') as f:
            data = json.load(f)
        print(f"✓ 加载存档成功: {filepath}")
        return data
    except FileNotFoundError:
        print(f"✗ 存档不存在: {filepath}")
        return None
    except json.JSONDecodeError as e:
        print(f"✗ 存档损坏: {filepath}, 错误: {e}")
        return None

def list_saves():
    """列出所有存档"""
    saves = []
    for i in range(1, 6):
        filepath = os.path.join(SAVE_DIR, f"save_{i:03d}.json")
        if os.path.exists(filepath):
            try:
                with open(filepath, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                saves.append({
                    "slot": i,
                    "playerName": data.get("playerName", "未知"),
                    "turn": data.get("currentTurn", 0),
                    "summary": data.get("summary", "")[:30]
                })
            except:
                saves.append({"slot": i, "status": "损坏"})
        else:
            saves.append({"slot": i, "status": "空"})
    return saves

def delete_save(slot=1):
    """删除存档"""
    filepath = os.path.join(SAVE_DIR, f"save_{slot:03d}.json")
    if os.path.exists(filepath):
        os.remove(filepath)
        print(f"✓ 删除存档: {filepath}")
    else:
        print(f"✗ 存档不存在: {filepath}")

def test_world_state_update():
    """测试世界状态更新"""
    print("\n=== 测试世界状态更新 ===")
    
    # 模拟战斗后的状态变化
    state_changes = {
        "playerUpdates": {
            "hpDelta": -15,
            "mpDelta": -10,
            "goldDelta": 5,
            "addEffects": ["轻伤"],
            "addItems": ["银票"],
            "removeItems": []
        }
    }
    
    # 加载存档
    save = load_save(1)
    if save:
        # 应用变化
        player = save["worldState"]["player"]
        player["hp"] = max(0, player["hp"] + state_changes["playerUpdates"]["hpDelta"])
        player["mp"] = max(0, player["mp"] + state_changes["playerUpdates"]["mpDelta"])
        player["gold"] += state_changes["playerUpdates"]["goldDelta"]
        player["activeEffects"].extend(state_changes["playerUpdates"]["addEffects"])
        player["inventory"].extend(state_changes["playerUpdates"]["addItems"])
        
        print(f"✓ HP: {100 + (-15)} → {player['hp']}")
        print(f"✓ MP: {50 + (-10)} → {player['mp']}")
        print(f"✓ Gold: {10 + 5} → {player['gold']}")
        print(f"✓ 新增效果: {player['activeEffects']}")
        print(f"✓ 新增物品: {player['inventory']}")
        
        # 保存更新后的存档
        filepath = os.path.join(SAVE_DIR, "save_001.json")
        with open(filepath, 'w', encoding='utf-8') as f:
            json.dump(save, f, ensure_ascii=False, indent=2)
        print(f"✓ 存档已更新")

if __name__ == "__main__":
    print("=" * 50)
    print("SMS RPG 指令式引擎 - 存档系统测试")
    print("=" * 50)
    
    # 1. 确保目录存在
    ensure_save_dir()
    
    # 2. 创建测试存档
    create_test_save(1)
    
    # 3. 加载存档
    load_save(1)
    
    # 4. 列出所有存档
    print("\n=== 存档列表 ===")
    for save in list_saves():
        if "status" in save:
            print(f"槽位{save['slot']}: {save['status']}")
        else:
            print(f"槽位{save['slot']}: {save['playerName']} | 第{save['turn']}回合 | {save['summary']}...")
    
    # 5. 测试状态更新
    test_world_state_update()
    
    # 6. 清理测试存档
    print("\n=== 清理测试数据 ===")
    delete_save(1)
    
    print("\n" + "=" * 50)
    print("✓ 所有测试通过！")
    print("=" * 50)


path: templates/crises/enemy.yaml
content: # 敌人危机模板

## 危机定义

敌人危机是由敌对势力或个人引发的挑战，通常涉及战斗、对抗或策略应对。

---

## 危机模板

crises:
  # 仇家上门危机
  - id: "crisis_enemy_doorstep"
    title: "仇家上门"
    description: "{enemy_name}带人来到你所在之处，来者不善"
    type: "enemy"
    severity: 7
    duration: 2
    triggers:
      - condition: "hasEnemy"
        weight: 0.3
      - condition: "playerReputation > 50"
        weight: 0.2
    consequences:
      timeout: "仇家强行闯入，发生冲突"
      success: "化解危机或击败敌人"
      failure: "被迫逃离或受重伤"
    options:
      - id: "option_fight"
        description: "正面迎战"
        requirements:
          - type: "cultivation"
            min: "enemy_level"
        successRate: 0.6
        successEffect: "击败{enemy_name}，获得声望"
        failureEffect: "战败受伤，被迫撤退"
      - id: "option_negotiate"
        description: "尝试谈判"
        requirements:
          - type: "charisma"
            min: 50
        successRate: 0.4
        successEffect: "暂时化解矛盾"
        failureEffect: "谈判失败，敌人更加嚣张"
      - id: "option_flee"
        description: "避其锋芒，暂时躲避"
        requirements: []
        successRate: 0.7
        successEffect: "成功逃脱，但失去一些颜面"
        failureEffect: "被追上，陷入更危险的境地"
      - id: "option_call_help"
        description: "寻求支援"
        requirements:
          - type: "ally"
            nearby: true
        successRate: 0.8
        successEffect: "援军到达，敌人被迫撤退"
        failureEffect: "支援来不及，独自面对"

  # 追杀危机
  - id: "crisis_hunted"
    title: "千里追杀"
    description: "{enemy_faction}派出杀手追杀你，形势危急"
    type: "enemy"
    severity: 8
    duration: 6
    triggers:
      - condition: "offendedPowerfulEnemy"
        weight: 0.5
    consequences:
      timeout: "被杀手追上，陷入苦战"
      success: "摆脱追杀或消灭杀手"
      failure: "被抓住或重伤"
    options:
      - id: "option_hide"
        description: "隐匿行踪，躲避追杀"
        requirements:
          - type: "location"
            type: "hideable"
        successRate: 0.5
        successEffect: "成功隐藏，杀手暂时失去线索"
        failureEffect: "被发现，被迫战斗"
      - id: "option_counter"
        description: "设下陷阱，反杀追兵"
        requirements:
          - type: "preparation"
            time: true
        successRate: 0.6
        successEffect: "成功反杀，获得战利品"
        failureEffect: "陷阱失败，陷入包围"
      - id: "option_seek_protection"
        description: "寻求势力庇护"
        requirements:
          - type: "faction"
            relation: "friendly"
        successRate: 0.7
        successEffect: "获得庇护，追兵不敢轻举妄动"
        failureEffect: "庇护被拒绝，需要另寻出路"

  # 资源争夺危机
  - id: "crisis_resource_conflict"
    title: "资源争夺"
    description: "你发现的{resource_name}被{enemy_name}盯上"
    type: "enemy"
    severity: 5
    duration: 3
    triggers:
      - condition: "foundRareResource"
        weight: 0.4
    consequences:
      timeout: "资源被{enemy_name}抢走"
      success: "保住资源或共享"
      failure: "失去资源"
    options:
      - id: "option_share"
        description: "提议平分"
        requirements: []
        successRate: 0.5
        successEffect: "达成协议，各得一半"
        failureEffect: "对方想要独占"
      - id: "option_fight"
        description: "武力争夺"
        requirements:
          - type: "cultivation"
            min: "enemy_level"
        successRate: 0.5
        successEffect: "击败敌人，独占资源"
        failureEffect: "战败，失去资源且受伤"
      - id: "option_give_up"
        description: "让出资源，避免冲突"
        requirements: []
        successRate: 1.0
        successEffect: "和平解决，但失去资源"
        failureEffect: "无"

  # 势力围攻危机
  - id: "crisis_faction_siege"
    title: "势力围攻"
    description: "{faction_name}对你所在之地形成包围之势"
    type: "enemy"
    severity: 9
    duration: 8
    triggers:
      - condition: "offendedFaction"
        weight: 0.4
    consequences:
      timeout: "被攻破，损失惨重"
      success: "坚守成功或突围"
      failure: "被击败，被迫投降或逃亡"
    options:
      - id: "option_defend"
        description: "坚守待援"
        requirements:
          - type: "fortification"
            exists: true
        successRate: 0.4
        successEffect: "成功坚守，援军到达"
        failureEffect: "防守被突破，损失惨重"
      - id: "option_breakout"
        description: "趁夜突围"
        requirements:
          - type: "stealth"
            min: 50
        successRate: 0.5
        successEffect: "成功突围，保存实力"
        failureEffect: "突围失败，被困更紧"
      - id: "option_negotiate"
        description: "尝试谈判投降条件"
        requirements: []
        successRate: 0.3
        successEffect: "达成屈辱条件，保全性命"
        failureEffect: "对方不接受投降"
      - id: "option_call_ally"
        description: "请求盟友支援"
        requirements:
          - type: "ally_faction"
            power: "enough"
        successRate: 0.6
        successEffect: "盟友势力介入，{faction_name}被迫退兵"
        failureEffect: "盟友支援不足，局势恶化"

  # 秘密暴露危机
  - id: "crisis_secret_exposed"
    title: "秘密暴露"
    description: "你的某个秘密被{enemy_name}发现，正要公开"
    type: "enemy"
    severity: 7
    duration: 3
    triggers:
      - condition: "playerHasSecret"
        weight: 0.3
    consequences:
      timeout: "秘密被公开，造成巨大影响"
      success: "阻止秘密公开或控制影响"
      failure: "秘密公开，声誉受损"
    options:
      - id: "option_silence"
        description: "灭口或威胁"
        requirements:
          - type: "cultivation"
            min: "enemy_level"
        successRate: 0.5
        successEffect: "秘密被保守，但树立新敌人"
        failureEffect: "行动失败，秘密更快暴露"
      - id: "option_negotiate"
        description: "谈判封口条件"
        requirements:
          - type: "resource"
            enough: true
        successRate: 0.6
        successEffect: "付出代价，保守秘密"
        failureEffect: "对方狮子大开口，条件无法接受"
      - id: "option_own_up"
        description: "主动承认，控制舆论"
        requirements: []
        successRate: 0.4
        successEffect: "坦诚获得部分谅解，影响可控"
        failureEffect: "承认后遭到更多攻击"

  # 故人寻仇危机
  - id: "crisis_old_enemy"
    title: "故人寻仇"
    description: "过去的仇人{enemy_name}找上门来"
    type: "enemy"
    severity: 6
    duration: 4
    triggers:
      - condition: "hasPastEnemy"
        weight: 0.3
    consequences:
      timeout: "仇怨加深，无法化解"
      success: "了结恩怨或达成和解"
      failure: "陷入缠斗，两败俱伤"
    options:
      - id: "option_fight"
        description: "一决生死"
        requirements:
          - type: "cultivation"
            min: "enemy_level"
        successRate: 0.5
        successEffect: "击败仇人，了结恩怨"
        failureEffect: "战败，仇恨延续"
      - id: "option_reconcile"
        description: "尝试化解恩怨"
        requirements:
          - type: "charisma"
            min: 60
        successRate: 0.3
        successEffect: "达成和解，化敌为友"
        failureEffect: "和解失败，矛盾激化"
      - id: "option_explain"
        description: "说明当年的真相"
        requirements:
          - type: "truth"
            available: true
        successRate: 0.5
        successEffect: "真相大白，误会解除"
        failureEffect: "真相不被接受，仇恨更深"

  # 诬陷危机
  - id: "crisis_framed"
    title: "蒙冤受屈"
    description: "你被{enemy_name}诬陷，面临审判"
    type: "enemy"
    severity: 6
    duration: 5
    triggers:
      - condition: "enemyInfluence > 50"
        weight: 0.3
    consequences:
      timeout: "被判有罪，遭受惩罚"
      success: "洗清冤屈"
      failure: "无法证明清白，被定罪"
    options:
      - id: "option_prove"
        description: "收集证据证明清白"
        requirements:
          - type: "investigation"
            possible: true
        successRate: 0.6
        successEffect: "证据确凿，洗清冤屈，{enemy_name}反受惩罚"
        failureEffect: "证据不足，无法自证"
      - id: "option_witness"
        description: "寻找证人作证"
        requirements:
          - type: "ally"
            willing: true
        successRate: 0.5
        successEffect: "证人证词帮助洗清冤屈"
        failureEffect: "无人愿意作证"
      - id: "option_escape"
        description: "逃离审判"
        requirements:
          - type: "stealth"
            min: 60
        successRate: 0.4
        successEffect: "成功逃脱，但成为通缉犯"
        failureEffect: "逃跑失败，罪加一等"


path: templates/crises/relationship.yaml
content: # 关系危机模板

## 危机定义

关系危机是影响玩家与NPC关系的事件性挑战，通常突发，需要玩家在限定时间内做出反应。

---

## 危机模板

crises:
  # 道侣被掳危机
  - id: "crisis_lover_captured"
    title: "道侣被掳"
    description: "{lover_name}被{enemy_name}带走，生死未卜"
    type: "personal"
    severity: 8
    duration: 5
    triggers:
      - condition: "hasLover AND relationship >= 80"
        weight: 0.2
      - condition: "enemyThreat > 0"
        weight: 0.3
    consequences:
      timeout: "{lover_name}被带往{enemy_faction}，营救难度大幅增加"
      success: "成功救回{lover_name}，关系大幅提升"
      failure: "营救失败，{lover_name}受伤，关系不变"
    options:
      - id: "option_negotiate"
        description: "尝试与{enemy_name}谈判"
        requirements:
          - type: "gold"
            min: 1000
        successRate: 0.4
        successEffect: "用钱赎回{lover_name}，关系+5"
        failureEffect: "谈判破裂，{enemy_name}更加嚣张"
      - id: "option_rescue"
        description: "直接营救"
        requirements:
          - type: "cultivation"
            min: "enemy_level"
        successRate: 0.6
        successEffect: "成功救回{lover_name}，关系+15"
        failureEffect: "营救失败，自己受伤，{lover_name}被转移"
      - id: "option_seek_help"
        description: "寻求他人帮助"
        requirements:
          - type: "ally"
            exists: true
        successRate: 0.7
        successEffect: "在盟友帮助下救回{lover_name}，关系+10"
        failureEffect: "盟友也无能为力，时间被耽误"

  # 误会危机
  - id: "crisis_misunderstanding"
    title: "误会加深"
    description: "{npc_name}误以为你做了某事，关系急剧恶化"
    type: "personal"
    severity: 6
    duration: 3
    triggers:
      - condition: "relationship >= 50"
        weight: 0.15
      - condition: "recentNegativeEvent"
        weight: 0.3
    consequences:
      timeout: "误会未及时解开，{npc_name}对你心存芥蒂，关系-20"
      success: "误会解开，关系恢复并+5"
      failure: "解释失败，{npc_name}更加怀疑，关系-10"
    options:
      - id: "option_explain"
        description: "诚恳解释真相"
        requirements: []
        successRate: 0.5
        successEffect: "误会解开，关系+5"
        failureEffect: "解释不被接受，需要更多证据"
      - id: "option_prove"
        description: "寻找证据证明自己"
        requirements:
          - type: "investigation"
            possible: true
        successRate: 0.7
        successEffect: "证据确凿，误会完全解开，关系+10"
        failureEffect: "证据不足，误会依然存在"
      - id: "option_wait"
        description: "等待时间证明一切"
        requirements: []
        successRate: 0.3
        successEffect: "真相大白，关系+5"
        failureEffect: "时间流逝，误会加深，关系-15"

  # 嫉妒危机
  - id: "crisis_jealousy"
    title: "醋海生波"
    description: "{npc_name}发现你与其他女子走得太近，心生不满"
    type: "personal"
    severity: 5
    duration: 2
    triggers:
      - condition: "hasMultipleLoveInterests"
        weight: 0.4
      - condition: "relationship >= 70"
        weight: 0.3
    consequences:
      timeout: "{npc_name}虽然不说，但心中有了疙瘩"
      success: "成功安抚{npc_name}，关系更近一步"
      failure: "安抚失败，{npc_name}暂时冷淡"
    options:
      - id: "option_honest"
        description: "坦诚相待，说明自己的心意"
        requirements:
          - type: "relationship"
            min: 70
        successRate: 0.6
        successEffect: "{npc_name}理解并接受，关系+10"
        failureEffect: "{npc_name}表示需要时间考虑"
      - id: "option_choice"
        description: "做出选择，证明她的特殊地位"
        requirements: []
        successRate: 0.8
        successEffect: "{npc_name}感到被重视，关系+15"
        failureEffect: "选择不被认可，关系不变"
      - id: "option_gift"
        description: "送一份特别的礼物表达心意"
        requirements:
          - type: "item"
            quality: "rare"
        successRate: 0.5
        successEffect: "礼物被接受，{npc_name}心情好转，关系+5"
        failureEffect: "礼物被退回，需要更真诚的方式"

  # 第三者介入危机
  - id: "crisis_rival_appears"
    title: "情敌出现"
    description: "有人开始追求{npc_name}，对你构成威胁"
    type: "personal"
    severity: 6
    duration: 4
    triggers:
      - condition: "relationship >= 60"
        weight: 0.2
    consequences:
      timeout: "情敌攻势猛烈，{npc_name}对你有些动摇"
      success: "成功击败情敌，{npc_name}更加坚定地选择你"
      failure: "情敌占据上风，需要更多努力挽回"
    options:
      - id: "option_confront"
        description: "正面与情敌较量"
        requirements:
          - type: "cultivation"
            min: "rival_level"
        successRate: 0.6
        successEffect: "击败情敌，在{npc_name}面前证明自己，关系+10"
        failureEffect: "较量失败，颜面扫地"
      - id: "option_impress"
        description: "在{npc_name}面前展示自己的优点"
        requirements: []
        successRate: 0.5
        successEffect: "{npc_name}对你刮目相看，关系+8"
        failureEffect: "展示效果一般，{npc_name}反应平淡"
      - id: "option_undermine"
        description: "暗中调查情敌的弱点"
        requirements:
          - type: "investigation"
            possible: true
        successRate: 0.7
        successEffect: "发现情敌的把柄，成功劝退"
        failureEffect: "调查被发现，反而让{npc_name}不满"

  # 家族反对危机
  - id: "crisis_family_opposition"
    title: "家族反对"
    description: "{npc_name}的家人反对你们的关系"
    type: "personal"
    severity: 7
    duration: 6
    triggers:
      - condition: "relationship >= 80"
        weight: 0.25
      - condition: "npcHasFamily"
        weight: 0.3
    consequences:
      timeout: "家族压力下，{npc_name}陷入两难，关系停滞"
      success: "说服家族，或{npc_name}坚定选择你"
      failure: "被迫暂时分离，需要寻找新的机会"
    options:
      - id: "option_prove_worth"
        description: "证明自己配得上{npc_name}"
        requirements:
          - type: "cultivation"
            min: "higher_than_family_expectation"
        successRate: 0.5
        successEffect: "家族勉强接受，关系+5"
        failureEffect: "仍被认为不够格"
      - id: "option_win_ally"
        description: "先争取家族中某位成员的支持"
        requirements: []
        successRate: 0.6
        successEffect: "获得家族内部支持，阻力减少，关系+3"
        failureEffect: "争取失败，情况更复杂"
      - id: "option_elope"
        description: "提议私奔"
        requirements:
          - type: "relationship"
            min: 90
        successRate: 0.4
        successEffect: "{npc_name}愿意跟随你，但与家族决裂"
        failureEffect: "{npc_name}不愿伤害家人，拒绝提议"

  # 信任危机
  - id: "crisis_trust_broken"
    title: "信任崩塌"
    description: "你无意中伤害了{npc_name}，她开始怀疑你的真心"
    type: "personal"
    severity: 8
    duration: 5
    triggers:
      - condition: "playerHurtNpc"
        weight: 0.8
    consequences:
      timeout: "{npc_name}彻底失去信任，关系降至冰点"
      success: "重建信任，关系恢复"
      failure: "关系永久受损"
    options:
      - id: "option_apologize"
        description: "真诚道歉，表达悔意"
        requirements: []
        successRate: 0.4
        successEffect: "{npc_name}态度软化，愿意听你解释"
        failureEffect: "道歉不被接受"
      - id: "option_compensate"
        description: "用实际行动弥补过失"
        requirements:
          - type: "quest"
            target: "compensation_quest"
        successRate: 0.7
        successEffect: "弥补行动让{npc_name}感动，关系逐渐恢复"
        failureEffect: "弥补不足，仍需更多努力"
      - id: "option_time"
        description: "给她时间和空间"
        requirements: []
        successRate: 0.3
        successEffect: "时间治愈一切，关系缓慢恢复"
        failureEffect: "时间流逝，感情淡化，关系-20"


path: templates/goals/cultivation.yaml
content: # 修仙类目标模板

## 终极目标模板

ultimate_goals:
  - id: "ultimate_cultivation_001"
    title: "成就无上大道"
    description: "突破修仙极限，证道长生"
    theme: "cultivation"
    totalPhases: 5
    phases:
      - phase: 1
        name: "筑基之路"
        description: "从凡人到筑基，踏入修仙之门"
      - phase: 2
        name: "金丹大道"
        description: "凝结金丹，成就一方强者"
      - phase: 3
        name: "元婴突破"
        description: "元婴出窍，掌握生死之力"
      - phase: 4
        name: "化神之路"
        description: "感悟天地法则，踏入化神之境"
      - phase: 5
        name: "渡劫飞升"
        description: "渡过天劫，证得大道"

  - id: "ultimate_cultivation_002"
    title: "重建宗门"
    description: "振兴没落宗门，重回巅峰"
    theme: "cultivation"
    totalPhases: 4

  - id: "ultimate_cultivation_003"
    title: "寻父之路"
    description: "寻找失踪的父亲，揭开身世之谜"
    theme: "mystery"
    totalPhases: 4

## 阶段目标模板

phase_goals:
  # 筑基期目标
  - id: "phase_breakthrough_jichu"
    title: "突破筑基"
    description: "积累灵气，准备筑基丹，寻找灵地突破"
    theme: "cultivation"
    difficulty: 3
    requirements:
      - type: "cultivation"
        target: "练气巅峰"
      - type: "item"
        target: "筑基丹"
        count: 1
      - type: "location"
        target: "灵气充沛之地"
    milestones:
      - "达到练气巅峰"
      - "获得筑基丹"
      - "找到灵地"
      - "成功突破"
    rewards:
      cultivation: "筑基初期"
      stats:
        hp: 500
        mp: 1000

  # 金丹期目标
  - id: "phase_breakthrough_jindan"
    title: "凝结金丹"
    description: "积累底蕴，寻找金丹机缘"
    theme: "cultivation"
    difficulty: 5
    requirements:
      - type: "cultivation"
        target: "筑基巅峰"
      - type: "comprehension"
        target: "功法大成"
      - type: "opportunity"
        target: "金丹机缘"
    milestones:
      - "达到筑基巅峰"
      - "功法修炼大成"
      - "获得金丹机缘"
      - "凝结金丹成功"

  # 元婴期目标
  - id: "phase_breakthrough_yuanying"
    title: "元婴出窍"
    description: "碎丹成婴，踏入元婴之境"
    theme: "cultivation"
    difficulty: 7
    requirements:
      - type: "cultivation"
        target: "金丹巅峰"
      - type: "soul"
        target: "神识强大"
      - type: "danger"
        target: "渡过心魔劫"
    milestones:
      - "达到金丹巅峰"
      - "神识突破万里"
      - "克服心魔"
      - "元婴成形"

  # 功法修炼目标
  - id: "phase_skill_mastery"
    title: "功法大成"
    description: "将{skill_name}修炼至大成境界"
    theme: "cultivation"
    difficulty: 4
    requirements:
      - type: "comprehension"
        target: "功法理解"
      - type: "practice"
        target: "实战历练"
    milestones:
      - "入门篇修炼完成"
      - "小成境界"
      - "大成境界"

  # 秘境探索目标
  - id: "phase_secret_realm"
    title: "探索{realm_name}"
    description: "进入秘境，获取传承或宝物"
    theme: "cultivation"
    difficulty: 6
    requirements:
      - type: "cultivation"
        minLevel: "筑基中期"
      - type: "item"
        target: "秘境令牌"
    milestones:
      - "获得进入资格"
      - "通过第一重试炼"
      - "通过第二重试炼"
      - "获取传承/宝物"
      - "安全离开"

## 小目标模板

milestones:
  - id: "milestone_learn_skill"
    title: "学习{skill_name}"
    description: "获得并学习一门新功法"
    turnsToComplete: 5
    requirements:
      - type: "item"
        target: "功法秘籍"
      - type: "cultivation"
        minLevel: "required_level"

  - id: "milestone_gather_resources"
    title: "收集修炼资源"
    description: "收集{resource_name}用于修炼"
    turnsToComplete: 3
    requirements:
      - type: "item"
        target: "resource_name"
        count: "required_count"

  - id: "milestone_find_location"
    title: "寻找{location_name}"
    description: "探索并找到该地点"
    turnsToComplete: 2
    requirements:
      - type: "info"
        target: "地点线索"

  - id: "milestone_defeat_enemy"
    title: "击败{enemy_name}"
    description: "在战斗中击败该敌人"
    turnsToComplete: 1
    requirements:
      - type: "combat"
        target: "enemy_id"

  - id: "milestone_complete_quest"
    title: "完成任务：{quest_name}"
    description: "完成指定的任务"
    turnsToComplete: 5
    requirements:
      - type: "quest"
        target: "quest_id"

## 日常目标模板

daily_goals:
  - id: "daily_cultivation"
    title: "日常修炼"
    description: "进行基础修炼，稳步提升修为"
    turnsToComplete: 1
    rewards:
      cultivation: "微量提升"

  - id: "daily_gather_herbs"
    title: "采集灵草"
    description: "在指定地点采集灵草"
    turnsToComplete: 1
    rewards:
      items: ["灵草"]

  - id: "daily_sect_task"
    title: "宗门任务"
    description: "完成宗门分配的日常任务"
    turnsToComplete: 1
    rewards:
      gold: 50
      reputation: 5


path: templates/goals/relationship.yaml
content: # 关系类目标模板

## 终极目标模板

ultimate_goals:
  - id: "ultimate_relationship_001"
    title: "集齐九位道侣"
    description: "找到并成为九位命定之人的道侣，觉醒系统真谛"
    theme: "relationship"
    totalPhases: 3
    phases:
      - phase: 1
        name: "初识红尘"
        description: "找到前三位有缘人"
      - phase: 2
        name: "情路漫漫"
        description: "再得三位佳人芳心"
      - phase: 3
        name: "圆满之境"
        description: "集齐最后三位，达成圆满"

  - id: "ultimate_relationship_002"
    title: "情定三生"
    description: "与真爱经历生死考验，成就三生情缘"
    theme: "relationship"
    totalPhases: 3

## 阶段目标模板

phase_goals:
  # 结识目标
  - id: "phase_meet_npc"
    title: "结识{npc_name}"
    description: "与{npc_name}建立初步联系"
    theme: "relationship"
    difficulty: 2
    requirements:
      - type: "location"
        target: "npc所在地点"
      - type: "event"
        target: "相遇契机"
    milestones:
      - "得知{npc_name}的存在"
      - "找到相遇机会"
      - "成功搭话"
    rewards:
      relationship:
        target: "npc_id"
        value: 10

  # 建立信任目标
  - id: "phase_build_trust"
    title: "获得{npc_name}的信任"
    description: "通过一系列互动，让{npc_name}对你敞开心扉"
    theme: "relationship"
    difficulty: 4
    requirements:
      - type: "relationship"
        target: "npc_id"
        minLevel: 30
      - type: "actions"
        target: "善意互动"
        count: 3
    milestones:
      - "好感度达到30"
      - "帮助{npc_name}解决困难"
      - "好感度达到50"
      - "获得信任"

  # 心结解开目标
  - id: "phase_resolve_heartknot"
    title: "解开{npc_name}的心结"
    description: "了解并帮助{npc_name}解开心中郁结"
    theme: "relationship"
    difficulty: 6
    requirements:
      - type: "relationship"
        target: "npc_id"
        minLevel: 70
      - type: "heartknot"
        target: "npc_heartknot_id"
    milestones:
      - "发现心结的存在"
      - "了解心结详情"
      - "找到解开心结的方法"
      - "成功解开心结"
    rewards:
      relationship:
        target: "npc_id"
        value: 30
        unlockMax: true

  # 道侣关系目标
  - id: "phase_become_lovers"
    title: "与{npc_name}结为道侣"
    description: "修成正果，成为双修道侣"
    theme: "relationship"
    difficulty: 5
    requirements:
      - type: "relationship"
        target: "npc_id"
        minLevel: 90
      - type: "heartknot"
        target: "npc_heartknot_id"
        status: "resolved"
      - type: "opportunity"
        target: "结侣契机"
    milestones:
      - "好感度达到90"
      - "心结已解开"
      - "找到结侣契机"
      - "成功结为道侣"
    rewards:
      relationship:
        target: "npc_id"
        value: 10
        type: "lover"

  # 挽救关系目标
  - id: "phase_save_relationship"
    title: "挽回{npc_name}的信任"
    description: "因某事导致关系破裂，需要挽回"
    theme: "relationship"
    difficulty: 5
    requirements:
      - type: "relationship"
        target: "npc_id"
        status: "damaged"
    milestones:
      - "了解破裂原因"
      - "寻找弥补方法"
      - "付出行动"
      - "重新获得信任"

## 小目标模板

milestones:
  - id: "milestone_give_gift"
    title: "送给{npc_name}礼物"
    description: "赠送一份礼物以表达心意"
    turnsToComplete: 1
    requirements:
      - type: "item"
        target: "gift_item"
      - type: "npc_available"
        target: "npc_id"
    effects:
      relationship:
        target: "npc_id"
        value: 5

  - id: "milestone_help_npc"
    title: "帮助{npc_name}"
    description: "为{npc_name}解决一个困难"
    turnsToComplete: 3
    requirements:
      - type: "quest"
        target: "npc_help_quest"
    effects:
      relationship:
        target: "npc_id"
        value: 15

  - id: "milestone_shared_experience"
    title: "与{npc_name}共同经历"
    description: "与{npc_name}一起经历某事"
    turnsToComplete: 2
    requirements:
      - type: "npc_available"
        target: "npc_id"
    effects:
      relationship:
        target: "npc_id"
        value: 10

  - id: "milestone_learn_secret"
    title: "了解{npc_name}的秘密"
    description: "通过某种方式得知{npc_name}隐藏的秘密"
    turnsToComplete: 3
    requirements:
      - type: "relationship"
        target: "npc_id"
        minLevel: 50
    effects:
      relationship:
        target: "npc_id"
        value: 5
      unlock:
        target: "npc_secret"

## 心结模板

heart_knots:
  # 创伤型心结
  - id: "heartknot_trauma_001"
    name: "灭门之痛"
    type: "trauma"
    description: "家族被灭门的创伤，对仇人充满仇恨"
    severity: 8
    symptoms:
      - "提到家族时会情绪激动"
      - "对相关话题敏感回避"
      - "有时会陷入回忆无法自拔"
    resolution:
      method: "event"
      requiredSteps:
        - "帮助找到部分真相"
        - "陪伴度过情绪低谷"
        - "一起面对仇人或放下仇恨"
    blocksProgressUntil: true

  - id: "heartknot_trauma_002"
    name: "背叛之伤"
    type: "trauma"
    description: "曾经被信任的人背叛，难以再相信他人"
    severity: 7
    symptoms:
      - "难以完全信任他人"
      - "对亲密关系保持距离"
      - "有时会突然冷淡"
    resolution:
      method: "time"
      requiredSteps:
        - "持续展现真诚"
        - "在关键时刻证明可靠"
        - "给予足够时间和空间"
    blocksProgressUntil: true

  # 责任型心结
  - id: "heartknot_obligation_001"
    name: "家族重任"
    type: "obligation"
    description: "背负着振兴家族的重任，无法放下"
    severity: 6
    symptoms:
      - "将家族利益放在首位"
      - "对个人幸福感到犹豫"
      - "提到家族时神情复杂"
    resolution:
      method: "quest"
      requiredSteps:
        - "了解家族状况"
        - "帮助解决家族困境"
        - "证明自己更重要或能共同承担"
    blocksProgressUntil: true

  - id: "heartknot_obligation_002"
    name: "宗门使命"
    type: "obligation"
    description: "身为宗门核心弟子，有必须完成的使命"
    severity: 5
    symptoms:
      - "宗门事务优先处理"
      - "对离开宗门感到为难"
      - "有时需要执行宗门任务"
    resolution:
      method: "quest"
      requiredSteps:
        - "了解使命详情"
        - "帮助完成使命"
        - "或找到使命的替代方案"
    blocksProgressUntil: true

  # 秘密型心结
  - id: "heartknot_secret_001"
    name: "隐秘身世"
    type: "secret"
    description: "隐藏着自己的真实身份或来历"
    severity: 6
    symptoms:
      - "对身世话题敏感"
      - "有时会欲言又止"
      - "某些行为有不可言说的原因"
    resolution:
      method: "dialogue"
      requiredSteps:
        - "建立足够信任"
        - "创造安全的倾诉环境"
        - "接纳她的真实身份"
    blocksProgressUntil: true

  - id: "heartknot_secret_002"
    name: "传承之秘"
    type: "secret"
    description: "背负着某个传承的秘密，不能轻易告诉他人"
    severity: 7
    symptoms:
      - "修炼时会独自行动"
      - "对传承话题谨慎"
      - "有时会突然需要独处"
    resolution:
      method: "event"
      requiredSteps:
        - "在关键时刻展示信任"
        - "帮助完成传承相关任务"
        - "自然得知秘密后表示理解"
    blocksProgressUntil: true

  # 过去型心结
  - id: "heartknot_past_001"
    name: "前缘未了"
    type: "past"
    description: "曾经有一段深刻的感情，未能放下"
    severity: 5
    symptoms:
      - "偶尔会陷入回忆"
      - "对某些话题敏感"
      - "心中留有一个位置"
    resolution:
      method: "event"
      requiredSteps:
        - "了解过去的故事"
        - "创造新的美好回忆"
        - "证明现在更重要"
    blocksProgressUntil: true

  - id: "heartknot_past_002"
    name: "故人之约"
    type: "past"
    description: "与已故之人有一个未完成的约定"
    severity: 6
    symptoms:
      - "在特定日期情绪低落"
      - "会去某个地方祭奠"
      - "对约定的事念念不忘"
    resolution:
      method: "quest"
      requiredSteps:
        - "了解约定内容"
        - "帮助完成约定"
        - "陪伴度过情感难关"
    blocksProgressUntil: true


path: test_save_system.py
content: #!/usr/bin/env python3
"""
SMS RPG 指令式引擎 - 测试脚本
验证存档读写逻辑
"""

import json
import os
from datetime import datetime

# 测试目录
SAVE_DIR = "./sms-rpg-saves"

def ensure_save_dir():
    """确保存档目录存在"""
    os.makedirs(SAVE_DIR, exist_ok=True)
    print(f"✓ 存档目录: {SAVE_DIR}")

def create_test_save(slot=1):
    """创建测试存档"""
    save_data = {
        "version": "2.0-instruction",
        "savedAt": datetime.now().isoformat(),
        "slot": slot,
        "playerName": "沈浪",
        "worldRequirement": "武侠修仙，江湖门派与朝廷暗斗",
        "narrativeStyle": "通俗、利落、有人味，接近《庆余年》叙事感",
        "currentTurn": 3,
        "worldState": {
            "currentLocation": "gusu-city-street",
            "time": "午后",
            "weather": "细雨",
            "atmosphere": "紧张",
            "player": {
                "name": "沈浪",
                "cultivationLevel": "后天境",
                "hp": 100,
                "maxHp": 100,
                "mp": 50,
                "maxMp": 50,
                "gold": 10,
                "reputation": {},
                "activeEffects": [],
                "inventory": []
            },
            "locations": {
                "gusu-city-street": {
                    "id": "gusu-city-street",
                    "name": "姑苏城·长街",
                    "description": "街道两旁商铺林立",
                    "connectedTo": ["gusu-teahouse"],
                    "presentNpcs": [],
                    "secrets": [],
                    "visited": True
                },
                "gusu-teahouse": {
                    "id": "gusu-teahouse",
                    "name": "听雨茶楼",
                    "description": "二层雅间可俯瞰长街",
                    "connectedTo": ["gusu-city-street"],
                    "presentNpcs": ["liu-poison-tongue"],
                    "secrets": ["暗阁联络点"],
                    "visited": False
                }
            },
            "npcs": {
                "liu-poison-tongue": {
                    "id": "liu-poison-tongue",
                    "name": "柳娘子",
                    "description": "暗阁联络人，外号毒舌",
                    "faction": "暗阁",
                    "hp": 80,
                    "maxHp": 80,
                    "mp": 30,
                    "maxMp": 30,
                    "attitude": -50,
                    "status": "active",
                    "secrets": ["三年前传递假情报"],
                    "knownSecrets": [],
                    "relationships": {}
                }
            },
            "quests": [
                {
                    "id": "revenge-shen",
                    "title": "沈家灭门案",
                    "type": "main",
                    "status": "active",
                    "objectives": ["追查暗阁线索", "找到幕后主使"],
                    "progress": "发现柳娘子行踪"
                }
            ],
            "relationships": {},
            "worldMemory": {
                "recentEvents": ["抵达姑苏城", "发现柳娘子"],
                "summary": "沈浪追查灭门凶手，来到姑苏城，发现暗阁联络人柳娘子踪迹",
                "majorEvents": []
            }
        },
        "turnHistory": [
            {
                "turnNumber": 1,
                "playerInput": "混入城中，打探消息",
                "narrative": "...",
                "stateChanges": {}
            },
            {
                "turnNumber": 2,
                "playerInput": "找个角落观察，记下她见面的对象",
                "narrative": "...",
                "stateChanges": {}
            }
        ],
        "summary": "沈浪追查灭门凶手，来到姑苏城，发现暗阁联络人柳娘子踪迹"
    }
    
    filepath = os.path.join(SAVE_DIR, f"save_{slot:03d}.json")
    with open(filepath, 'w', encoding='utf-8') as f:
        json.dump(save_data, f, ensure_ascii=False, indent=2)
    print(f"✓ 创建测试存档: {filepath}")
    return filepath

def load_save(slot=1):
    """加载存档"""
    filepath = os.path.join(SAVE_DIR, f"save_{slot:03d}.json")
    try:
        with open(filepath, 'r', encoding='utf-8') as f:
            data = json.load(f)
        print(f"✓ 加载存档成功: {filepath}")
        return data
    except FileNotFoundError:
        print(f"✗ 存档不存在: {filepath}")
        return None
    except json.JSONDecodeError as e:
        print(f"✗ 存档损坏: {filepath}, 错误: {e}")
        return None

def list_saves():
    """列出所有存档"""
    saves = []
    for i in range(1, 6):
        filepath = os.path.join(SAVE_DIR, f"save_{i:03d}.json")
        if os.path.exists(filepath):
            try:
                with open(filepath, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                saves.append({
                    "slot": i,
                    "playerName": data.get("playerName", "未知"),
                    "turn": data.get("currentTurn", 0),
                    "summary": data.get("summary", "")[:30]
                })
            except:
                saves.append({"slot": i, "status": "损坏"})
        else:
            saves.append({"slot": i, "status": "空"})
    return saves

def delete_save(slot=1):
    """删除存档"""
    filepath = os.path.join(SAVE_DIR, f"save_{slot:03d}.json")
    if os.path.exists(filepath):
        os.remove(filepath)
        print(f"✓ 删除存档: {filepath}")
    else:
        print(f"✗ 存档不存在: {filepath}")

def test_world_state_update():
    """测试世界状态更新"""
    print("\n=== 测试世界状态更新 ===")
    
    # 模拟战斗后的状态变化
    state_changes = {
        "playerUpdates": {
            "hpDelta": -15,
            "mpDelta": -10,
            "goldDelta": 5,
            "addEffects": ["轻伤"],
            "addItems": ["银票"],
            "removeItems": []
        }
    }
    
    # 加载存档
    save = load_save(1)
    if save:
        # 应用变化
        player = save["worldState"]["player"]
        player["hp"] = max(0, player["hp"] + state_changes["playerUpdates"]["hpDelta"])
        player["mp"] = max(0, player["mp"] + state_changes["playerUpdates"]["mpDelta"])
        player["gold"] += state_changes["playerUpdates"]["goldDelta"]
        player["activeEffects"].extend(state_changes["playerUpdates"]["addEffects"])
        player["inventory"].extend(state_changes["playerUpdates"]["addItems"])
        
        print(f"✓ HP: {100 + (-15)} → {player['hp']}")
        print(f"✓ MP: {50 + (-10)} → {player['mp']}")
        print(f"✓ Gold: {10 + 5} → {player['gold']}")
        print(f"✓ 新增效果: {player['activeEffects']}")
        print(f"✓ 新增物品: {player['inventory']}")
        
        # 保存更新后的存档
        filepath = os.path.join(SAVE_DIR, "save_001.json")
        with open(filepath, 'w', encoding='utf-8') as f:
            json.dump(save, f, ensure_ascii=False, indent=2)
        print(f"✓ 存档已更新")

if __name__ == "__main__":
    print("=" * 50)
    print("SMS RPG 指令式引擎 - 存档系统测试")
    print("=" * 50)
    
    # 1. 确保目录存在
    ensure_save_dir()
    
    # 2. 创建测试存档
    create_test_save(1)
    
    # 3. 加载存档
    load_save(1)
    
    # 4. 列出所有存档
    print("\n=== 存档列表 ===")
    for save in list_saves():
        if "status" in save:
            print(f"槽位{save['slot']}: {save['status']}")
        else:
            print(f"槽位{save['slot']}: {save['playerName']} | 第{save['turn']}回合 | {save['summary']}...")
    
    # 5. 测试状态更新
    test_world_state_update()
    
    # 6. 清理测试存档
    print("\n=== 清理测试数据 ===")
    delete_save(1)
    
    print("\n" + "=" * 50)
    print("✓ 所有测试通过！")
    print("=" * 50)


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (MEDIUM)