@@ -0,0 +1,316 @@
|
||||
# 高好感角色聊天内委托触发与领取流程设计
|
||||
|
||||
更新时间:`2026-04-19`
|
||||
|
||||
## 0. 目标
|
||||
|
||||
这次迭代解决的是一个很具体的体验断层:
|
||||
|
||||
1. 当前角色委托主要还是从 NPC 互动菜单里直接出现,缺少“先聊上 1-2 轮,再顺着上下文自然托付任务”的过渡。
|
||||
2. 聊天态虽然已经有多轮对话、自定义输入和选项建议,但没有“临时任务 offer”这一层中间状态。
|
||||
3. 现有任务详情面板已经能看任务、领奖励,但还不能承接“任务尚未正式入日志,只是对方刚提出委托”的场景。
|
||||
|
||||
目标不是新造一套聊天任务系统,而是把现有:
|
||||
|
||||
- `npc_chat` 多轮聊天流
|
||||
- `generateQuestForNpcEncounter(...)` 任务生成链
|
||||
- `QuestLogEntry` 任务日志结构
|
||||
- `AdventurePanelOverlays` 任务详情面板
|
||||
|
||||
串成一条更自然的“聊天内委托”链路。
|
||||
|
||||
一句话目标:
|
||||
|
||||
**当玩家与好感度大于 0 的角色聊天时,先寒暄 1-2 轮,再由角色顺着上下文提出委托;玩家可查看、换任务、放弃任务,确认领取后任务才正式进入日志,并恢复自由聊天。**
|
||||
|
||||
## 1. 这次不做什么
|
||||
|
||||
为了避免系统边界漂移,这次明确不做下面这些事:
|
||||
|
||||
1. 不重写任务生成器。
|
||||
- “任务”和“更换任务”都必须复用现有 `generateQuestForNpcEncounter(...)` 链路。
|
||||
- 也就是说,仍然走现在的 `evaluateQuestOpportunity -> AI / fallback quest intent -> compileQuestIntentToQuest`。
|
||||
|
||||
2. 不把聊天态任务 offer 直接视为已接任务。
|
||||
- 对方刚把委托提出来时,它还只是 `pending offer`,不应立即写进 `gameState.quests`。
|
||||
- 只有玩家点击“领取任务”后,才正式调用现有任务接取写入逻辑。
|
||||
|
||||
3. 不在 UI 默认堆说明文字。
|
||||
- 聊天态只切换三项操作:
|
||||
- `查看任务`
|
||||
- `更换任务`
|
||||
- `放弃任务`
|
||||
- 不额外在主界面堆功能说明。
|
||||
|
||||
4. 不改成必须走服务端聊天。
|
||||
- 当前多轮 NPC 聊天仍沿用前端本地的 `handleNpcChatTurn(...)` 流程。
|
||||
- 这次只是在聊天流程里插入任务 offer 状态。
|
||||
|
||||
## 2. 核心流程
|
||||
|
||||
## 2.1 触发条件
|
||||
|
||||
只有同时满足下面条件时,聊天中才允许提出委托:
|
||||
|
||||
1. 当前遭遇是角色型 NPC。
|
||||
- `encounter.characterId` 存在。
|
||||
|
||||
2. 当前好感度大于 `0`。
|
||||
|
||||
3. 当前角色没有未结清任务。
|
||||
- 复用 `getQuestForIssuer(...)` 判断。
|
||||
|
||||
4. 当前聊天里还没有待处理的任务 offer。
|
||||
|
||||
5. 已经完成前置寒暄轮次。
|
||||
- 默认要求先完成 `1-2` 轮自然聊天。
|
||||
- 建议规则:
|
||||
- `affinity >= 30` 时,完成 `1` 轮后即可进入委托时机。
|
||||
- `0 < affinity < 30` 时,完成 `2` 轮后再进入委托时机。
|
||||
|
||||
## 2.2 聊天轮次切换
|
||||
|
||||
正常聊天时:
|
||||
|
||||
- 保持现有三条 `npc_chat` 建议选项
|
||||
- 保持自定义输入可用
|
||||
|
||||
当触发委托时:
|
||||
|
||||
1. 先正常生成本轮 NPC 回复。
|
||||
2. 随后调用现有 `generateQuestForNpcEncounter(...)` 生成一份 `pending quest offer`。
|
||||
3. 在当前轮次追加一段 NPC 委托台词。
|
||||
4. 把当前轮次选项替换成:
|
||||
- 第一项:`查看任务`
|
||||
- 第二项:`更换任务`
|
||||
- 第三项:`放弃任务`
|
||||
5. 临时隐藏自定义输入。
|
||||
|
||||
这意味着聊天态此时进入一个短暂的“任务处理态”,直到玩家:
|
||||
|
||||
- 查看并领取
|
||||
- 更换
|
||||
- 放弃
|
||||
|
||||
其中任一分支结算完成后,再恢复自由聊天。
|
||||
|
||||
## 2.3 查看任务
|
||||
|
||||
点击 `查看任务` 时:
|
||||
|
||||
1. 不立即写入任务日志。
|
||||
2. 直接复用现有任务详情弹层展示 `pending quest offer` 的详情。
|
||||
3. 任务详情面板在这类任务上新增主按钮:
|
||||
- `领取任务`
|
||||
|
||||
这一步的关键是:
|
||||
|
||||
**查看任务只是看,不等于接。**
|
||||
|
||||
## 2.4 领取任务
|
||||
|
||||
点击 `领取任务` 时:
|
||||
|
||||
1. 使用当前 `pending quest offer` 的 `QuestLogEntry`,调用现有任务接取写入逻辑,把任务正式写入 `gameState.quests`。
|
||||
2. 同时把这轮动作写回聊天:
|
||||
- 追加玩家一句明确接受委托的话。
|
||||
- 可追加一条简短 NPC 确认回应,或直接用现有结果文案转成对话语义。
|
||||
3. 更新 `storyHistory`,确保后续聊天上下文知道“这份委托已经接下”。
|
||||
4. 清空 `pending quest offer`。
|
||||
5. 恢复正常 `npc_chat` 建议选项与自定义输入。
|
||||
|
||||
## 2.5 更换任务
|
||||
|
||||
点击 `更换任务` 时:
|
||||
|
||||
1. 必须再次调用现有 `generateQuestForNpcEncounter(...)`。
|
||||
2. 旧的 `pending quest offer` 被新的覆盖。
|
||||
3. 当前聊天追加一条“对方换了个委托”的回应。
|
||||
4. 仍然维持任务处理态:
|
||||
- 继续显示
|
||||
- `查看任务`
|
||||
- `更换任务`
|
||||
- `放弃任务`
|
||||
- 自定义输入仍隐藏
|
||||
|
||||
这里的关键约束是:
|
||||
|
||||
**更换任务不是本地改标题或改描述,而是重新走现有任务生成链。**
|
||||
|
||||
## 2.6 放弃任务
|
||||
|
||||
点击 `放弃任务` 时:
|
||||
|
||||
1. 直接丢弃当前 `pending quest offer`。
|
||||
2. 在对话里补一条“玩家暂时不接”的回应。
|
||||
3. 恢复自由聊天:
|
||||
- 再次显示正常 `npc_chat` 建议
|
||||
- 恢复自定义输入
|
||||
|
||||
放弃这里只作用于“待领取委托”,不会影响已经入日志的正式任务。
|
||||
|
||||
## 3. 数据与状态设计
|
||||
|
||||
## 3.1 聊天态新增待领取任务状态
|
||||
|
||||
建议把这次临时状态挂在 `StoryNpcChatState` 上,而不是直接写入 `GameState.quests`。
|
||||
|
||||
```ts
|
||||
interface StoryNpcQuestOfferState {
|
||||
quest: QuestLogEntry;
|
||||
}
|
||||
|
||||
interface StoryNpcChatState {
|
||||
npcId: string;
|
||||
npcName: string;
|
||||
turnCount: number;
|
||||
customInputPlaceholder?: string;
|
||||
pendingQuestOffer?: StoryNpcQuestOfferState | null;
|
||||
}
|
||||
```
|
||||
|
||||
这样有 3 个好处:
|
||||
|
||||
1. 任务 offer 只属于当前聊天上下文,不污染正式任务日志。
|
||||
2. AdventurePanel 可以直接从 `currentStory.npcChatState` 判断是否进入任务处理态。
|
||||
3. 任务详情面板可以直接读取这份 `QuestLogEntry` 展示,而不用再造一套展示结构。
|
||||
|
||||
## 3.2 任务处理态的选项表达
|
||||
|
||||
建议不要把“查看 / 更换 / 放弃”接进服务端 runtime action。
|
||||
|
||||
原因是:
|
||||
|
||||
1. `查看任务` 只是 UI 行为,不需要服务端结算。
|
||||
2. `更换任务` 和 `放弃任务` 都是当前聊天态内部状态流转。
|
||||
3. 这三项更适合作为本地聊天态专用选项,由 `AdventurePanel + npcEncounterActions` 协同处理。
|
||||
|
||||
建议做成 3 个本地专用 `StoryOption`:
|
||||
|
||||
```ts
|
||||
{
|
||||
functionId: 'npc_chat_quest_offer_view',
|
||||
actionText: '查看任务',
|
||||
runtimePayload: { npcChatQuestOfferAction: 'view' }
|
||||
}
|
||||
```
|
||||
|
||||
其余两个同理:
|
||||
|
||||
- `replace`
|
||||
- `abandon`
|
||||
|
||||
## 3.3 接取后的正式写入
|
||||
|
||||
正式领取后才进入任务日志:
|
||||
|
||||
```ts
|
||||
nextState = {
|
||||
...state,
|
||||
quests: acceptQuest(state.quests, pendingQuest.quest),
|
||||
runtimeStats: incrementGameRuntimeStats(state.runtimeStats, {
|
||||
questsAccepted: 1,
|
||||
}),
|
||||
}
|
||||
```
|
||||
|
||||
也就是说:
|
||||
|
||||
- `pending offer` 不计入 `questsAccepted`
|
||||
- 真正点击 `领取任务` 才计数
|
||||
|
||||
## 4. UI 落点
|
||||
|
||||
## 4.1 聊天面板
|
||||
|
||||
`AdventurePanel` 中增加一个判断:
|
||||
|
||||
1. `currentStory.npcChatState?.pendingQuestOffer` 存在时:
|
||||
- 只显示三项任务处理选项
|
||||
- 隐藏自定义输入
|
||||
|
||||
2. 不存在时:
|
||||
- 保持现有聊天输入与 `npc_chat` 建议
|
||||
|
||||
## 4.2 任务详情弹层
|
||||
|
||||
`AdventurePanelOverlays` 里的任务详情弹层继续复用,但要区分两种任务来源:
|
||||
|
||||
1. 已在任务日志中的正式任务
|
||||
- 保持现有逻辑
|
||||
- 完成后仍显示 `领取奖励`
|
||||
|
||||
2. 聊天里的 `pending quest offer`
|
||||
- 底部显示 `领取任务`
|
||||
- 不显示 `领取奖励`
|
||||
|
||||
点击 `领取任务` 后:
|
||||
|
||||
- 关闭详情弹层
|
||||
- 回到聊天界面
|
||||
- 当前聊天追加“我愿意接下”这一步
|
||||
|
||||
## 5. 代码改动建议
|
||||
|
||||
建议落地在这些文件:
|
||||
|
||||
1. `src/types/story.ts`
|
||||
- 扩展 `StoryNpcChatState`
|
||||
|
||||
2. `src/hooks/story/npcEncounterActions.ts`
|
||||
- 增加聊天内任务 offer 触发判断
|
||||
- 接入 `generateQuestForNpcEncounter(...)`
|
||||
- 增加
|
||||
- 更换任务
|
||||
- 放弃任务
|
||||
- 领取任务
|
||||
对应的本地状态流转
|
||||
|
||||
3. `src/hooks/story/useStoryInteractionCoordinator.ts`
|
||||
- 向上暴露聊天内任务 offer 的操作方法
|
||||
|
||||
4. `src/hooks/useStoryGeneration.ts`
|
||||
- 把聊天内任务 offer UI 能力透传给面板
|
||||
|
||||
5. `src/components/AdventurePanel.tsx`
|
||||
- 聊天态隐藏 / 恢复输入
|
||||
- 拦截 `查看任务 / 更换任务 / 放弃任务`
|
||||
- 让 pending quest 也能进入任务详情弹层
|
||||
|
||||
6. `src/components/adventure-panel/AdventurePanelOverlays.tsx`
|
||||
- 为 pending quest 增加 `领取任务` 按钮
|
||||
|
||||
7. `src/components/AdventurePanel.test.tsx`
|
||||
- 补聊天态输入隐藏测试
|
||||
|
||||
8. `src/hooks/story/npcEncounterActions.test.ts`
|
||||
- 补任务 offer 触发 / 更换 / 接取测试
|
||||
|
||||
## 6. 验收标准
|
||||
|
||||
做到以下几点,才算这次需求成立:
|
||||
|
||||
1. 与好感度大于 `0` 的角色聊天时,不会一上来立刻塞任务,前 `1-2` 轮先正常寒暄。
|
||||
2. 达到委托时机后,系统会调用现有 `generateQuestForNpcEncounter(...)` 生成一份待领取任务。
|
||||
3. 当前聊天轮次会出现一段明确的委托台词。
|
||||
4. 这一轮聊天选项会切成:
|
||||
- `查看任务`
|
||||
- `更换任务`
|
||||
- `放弃任务`
|
||||
5. 任务处理态下,自定义输入会被临时隐藏。
|
||||
6. 点击 `查看任务` 会弹出现有任务详情面板。
|
||||
7. 点击 `领取任务` 后,任务才正式进入任务日志,并在对话里体现“玩家愿意接下”。
|
||||
8. 领取完成后,聊天会恢复正常输入与自由继续对话。
|
||||
9. 点击 `更换任务` 时,必须重新调用现有任务生成链,而不是本地改文案。
|
||||
|
||||
## 7. 一句话收束
|
||||
|
||||
这次要做的,不是“让聊天里多一个任务按钮”,而是把:
|
||||
|
||||
- 高好感聊天
|
||||
- 上下文化任务生成
|
||||
- 临时任务 offer
|
||||
- 任务详情查看
|
||||
- 正式领取后回流聊天
|
||||
|
||||
整合成一个更自然的叙事交接过程。
|
||||
@@ -134,6 +134,17 @@
|
||||
- 公开作品广场
|
||||
- 本地浏览历史
|
||||
|
||||
公开作品广场前端请求约束:
|
||||
|
||||
- `listCustomWorldGallery`
|
||||
- `getCustomWorldGalleryDetail`
|
||||
|
||||
这两类公开请求必须走“公开只读请求”通道:
|
||||
|
||||
- 不主动附带 `Authorization`
|
||||
- 不因本地 access token 失效去触发 `/api/auth/refresh`
|
||||
- refresh cookie 缺失、refresh 失败、账号状态过期时,不能把首页公开作品广场一起拖成错误态
|
||||
|
||||
未登录时不读取:
|
||||
|
||||
- 自定义世界库
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
- 大圆角卡片
|
||||
- 半透明玻璃质感
|
||||
- 平台正文与功能信息统一使用 `Inter + Noto Serif SC`
|
||||
- 左上角品牌区允许使用专用像素字标组件或直接使用 `Fusion Pixel` 文本,但仅限品牌 logo,不向正文、按钮、标签扩散
|
||||
- 品牌 logo 只能复用游戏现有 `Fusion Pixel`,不允许再引入第二套像素字体文件
|
||||
|
||||
主题基准:
|
||||
|
||||
@@ -57,6 +59,10 @@
|
||||
### 3.2 排版
|
||||
|
||||
- 平台层正文、按钮、说明、功能标签统一使用非像素字体
|
||||
- 左上角 `叙世 / GENARRATIVE` 品牌字标允许单独做成像素化 logo
|
||||
- `GENARRATIVE` 与 `叙世` 都优先直接使用游戏内同款 `Fusion Pixel`
|
||||
- 品牌字标默认保持正常像素字观感,禁止再叠双层粗阴影或手动加粗到影响识别
|
||||
- 品牌字标直接使用字体文件内原字形,不额外做运行时描字、轮廓拼字或伪粗体处理
|
||||
- 主标题保留明显层级,但不再做像素描边效果
|
||||
- 微型标签维持高字距英文/中文短标签,用来保留产品感和秩序感
|
||||
|
||||
@@ -69,8 +75,12 @@
|
||||
- 弹窗:沿用登录页的圆角浮层和半透明遮罩,不再使用像素弹窗边框
|
||||
- 桌面壳层:首页允许增加顶部工具栏、左侧导航轨、中央内容舞台与右侧趋势面板的组合
|
||||
- 登录页、绑定手机号、账户弹窗、平台详情、创作生成页、结果页、编辑弹窗都必须共享同一套平台主题 token,禁止再各自写一套独立旧色板
|
||||
- 创作中心、Agent 工作台、草稿详情抽屉、资产工坊、启动弹窗、生成弹窗这类二三级平台面板必须显式挂载平台主题壳层或平台 remap 容器,禁止直接在局部面板里写死旧深色 modal 底和旧输入框底色
|
||||
- 平台“我的”页中的“设置”入口必须打开真正的设置面板;账号信息、设备管理、安全状态属于设置面板中的分区,不允许再把账号信息弹层直接充当设置页
|
||||
- 设置面板必须支持平台亮色 / 暗色主题切换,并复用同一套平台 token 驱动登录页、首页、详情页与二三级面板
|
||||
- 首页移动端底部 Tab 与桌面侧边导航的图标底座、图标颜色、文字状态必须全部由平台 token 驱动;暗色主题下不得出现过浅底座和错误文字色,亮色主题下不得残留旧灰蓝 inactive 状态
|
||||
- 首页、存档页、作品详情这类平台主导航与局部 Tab 的 active fill、active shadow、icon shell fill 必须全部来自主题 token;暗色主题禁止继续复用亮色主题的粉橘高光、白色 active 底座
|
||||
- “我的”页账号主卡必须跟随平台亮 / 暗主题联动,不允许继续写死浅色渐变卡面与 `slate` 系按钮
|
||||
|
||||
## 4. 交互与布局约束
|
||||
|
||||
@@ -84,17 +94,19 @@
|
||||
## 5. 实现约束
|
||||
|
||||
- 平台态从 `fusion-pixel-app` 中隔离,避免被全局像素字体覆盖
|
||||
- 品牌区禁止新增额外像素字体包;平台层只允许保留现有 `public/fusion-pixel.ttf` 这一份像素字体资源
|
||||
- 平台态背景不再使用 `/UI/Background_fill.png`
|
||||
- 新样式优先沉淀为平台专用 class / theme token,避免把游戏内像素 class 改坏
|
||||
- 平台默认挂载亮色主题 class,旧紫蓝方案保留为暗色主题 class
|
||||
- 亮色主题需要补齐统一的 overlay、progress track、status pill token,登录弹层与二三级功能面板禁止继续沿用旧深色遮罩与紫蓝强调残留
|
||||
- 平台态中仍保留旧 Tailwind 深色类的历史组件,必须通过平台 remap 容器或平台专用 class 统一收口,不能放任 `bg-[#111318]`、`bg-black/*`、`bg-white/*` 这类旧类在亮色主题下直接裸露
|
||||
- 编辑弹窗保留业务结构与表单逻辑,只替换壳层样式
|
||||
|
||||
## 6. 验收标准
|
||||
|
||||
达到以下结果才算完成:
|
||||
|
||||
1. 平台首页、详情、登录、绑定手机号、账户弹窗、创作入口、创作结果页不再出现像素字体
|
||||
1. 除左上角品牌像素字标外,平台首页、详情、登录、绑定手机号、账户弹窗、创作入口、创作结果页不再出现像素字体
|
||||
2. 平台层按钮、面板、关闭按钮、底部 tab 不再依赖像素 UI 素材
|
||||
3. 平台默认展示亮色主题,暗色主题保留为独立主题方案
|
||||
4. 平台层二三级面板、表单、状态卡、弹窗与登录体系不再残留旧金橙 / 青蓝 / 深黑混搭方案
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
- [RPG_NARRATIVE_PLANNING_FULL_PIPELINE_WORKFLOW_2026-04-12.md](./RPG_NARRATIVE_PLANNING_FULL_PIPELINE_WORKFLOW_2026-04-12.md):专业剧情策划构建 RPG 游戏全剧情的工作流程与交付模板。
|
||||
- [EQUIPMENT_BUILD_AND_FORGE_LOOP_SYSTEM_DESIGN.md](./EQUIPMENT_BUILD_AND_FORGE_LOOP_SYSTEM_DESIGN.md):配装构筑与合成/锻造闭环设计。
|
||||
- [COMPANION_FIRST_CONTACT_RELATIONSHIP_AND_PRIVATE_CHAT_DESIGN_2026-04-04.md](./COMPANION_FIRST_CONTACT_RELATIONSHIP_AND_PRIVATE_CHAT_DESIGN_2026-04-04.md):角色首遇感、关系分层解锁、私聊系统设计。
|
||||
- [NPC_HIGH_AFFINITY_CHAT_QUEST_OFFER_FLOW_2026-04-19.md](./NPC_HIGH_AFFINITY_CHAT_QUEST_OFFER_FLOW_2026-04-19.md):高好感角色在聊天内自然提出委托,并支持查看、更换、放弃、领取的流程设计。
|
||||
- [SCENE_CHAPTER_LOOP_AND_FIRST_ENTRY_CHAPTER_QUEST_DESIGN_2026-04-08.md](./SCENE_CHAPTER_LOOP_AND_FIRST_ENTRY_CHAPTER_QUEST_DESIGN_2026-04-08.md):把每个场景收束成章节单元,并在首进场景时开启章节任务的设计稿。
|
||||
- [SCENE_CHAPTER_BENCHMARK_GAP_AND_AI_NATIVE_EXPERIENCE_SUPPLEMENT_2026-04-08.md](./SCENE_CHAPTER_BENCHMARK_GAP_AND_AI_NATIVE_EXPERIENCE_SUPPLEMENT_2026-04-08.md):对标仙剑、博德之门、黑神话,分析单场景章节的体验缺口,并给出 AI 原生补强方案。
|
||||
- [npc-conversation-situation-draft.md](./npc-conversation-situation-draft.md):NPC 对话阶段和情景注入草案。
|
||||
@@ -27,6 +28,7 @@
|
||||
- 做自定义世界去模板依赖、跨题材泛化、兼容迁移设计时,优先看新增的去模板化优化设计稿。
|
||||
- 做“模板依赖如何真正变成自定义世界自有设定层”的具体迁移方案时,优先看新增的自有设定层优化方案。
|
||||
- 做角色关系、同伴互动、对话表现时,先看后两份。
|
||||
- 做“高好感聊天里如何顺着上下文自然抛出委托、并让任务在聊天内领取”的需求时,优先看新增的聊天委托流程设计稿。
|
||||
- 做剧情引擎章节化、场景闭环、章节任务接入时,优先看新增的场景章节设计稿。
|
||||
- 做“单章节体验还缺什么、该补哪种情感 / 抉择 / 试炼模块”时,优先看新增的章节对标补强设计稿。
|
||||
- 如果要判断是否符合目标,再和 `docs/prd/` 中对应 PRD 对照阅读。
|
||||
|
||||
Reference in New Issue
Block a user