Files
gplan-2/design/gdd/b2-enemy-system.md
T
DKChan 85841f52be docs(gdd): 13 份系统 GDD 迁移为 design/analysis 两件套 v2
- design 件只装结论:v2 骨架(设计目的/系统范围/核心循环/领域章节/依赖与输出/P0 闭环/P1·P2 后置/调参表/GWT 验收/版本历史),AC/EC/OQ/义务台账编号全部保留
- 新建 design/gdd/analysis/ 13 份推演件:候选取舍/公式推导/数值锚定论证/已裁决争议按问题节组织,文末附去向映射表(零丢失审计)
- v1 原文备份于 design/gdd/legacy-2026-09-14-v1/(13 份)
- systems-index 文档树补 analysis 目录导航行
- gdd_lint 全量 PASS(14 文件 0 不通过);迁移零裁决——19+1 项待拍板已登记各 analysis 开放问题区
2026-09-14 20:39:11 +08:00

42 KiB
Raw Blame History

B2 敌人系统(Enemy System / 战斗单位系统)

状态:Approved · 版本:v2 · 2026-09-14 一句话:定义战斗双方是谁、多强、带什么词条、如何受伤与死亡——雷的代价的收件人。 推演件:design/gdd/analysis/b2-enemy-system.md(本文件只收结论,理由在那里)

设计目的

B2 是战斗域单位层(Layer 2 Core · MVP):持有 EnemyTable/HeroTable 回填权,承载主角与敌人共用的战斗单位接口。缺本系统则踩雷优势无受益者、胜负判定无主体、难度曲线无施加对象。

  1. 对面是个看得懂的对手——威胁可推测、可归因、可拆解,不是一个血条。
  2. 它弓起背,下一拍是重击——读怪推理进入挖掘决策。
  3. 它强是我喂的,它弱是我拆的——伏击与削弱落在同一个它身上。
  4. 越下越险——深层敌人更凶,给下探氛围一个可见刻度。

反向护栏:威胁绝不能是无源暗账——玩家说不出"它为什么变强 / 这一拳为什么这么重"即归因链失职。

系统范围

负责:

  • 单位状态(hp/max_hp/存活/行为环指针)与查询/受击/推进接口
  • EnemyTable/HeroTable schema 与行回填(行键 (level_index, node_depth, enemy_id))
  • 行为环语义与目标选择规则(固定顺位)
  • 伏击量纲定稿与 advantage_per_round_cap 表值(B1 条款 3 对账供给)

不负责:

  • 结算编排与伤害消费语义(B1 SettlementTable)
  • 状态实例容器(B3)
  • 奖励内容与掉落(B4)
  • 棋盘规则(A1/A2)
  • 单位成长曲线与难度修饰(C3)
  • 遭遇构成与跨战斗 HP 持久性(C1/C2)
  • 呈现(D1/B5/D5)
  • 单位/词条类结构与事件载体实现(实现期 ADR 域)

硬约束:零随机(rng_service 流封闭)· 零 UI 依赖 · 零主动事件订阅 · 悬空引用致命、零软回退 · 行为环敌单位专属 · 单位接口调用权集中归 B1 · 胜利路径 = 基础攻击(恒在)+ B4 奖励侧规划面伤害共同承载——"敌人全灭 → 战斗胜利"可判定。

核心循环

战斗开始(B1 编排调用——B2 编排被动,调用权集中归 B1)
  ① 解析遭遇行 (level_index, node_depth) + enemy_id 精确匹配(悬空致命)
  ② 行值快照 → 实例化本战 n 个敌单位(行主序生成序)+ 主角(hp 入参);指针指向环首
每次结算(B1 驱动;每存活敌单位恰一次 advance,主角无环不在推进域)
  ⓪ 主角先手攻击 → apply_damage(顺位最前存活敌)
  ① 兑付读值 query_attack(u, L, m_amb) → {baseline, attach, total}
  ② 受击上报 apply_damage(hero, 终值)——调用序钉死:倒序会读到下一拍
  ③ 推进 advance(u)——存活才推进(先作用后推进)
当前拍作用:attack = atk 点伤害 · charge = 空拍不兑付 · heavy = atk × 倍率
轮到前被杀 → 本拍不打、指针冻结(MVP 无复活 → 永久冻结)
battle_over(B1 调 despawn_all)→ 全部单位消亡,不跨战斗
出口 触发 动作/去向 约束
单位死亡 hp = 0(判定时机归 B1) 移出顺位、不再作用、不计入"未灭" 不可逆(MVP 无复活);Dead 句柄保留只读可查(query_beat 冻结值)
敌全灭 存活敌集 = ∅ "敌人全灭"成立 → B1 胜利判定素材;单体/AOE 无有效目标;敌侧伏击池随轮末衰减自然清空 判定逻辑归 B1
主角死亡 hero hp = 0 战斗失败判定素材(判定时机归 B1) battle_over → 全部单位 Despawned——不存在"主角死后敌继续攻击"的中间态
battle_over B1 编排 despawn_all 全部单位状态消亡、不跨战斗;唯一出口 = 重新 spawn 重复 despawn_all → false + 诊断;Despawned 为逻辑失效态(查询空 + 诊断)

单位与状态

状态 进入条件 行为/出口
Unspawned 构造后未实例化 无接口副作用;唯一出口 = B1 编排实例化
Alive 实例化(行值快照 / hp 入参) 可被指定目标(顺位)、按行为环作用、计入全灭判定;受击 hp 递减
Dead hp = 0(判定时机归 B1) 移出顺位、不再作用、不计入"未灭";不可逆;句柄保留只读可查(query_beat 冻结值)
Despawned battle_over(B1 despawn_all) 逻辑失效态——失效句柄查询返回空 + 诊断、作用接口拒绝;唯一出口 = 重新 spawn

不变式(debug 断言口径):hp ∈ [0, max_hp];敌单位数 = 本战实例化数(战斗内不增);行为环指针 ∈ [0, 环长);违规 = debug 断言中止(进程致命保留给 D2 数据通道)。

规则:

  1. 主角和敌人共用同一套受伤与死亡规则:战斗场上恰两类单位(主角一个、敌人若干),共用同一套身体语义——每单位有当前血量与上限,挨打血量往下减,到 0 即死亡;超上限/负数/溢杀与"何时算死"归 B1 结算公式域裁决,B2 只提供受击上报与状态查询接口、如实记账。主角血量归零 = 失败判定素材、敌人全部归零 = 胜利判定素材,判定本身归 B1。
  2. 敌人系统自己不主动做事,一切等结算编排来调:B2 不产生随机数、不碰界面、不订阅任何事件——挖雷、插旗等棋盘事实经 B1 转化后由它调用;B2 只摆出查状态(血量/当前拍/顺位/存活)与受动作(受击/推进/消亡)两组能力,什么时候调、按什么顺序调全归 B1。

敌人构成与名录

规则:

  1. 一场战斗 1–3 个同种敌人,敌方效果对全体生效:MVP 每场战斗 1–3 个敌人,全部同种同属性——同一 EnemyTable 行实例化、按行主序排生成序;战斗中敌人只减不增(不做召唤/增援/分裂——EC5,出现即 debug 断言中止)。敌方增益/减益 side-wide:作用于所有存活敌人、层数进一个共享池(F2 池共享不消耗;B3 现接口零改动兼容);"只作用于某一个敌人"的单体寻址暂不开放,target_ref 登记为 B3 扩展位义务(首个单体效果上线时补列,随批 B1 归集语义/D1 呈现裁决)。
  2. 敌种按关卡坐标存放,每个坐标只出一种:EnemyTable 以(关卡序号 × 节点深度)为坐标存放敌人,每行集恰一敌种(行集内 enemy_id 唯一 = 表结构校验,配出两种加载期致命——既无"同点随机挑一种"的选择规则,也无引用悬空风险);同一关内随深度换敌种合法;"同深度多敌种怎么选"归 C1/C3(预留结构位);精英/Boss 修饰在现键结构下无编码位(预登记 OQ7,C1 定稿时强制核对);名录扩容归垂直切片/Alpha。
敌种 行为环 armor_type 说明
goblin(地精) [attack](环长 1,mod 1 恒等) none 每拍 attack、无自然空窗(兑付率 ρ=1——EC10)
bugbear(熊地精) [attack, charge, heavy](三拍环) a heavy_multiplier = 2
ogre_chief(食人魔酋长) [attack, attack, charge, heavy](四拍 Boss 环) b heavy_multiplier = 2

现行名录 = {goblin, bugbear, ogre_chief} 三敌种(以 registry enemy.mvp_content 为准);各行 hp/atk/unit_count 数值全部 provisional、曲线调参所有权归 C3;遭遇分布调参所有权归难度域(防多样性无护栏,勿照抄任何示例分布)。设计意图:名录小、坐标单敌种——加载期就把配置错误杀死,选择规则留给遭遇域。

行为环

规则:

  1. 敌人按排好的剧本轮流出招,走到哪一拍零随机:每种敌人一条行为环——战斗开始指向第一步,之后每结算一次走一格、先把当前拍的招打出去再走格(先作用后推进);环尾回环首;跨轮次、跨扫雷图延续(EC11,除 despawn_all 外无任何重置入口);轮到它之前被打死 → 本拍不出手、指针就地冻结(死亡即不动手——EC1;MVP 无复活 → 永久冻结);行动完成后才死 → 已行动已推进;同种敌人永远同拍(同步性质——EC2);heavy 拍前被杀 → 重击永不兑现(抢杀窗口——EC9)。全程零随机,走到哪一拍由结算次数唯一决定。行为环敌单位专属:主角无行为环,对主角调环接口一律拒绝(false / 空 + 诊断)。MVP 只启用 attack/charge/heavy 三种拍,后四类为预留语义位、配进表会被校验拒绝(fail-fast;启用走本 GDD 修订非调参——枚举封闭性)。
值 MVP 状态 语义
attack 实现 本结算对主角造成 atk 点伤害
charge 实现 本结算不作用——威胁空拍、规划窗口;不兑付伏击(不读池)
heavy 实现 atk × heavy_multiplier
guard 预留(校验拒绝) 自防
boost 预留(校验拒绝) 自体强化
hinder 预留(校验拒绝) 妨害雷图——敌方向棋盘施加变异类妨害
summon 预留(校验拒绝) 召唤增援
项 细则
指针与推进 战斗开始 beat = pattern[0]、steps = 0;每次结算推进一格——先作用后推进(B3"先兑付后衰减"同款时序哲学);轮到该单位时仍存活才行动并推进(每结算恰一次 = B1 义务①)
死亡口径 轮到前被杀 → 本拍不打、指针冻结(F1 承载);行动完成后才死 → 已行动已推进
回绕与延续 环尾回环首;指针 ∈ [0, 环长),环长 1(goblin)退化为恒等;跨轮次、跨扫雷图延续;battle_over 随单位消亡,除 despawn_all 外无重置入口
确定性与专属域 零随机——环推进是结算次数的确定函数(rng_service 流封闭);主角无行为环,advance/query_beat 等环接口对主角句柄一律拒绝(false / 空 + 诊断)
实现域 pattern 环长 [1, 8];MVP 校验域 = {attack, charge, heavy};EnemyTable.pattern 校验拒绝预留值(fail-fast,A1 solver_rules 冻结先例)

设计意图:确定性环 = 可学习性来源——读怪收益(抢在重击前击杀)由此产生。

伏击

规则:

  1. 每踩一颗雷敌方叠一层伏击——一轮封顶、超出可见不生效:挖开雷格时敌方全体获得一层"伏击"——MVP 伏击清单只有伏击这一条(StatusEffectTable mine_hit 来源的唯一效果行;将来加新词条要 B3 加行并连锁更新锚点,不属于 MVP)。转化路径:棋盘上报"挖到雷"→ B1 转成一次伏击施加(作用全体敌人、共享层数池),每颗雷恰转化一次(B1 义务②)。单轮授予上限 = cap 行值:上限内逐颗叠加;达到上限后多踩的雷不生效,但逐颗记一行"溢出未生效"结算明细(B1 义务⑥)——惩罚不静默蒸发。
  2. 一层伏击 = 敌人每次攻击多打 3 点固定伤害:一层伏击 = 每次攻击类行为(普攻或重击)额外附加 m_amb(provisional 3)点伤害,按主角血量点数计;附加是后置加法、不进重击倍乘(倍率只乘基础伤害);蓄力拍不出手、不附加(charge 不读池——EC8:蓄力轮授予的伏击层当轮全部蒸发,合法推论 + 读怪奖励,D5 教学条目)。伏击只活一轮——每轮结算清零、没有跨轮存量(dur=1,池衰减归 B3),跨轮累计没有表值上界;同结算内授予先于兑付(EC17——本轮踩的雷当轮即兑付,若该轮有攻击拍;读值语义归 B2、次序归 B1 义务①②)。
单轮伏击上限(cap 行值) 行为
默认 4 前 4 颗雷各叠一层;第 5 颗起每颗记一行"溢出未生效"明细
调到 8 及以上 单轮雷数至多 8 颗、达不到上限——溢出协议自然不可达
0 该行敌种免疫伏击——每颗雷都记"溢出未生效",全部可见、全部无效(EC6;该遭遇条款 3 右臂仅剩基线伤)

设计意图:惩罚有源可溯、有顶可见——cap 默认 4 是单轮 5–8 雷灾难轮(EC7)的反灾难护栏。

目标选择与读怪

规则:

  1. 敌方打主角不用挑,玩家侧永远先打排最前的敌人:敌方一侧没有选择可言——所有存活敌人各自按当前拍作用于主角(己方唯一单位,天然唯一目标)。玩家/道具一侧用固定顺位:单体效果默认打生成序最前的存活敌人,它死了顺延到下一个;范围效果(AOE)打全体存活敌人,同样无需选择;unit_count = 1 时顺位顺延与 AOE 分流无消费者、AOE ≡ 单体——合法退化非错误(EC15)。道具自带"指定目标"语义的扩展归 B4/结算域;顺位必须对玩家可读——"下一个被打的是谁"要能推测出来(D1 义务③)。
  2. 敌人要出什么招靠看图推测,不直接报数字:界面不直接显示敌人下一拍的行为与数值——威胁靠看图推测(它弓起背,下一拍就是重击);即将执行的一拍在挖掘阶段全程亮出;映射每局恒定、禁止重掷(否则读怪退化成猜怪);精确数字只在结算明细兑现。线索清单与图像规格归 D1/B5,映射键 = enemy_id(B3 effect_id→icon 同款契约);MVP 读怪对象最长 3 拍环,学习成本低。
# 规格 内容
① 图像↔行为映射稳定可学 同一敌种同一行为恒同一视觉状态(如 bugbear 蓄力拍 = 蓄力姿态)
② 形态暗示强度 敌种形态承载强度档位与环长的直觉编码("大个子多半有重击"式)
③ 映射每 run 恒定 禁止重掷——否则"读怪"退化"猜怪";映射键 = enemy_id
④ 精确数值在结算明细兑现 预告面是图像、数字面是明细
⑤ 预告时序锁定 视觉状态呈现即将执行的一拍(当前拍预告)——挖掘阶段全程可见;结算时不另设独立意图播片(结算明细是数字兑现面、非意图预告面)

设计意图:读怪是规划素材;映射重掷 = 读怪退化成猜怪(P1 裁剪判据)。

主角与实例化

规则:

  1. 主角数值在英雄表里——血量上限加恒在的基础攻击:主角战斗数值单独放一张全局单行的 HeroTable(B2 是回填 owner,走 D2 接口漂移规则回写),max_hp 与 atk 两字段。基础攻击恒存在、不许为 0——零基线乘任何百分比增益恒为零,这个死锁从数据层就进不来(atk = 0 加载期校验拒绝)。每次结算的战斗段主角先手攻击顺位最前的存活敌人——先于敌方行动;攻击是固定动作、不是行为环一拍;伤害算式/乘区/明细行协议归 B1 战斗段。attack_up(+50 percent)的唯一消费面就是这次先手攻击;道具伤害是恒定表值、不吃修正。战斗开始血量由编排方入参供给(越界拒绝——EC16:> max_hp 或 ≤ 0 → false + 诊断、不留半实例化;MVP 冒烟以血量上限入参),跨战斗是否保留归 C1/C2;解锁成长归 C4、曲线调参归 C3。胜利路径 = 基础攻击 + 奖励侧规划面伤害共同兑付"敌人全灭 → 战斗胜利",每一分伤害逐行标注来源(hero_attack / 道具逐件实例)。
  2. 开战按坐标读表生成敌人,数值是生成那一刻的快照:战斗开始时编排方给出遭遇坐标(关卡序号 + 节点深度),B2 据此从 EnemyTable 精确匹配一行(D2 R1 进度键 floor + enemy_id 精确匹配,悬空致命、坐标越界前置守卫——EC13/EC14 走 D2 通道),实例化"本战实际数量 n"个敌单位——n 由 B1 开战掷的 encounter 骰从数量区间 [unit_count, unit_count_max] 定出(定值行取表值);主角同时以血量入参生成。实例化拿到的是当时表值的快照:之后热重载改表,已生成单位一概不受影响(EC12,B3 EC9 先例)。难度成长走双通道:表值随坐标加深而变 + C3 整体修饰——修饰施加点 = 行值快照之前套乘,MVP 难度表为空、零修饰(registry difficulty_table,算式归 C3);B2 一律按实例化后的数值运作。

数据表 Schema

EnemyTable(D2 承载,键 (level_index, node_depth, enemy_id),B2 回填 owner)

进度键 floor(D2 R1)+ 实体键精确匹配;每行集恰一敌种(表结构校验,违规加载期致命);本表是进度成长表(A1 BoardGenTable 同型,无 Rule 4 豁免);表非空(D2 Rule 6)。

字段 类型/范围 语义
enemy_id String(行集内主键) 实体键精确匹配(D2 Rule 4);意图视觉映射键
display_name String 图例/HUD/明细用名(本地化归 D6)
unit_count int [1, 3] 遭遇区间下界(knob;区间 [unit_count, unit_count_max] 经 B1 encounter 骰定本战实际数量)
unit_count_max int [unit_count, 3],可省略 遭遇区间上界(缺省 = 定值,旧行零迁移)
armor_type enum {none, a, b},缺省 none 护甲类型(克制矩阵 = SettlementTable.armor_effectiveness;MVP 映射 goblin=none / bugbear=a / ogre_chief=b)
hp int [1, 999] 单位最大生命基线(knob;难度修饰前)
atk int [0, 999] 攻击基线(knob;0 合法 = 纯伏击伤敌种)
heavy_multiplier int [1, 16] heavy 倍率(knob;无 heavy 拍的敌种不消费——非校验项,B3 max_stack 先例)
pattern StringList(环长 [1, 8]) 行为环(元素 ∈ {attack, charge, heavy} 为 MVP 校验域;预留值校验拒绝)
advantage_per_round_cap int [0, 16] 单轮伏击授予上限(knob,默认 4 定稿;条款 3 供给表值;0 = 免疫伏击的合法极端)

HeroTable(D2 新增 schema 行,单行全局,B2 回填 owner)

主角不随关卡自动成长(成长 = 天赋 C4 / 奖励侧);Rule 4 豁免同 ActionEconomyTable 先例。

字段 类型/范围 语义
max_hp int [1, 999] 主角最大生命(knob,MVP 值 provisional 出处待查)
atk int [1, 999] 基础攻击(knob,MVP = 6 原型锚 provisional 归 C3;0 = 加载期校验拒绝——零基线死锁自 schema 层杜绝)

数值公式(F1–F4 结论)

全部公式零随机、同输入恒同输出(可回放前提)。术语:拍 = 行为环里的一格行动;伏击池 = 敌方侧共享的伏击层数(本轮踩几颗雷就几层,轮末清零);溢出 = 单轮踩雷超过 cap 的部分(转化为明细行可见、不生效)。推导与论证见 analysis 件。

F1 行为环推进(ring_advance)

结论:beat(u) = pattern[steps_u mod 环长]、行动完成后 steps_u + 1;指针恒 ∈ [0, 环长)、环长 1 退化为恒等;死亡即不动手——轮到前被杀本拍不打、步数冻结(永久);同种单位同指环首且每结算各恰推进一次 ⇒ 存活者永远同拍(同步性质定理)。

beat(u)  = pattern[steps_u mod 环长]      行动前读拍;战斗开始 steps_u = 0(指向环首)
steps_u' = steps_u + 1                    行动完成后推进(先作用后推进)
轮到前被杀 → steps_u 冻结(死亡即不动手);行动完成后才死 → 已行动已推进

边界:归 B2——指针所有权、存活校验、冻结不变式、环首初始化、跨轮跨图延续;归 B1——死亡判定时机、结算内先后次序、每结算恰一次推进。

F2 攻击行为裸伤害构成(raw_attack_damage)

结论:attack 拍 D = atk + m_amb × L、heavy 拍 D = atk × heavy_multiplier + m_amb × L、charge 拍 D = 0(不读伏击池);伏击附加是后置加法、不进倍乘;池共享不消耗(同结算多敌读同一 L,非均分、非先到先得);B2 向 B1 供(基线, 伏击)分量二元组(结算明细"伏击 +N"归因行的数据源)。

attack 拍:D = atk + m_amb × L                m_amb = StatusEffectTable.ambush.magnitude(provisional 3)
heavy 拍:D = atk × heavy_multiplier + m_amb × L
charge 拍:D = 0                              不读伏击池——空拍零兑付

读数:合成序判别例——bugbear(atk=4, mult=2)heavy 拍 L=4 → 4×2 + 12 = 20(塞进倍乘得 (4+12)×2 = 32 ≠ 20);单结算单单位附加上界 = cap × 3 = 12(默认,L ≤ min(雷数, cap));无负值分支——clamp/地板/hero 侧减伤合成归 B1。

F3 伏击授予与溢出(ambush_grant_overflow)

结论:granted_r = min(当轮新开雷数, cap)(cap 判定在授予前——B1 预截流);overflow_r = 当轮雷数 − granted_r(每颗溢出雷一行"溢出未生效"明细、含来源);L_r = granted_r(当轮兑付一次、轮末全清、无跨轮存量);守恒 granted + overflow = 当轮雷数、零静默蒸发;max_stack = 16 结构不可达(dur=1 ∧ AP ≤ 8 承载——死护栏非死字段)。

granted_r  = min(当轮新开雷数, cap)          cap 判定在授予前(B1 预截流)
overflow_r = 当轮新开雷数 − granted_r        每颗溢出雷一行"溢出未生效"明细(含来源)
L_r        = granted_r                       只活一结算:当轮兑付一次、轮末全清

变量域:mines_r ∈ [0, 8](结构界 = AP;复开不可能——A2 棋盘面语义);cap ∈ [0, 16] 默认 4(行值 knob;0 = 免疫伏击、全溢出可见);granted_r ∈ [0, 4](B1 编排期逐雷 apply_effect、每雷恰一次转化)。边界:归 B1——预截流编排、授予次序(行主序雷格序为建议序)、每雷恰一次、溢出行协议。

F4 条款 3 供给口径(clause3_supply)

结论:每结算敌方伏击暴露 = k × L × m_amb(k = 本结算存活敌中攻击/重击拍的单位数,确定性可算);每结算结构上界 = unit_count × min(AP 上界, cap) × m_amb(cap > AP 界时 cap 腿松弛);跨结算累计 = 轨迹量、非表值、不设上界(dur=1 每结算清零);B1 对账取"每结算"口径即可闭合、无需战斗长度假设。

每结算敌方伏击暴露(精确式)= k × L × m_amb
每结算结构上界 = unit_count × min(AP 上界, cap) × m_amb
跨结算累计 = 轨迹量,非表值、不设上界

读数:默认满配上界 = 3 × min(8, 4) × 3 = 36;cap ≥ 8 时真可达上界 72(而非 144);默认行值 unit_count = 1 下 = 12。

依赖与输出

B2 编排被动——调用权集中归 B1;A2/A3/A1 事实均经 B1 结算编排转化,零直接接口。registry / 接口漂移回写义务(R-1–R-4)与双向一致性核对记录见 analysis 附录。

方向 系统 性质 接口要点
上游 D2 hard EnemyTable schema + 行回填(B2 为回填 owner)+ HeroTable 新增(走 D2 接口漂移规则回写)+ ConfigDB 单点读取(R1 行解析)
下游 B1 hard(provisional) 单位状态查询/受击/推进接口(冒烟 API 面)+ 义务①–⑥(缺项即 blocking,见下表)
相邻 B3 零运行时依赖 ambush/weaken 量纲与作用域验收锚归 B2;side-wide MVP 兼容(B3 接口零变更);target_ref 扩展位义务
下游 B4 soft(provisional) 伤害道具默认目标消费(固定顺位);伏击清单扩展联动修订;attack_up 消费面 = 主角战斗段先手攻击;道具/增益 = 基础攻击之外的规划面伤害
间接 A2/A3 零直接接口 雷/旗事实经 B1 转化;AP 界(单轮开雷 ≤ 8)= cap 默认值结构来源;weaken 档位锚归 B4/B1
间接 A1 — 雷数分布影响伏击吞吐——条款 3 对账消费 A1 actuals p10(B1 义务,非 B2 域)
下游 C3 soft(provisional) 难度修饰施加点/算式归 C3;两表曲线数值调参所有权归 C3;多敌种同深度选择规则共裁;新敌种投放节奏 = 关卡命脉(goblin 单拍环证伪项 OQ8)
下游 C1 soft(provisional) 遭遇构成(战斗触发、(L,D) 供给、unit_count 覆盖语义)归 C1;跨战斗 HP 持久性归 C1/C2
下游 D1 soft 视觉推测型呈现义务①–④(缺项即 blocking);敌单位 HUD(血条/顺位/姿态)呈现
下游 B5 soft 行为环视觉状态表现(蓄力姿态等——预告时序规格⑤);结算明细敌方行呈现(数据源 = B1 流水)
下游 D5 soft 读怪教学(敌种环模式可学、顺位规则)+ "蓄力拍前放心贪雷"教学 + 首次蓄力姿态一次性提示候选

义务台账(活契约,缺项即 blocking)

对外引用口径:B1 清单引用名「B2 义务①–⑥」(b1-settlement 上游表同口径);D1 清单引用名「D1 呈现义务①–④」。

编号 内容 对侧 状态
B1-① 单位接口调用集中在结算编排、行为环推进每结算恰一次(double-advance 无守卫——信任编排);结算内调用序成文:query_attack → apply_damage → advance(倒序会读到下一拍),B1 冒烟须回放结算步流 B1 已登记 · 缺项即 blocking
B1-② 雷→伏击事实转化恰一次(每颗雷格实例至多一次) B1 已登记 · 缺项即 blocking
B1-③ 伤害 clamp/负值/溢杀语义与死亡判定时机成文 B1 已登记 · 缺项即 blocking
B1-④ 条款 3 闭合对账:消费 B2 cap 表值 + 伏击量纲 + A1 actuals p10(非 target 参数) B1 已登记 · 缺项即 blocking
B1-⑤ 默认目标规则消费与单体/AOE 分流(顺位快照 = 生成序) B1 已登记 · 缺项即 blocking
B1-⑥ 伏击 cap 溢出的"溢出未生效"明细行协议(呈现归 B5/D1) B1 已登记 · 缺项即 blocking
D1-① enemy_id→图像线索映射清单成文(形态/姿态↔行为状态;预告时序 = 下一拍预告、挖掘期全程可见;含强度档位与环长直觉编码说明;形状+色相双通道,art-bible 约束) D1 已登记 · 缺项即 blocking
D1-② 线索映射全局恒定(映射键 = enemy_id——跨 run 恒定、禁止重掷) D1 已登记 · 缺项即 blocking
D1-③ 单位顺位与存活可读(固定顺位规则的推测前提;顺位标记资产需求见呈现契约 #3) D1 已登记 · 缺项即 blocking
D1-④ 敌方 side 池状态呈现口径(伏击层数经 B1 流水——B3 敌侧延伸) D1 已登记 · 缺项即 blocking

呈现契约(数据面义务——B2 无自有渲染面,呈现归 D1/B5)

# 数据面义务 归属
1 敌种视觉身份:双敌种剪影一眼可辨(形状+颜色双通道、色弱可用);形态承载强度档位直觉编码 D1/B5,art-bible 约束
2 行为环视觉状态:每敌种每类行为(attack/charge/heavy)对应恒定且互异的视觉状态,映射每 run 恒定禁止重掷;MVP 清单 = goblin 1 态(攻击)、bugbear 3 态(攻击/蓄力/重击) D1/B5
3 资产需求下限:受击反馈(多敌同屏"谁挨了打"归因前提——两敌种可共用通用一组、须显式登记)+ 死亡表现("重击被掐灭"兑付可见——死亡瞬间可辨识、不得直接消失)+ 顺位标记呈现元素;D1/B5 照单生产、不得隐式缺席 D1/B5
4 单位呈现数据供给:hp/max_hp、顺位、存活态、当前拍视觉状态——数据源 = B2 单位状态查询(经 B1 编排流水) D1
5 敌方增益呈现:伏击池层数 HUD 口径(数据源 = B1 流水经 B3 投影);结算明细敌方行使用分量二元组("攻击 13 = 基线 4 + 伏击 9") D1/B5
6 视觉锚适用:血条/伤害数字暗色底高对比(锚 1);敌单位出现在棋盘上还是独立战斗场景 = B5 前"战斗表现美术测试"锁定,B2 只锁数据面不预设舞台;敌人层绘制优先级插入位置(姿态精灵与数字/旗/小人遮挡关系)随美术测试一并裁决 D1/B5 / art-bible
7 UI 三项:敌单位 HUD、结算明细敌方行(分量二元组 + 伏击溢出行)、教学口径;MVP 无敌图鉴/敌人列表 UI(名录学习成本内,扩展时再议) D1/B5/D5
8 音频:MVP 无需求(攻击/死亡/蓄力音效归 D4 Alpha);蓄力拍音频前摇 = 读招潜在第二通道,登记为垂直切片可选项 D4

P0 最小闭环

  1. 战斗开始:B1 调 spawn——按遭遇坐标读表、行值快照实例化 n 个敌单位 + 主角(hp 入参),指针指向环首。
  2. 玩家挖掘扫雷;踩雷事实经 B1 转化为伏击施加(每雷恰一次、cap 截流、溢出记账)。
  3. 结算开始:主角先手攻击顺位最前的存活敌人。
  4. 每个存活敌单位读当前拍:attack/heavy 兑付(基线 + 伏击附加),charge 空拍。
  5. 受击上报、hp 递减;hp = 0 移出顺位(死亡即不动手)。
  6. 存活敌单位各推进一格(先作用后推进,环尾回环首)。
  7. 敌全灭 → "敌人全灭"成立,回流 B1 作胜利判定素材;英雄归零 → 失败判定素材。
  8. battle_over:despawn_all 全部单位消亡,不跨战斗;下一场重新 spawn。

P1 / P2 后置

优先级 内容 后置原因
P1 预留行为拍 guard/boost/hinder/summon 启用 枚举封闭——启用 = 本 GDD 修订非调参;垂直切片/Alpha
P1 敌种名录扩容与新敌种投放节奏 投放节奏 = 关卡命脉(C3 所有权);垂直切片/Alpha
P1 target_ref 单体寻址(B3 扩展位) 首个单体效果上线时补列,随批 B1 归集语义/D1 呈现裁决
P1 蓄力拍音频前摇(读招第二通道) 垂直切片可选项,非 MVP 义务
P2 敌图鉴/敌人列表 UI 名录学习成本内;名录扩展时再议(垂直切片)
P2 精英/Boss 遭遇编码位(改键,如追加 encounter_class 维度) 现键结构无编码位;C1 定稿强制核对,改键走 D2 Rule 4 接口漂移(OQ7)

调参表

字段 域 默认 owner 说明
EnemyTable.unit_count int [1, 3] 1(provisional) C3 遭遇区间下界;B1 encounter 骰定本战实际数量
EnemyTable.unit_count_max int [unit_count, 3],可省略 缺省 = 定值 C3 遭遇区间上界
EnemyTable.hp int [1, 999] provisional(出处待查) C3 难度修饰前基线
EnemyTable.atk int [0, 999] provisional(出处待查) C3 0 合法 = 纯伏击伤敌种
EnemyTable.heavy_multiplier int [1, 16] 2(provisional) C3 无 heavy 拍不消费、非校验项
EnemyTable.advantage_per_round_cap int [0, 16] 4(本 GDD 定稿) B2 条款 3 供给表值;0 = 免疫伏击合法极端
HeroTable.max_hp int [1, 999] provisional(出处待查) C3
HeroTable.atk int [1, 999] 6(原型锚 provisional) C3 0 = 加载期校验拒绝(基础攻击恒在)
  • 非 knob(结构冻结):行为枚举七类封闭、死亡即不动手、先作用后推进、伏击池共享读法、合成序后置加法、伏击量纲 = HP 点、固定顺位规则、每行集恰一敌种、零随机——修订走本 GDD 流程。
  • Knob 交互:cap × atk(支配边界 L* 联动)、unit_count × cap(单结算上界双线性)、heavy_multiplier × atk(heavy 拍支配)——禁止独立调参,联动评估归 B1 条款 3 闭合对账;pattern 内容(环长/charge 占比 → 兑付率 ρ)属内容行调参,所有权归 C3。
  • 零伤害死局护栏:hero atk=0 已被 HeroTable 域下界结构杜绝;残余退化 = 行 atk=0 且 cap=0 → 无威胁敌(内容调参禁区注记,非死局——OQ9);跨表量级护栏(atk×mult 上界 vs max_hp 域)owner = 实现期 ADR/D2;混编遭遇下 side 池 cap 取哪行值未定义——现结构恒单行值,混编引入时随 OQ7 改键一并裁决。
  • 调参所有权:MVP 全部默认值 provisional、曲线数值归 C3;B1 条款 3 对账落定前,cap 与伏击量纲相关联调须重跑方向性预检并同步 registry(接口漂移义务)。

验收标准

口径摘要:B2 是单位层纯逻辑类——冒烟载体 = godot --headless --script;B1 未实现期间冒烟脚本扮演编排方,按"实例化 → 查询 → 受击 → 推进 → 消亡"序列驱动(B1 就绪后改走真实调用方、断言口径不变);每用例全新实例;期望值按表读值推导不写死;返回 = 受理/拒绝布尔 + debug 诊断(进程致命归 D2 数据通道)。冒烟 API 面、测试口径、夹具策略、覆盖声明与覆盖矩阵见 analysis 附录 B。

AC 清单(Given-When-Then,编号不变)

AC Given When Then 覆盖
AC-1 默认根加载完成、全新容器 spawn(goblin 坐标, M_h);Alive 相位再 spawn 同坐标 首次 true;敌恰 unit_count 个、同 enemy_id、投影五字段(hp/max_hp/atk/pattern/cap)= 行值快照;hero 恰 1、hp = 入参;敌投影序 = 行主序生成序;再 spawn → false + 诊断、容器不变(相位守卫) Rule 2/9/10
AC-2 默认根、全新实例 hero_hp ∈ {M_h+1, 0, −1} 三腿;随后 hero_hp = 1 越界三腿均 false + 诊断且双侧恒空(拒绝原子性、无半实例化);域内下界 → true——拒绝域不扩大 EC16 / Rule 9
AC-3 spawn 完成(bugbear 坐标) 读初拍;连续 advance;goblin 坐标连续 3 次 advance;任意长 advance/受击序列 初拍 = p_e[0];轨迹 = p_e[k mod 环长]、环尾回环首;环长 1 恒 attack(前提 |p_g| = 1 按表读值核对,不满足显式 SKIP);任意序列后状态 = 驱动序列的确定函数、除 despawn_all 外无重置入口 Rule 4 / EC10 / EC11 / F1
AC-4 默认根;前提 p_e[1]=charge 且 p_e[2]=heavy(不满足显式 SKIP) charge 拍后杀死再 advance;heavy 拍 advance 后才死;对 Dead 句柄 apply_damage heavy 前被杀:hp = 0(溢杀 floor)、advance → false 无诊断、beat 冻结于 heavy 前一拍(重击永不兑现);行动后才死:已推进、指针回绕;Dead 受击 → false + 诊断(无复活) EC1 / EC9 / F1
AC-5 夹具根 enemy_multi_unit(u_c = 3,bugbear 行) 三单位读初拍;某步 advance(u2) 前杀 u2;全程观测规模 三单位初拍恒等(同种同指环首);u2 本步不打、指针冻结,幸存者 beat 连续多步恒相同(同步性质定理——EC2);单位数 ∈ {3,2,1} 严格递减、无增员(EC5 负空间行为面) Rule 2 / EC2 / F1
AC-6 默认根 + AC-5 根 逐一致死;杀 hero 后 despawn_all、重复 despawn_all、重新 spawn 全灭 → query_alive(enemy) = 空(胜利判定素材归 B1);hero hp = 0(失败判定素材);despawn → true、双侧空、失效句柄查询空 + 诊断、作用接口 false;重复 despawn → false + 诊断;重新 spawn → true(Despawned 唯一出口) Rule 1 / EC3 / EC4
AC-7 默认根 spawn(bugbear)、m_amb 表读值 attack 拍 query_attack(L=2);heavy 拍 query_attack(L=4) 合成序判别;charge 拍 query_attack(L=c_r);多敌根同 L 重复/多单位 query attack:{baseline = a_e, attach = 2×m_amb, total = a_e + 2×m_amb};heavy:total = a_e×m_e + 4×m_amb 且 ≠ (a_e + 4×m_amb)×m_e(后置加法判别;m_e = 1 时负断言恒等、显式 SKIP);charge:恒 {0,0,0}(不读池——EC8 的 B2 半);同 L 多读逐字相同、多单位读值一致(共享不消耗)、query 前后投影零变化(纯函数——EC17 读值半) F2 / Rule 6 / EC8 / EC17
AC-8 默认根、c_r = cap 表读值 ambush_grant_plan 参数化:mines = c_r+2;mines ∈ {0, 1, c_r, c_r+1};mines ∈ [5, 8];cap = 0 granted = min(mines, c_r)、守恒 granted + overflow = mines(零静默蒸发);灾难轮 granted = 4、overflow = mines − 4(EC7);cap = 0 → granted = 0、overflow = m(EC6 免疫全溢出可见) F3 / EC6 / EC7
AC-9 夹具根 enemy_multi_unit advance 序构造混合拍读暴露;记号恒等式断言 暴露 = k × L × m_amb,k 经只读观测量导出(确定性可算、无隐藏状态);全 charge 轮 k = 0(EC8);结构上界 = u_c × min(AP_r, c_r) × m_amb 记号恒等式(全参表读值/夹具登记值,非定值断言);无跨结算累计观测量(负空间) F4 / EC8
AC-10 腿 1 默认根(u_c=1);腿 2/3 多敌根 default_target();杀 [0] 后再查;连续杀至空 u_c=1 → 唯一存活单位(合法退化——EC15);多敌 → query_alive(enemy)[0](顺位快照 = 生成序);杀最前后顺延;杀至空 → null Rule 7 / EC3 / EC15
AC-11 默认根 spawn 完成、存活与 Dead 并存 测试通道换根加载 enemy_reloaded(非 D2 reload() 路径);despawn 后同坐标重新 spawn;原地改写返回的 pattern 投影 已实例化单位快照五字段 + beat + hp 逐字不变、hero 投影不变(快照抗热重载——EC12);新实例 = 漂移后表值;投影为拷贝非活引用 Rule 10 / EC12
AC-12 EnemyTable schema 类直引实例 validate() 作用于越域代表值(unit_count {0,4}、hp {0,1000}、atk {−1,1000}、mult {0,17}、环长 {0,9}、预留值 "guard"、未知枚举、cap {−1,17})与域内代表值(含 atk=0、cap=0 两合法极端、环长两界);表级构造同坐标两行相异 enemy_id 越域各含对应域错误类别(零静默);表级含每行集恰一敌种错误类别;域内零诊断(防过度约束锁死内容——atk=0 与 cap=0 是承重点) Rule 3/4 / EC6
AC-13 HeroTable schema 类直引实例 validate():max_hp {0,1000}、atk {−1,0,1000} 越域;max_hp/atk ∈ [1,999] 域内;表级构造两行 越域各含域错误类别(atk=0 拒绝 = 基础攻击恒在的 schema 承重腿);域内零诊断;两行 → 单行全局约束错误(落点 = schema 或可选根 hero_extra_row manifest,两处恰一承载) Rule 9
AC-14 默认根加载完成 读 EnemyTable;读 HeroTable 敌种 id 集合 = {goblin, bugbear, ogre_chief}(定值断言);每行集恰一敌种;pattern 元素 ⊆ {attack, charge, heavy};goblin 行 pattern 不含 "heavy";unit_count_max 仅在区间行出现;display_name 非空(本地化归 D6);遭遇分布不作定值断言(C3 域 knob);HeroTable 恰 1 行、atk ∈ [1,999](MVP 值 6 provisional 不作定值断言)、max_hp ∈ [1,999] Rule 3/9
AC-15 全新实例 ×2(同默认根) 同一定长序列驱动两遍(spawn → 受击含轮到前击杀 → 交替 advance → query 投影 → default_target) 两遍的 query_alive 投影序列、逐单位 beat 轨迹、default_target 返回序列逐项相同——零随机行为级硬证据(rng_service 流封闭) Rule 4/11 / F1
AC-16 默认根加载完成 脚本解析 design/registry/entities.yaml 的 enemy 与 hero 条目逐字段对账 ① enemy.fields 十键与 EnemyTable schema 字段名/类型/域逐一相等;② hero.fields 两键同上;③ enemy 注记物种集 = {goblin, bugbear, ogre_chief} 与表行集合相等;④ status_effect.ambush 含 B2 量纲定稿注记(活值 m_amb 不作定值对账——knob 纪律);⑤ hero"单行全局豁免"与 enemy"每行集恰一敌种校验"注记存在 Rule 6 / registry
AC-17 B2 文件集纳入 D2 AC-9 模式项目级扫描域 静态扫描 randomize() / RandomNumberGenerator / ConfigDB 外 data 表加载 / extends Control / .tscn preload 零命中(schema 与容器 class_name 直引实例化豁免);事件订阅 API 零命中;B3 API 符号零引用(相邻零运行时依赖);零随机行为级证据 = AC-15 Rule 11 / D2 AC-9

版本历史

版本 日期 改动
v2 2026-09-14 两件套迁移:按模板 v2 重排——design 只收结论,公式推导、数值锚定论证、候选取舍、体验锚点论证移至 design/gdd/analysis/b2-enemy-system.md;规则/数值/AC/EC/F/OQ 编号与内容全保留,零设计变更
v1.0-lean 2026-09-13 格式迁移:legacy 原稿按 lean 样例重排——修订注记出正文收敛至本表;规则/枚举/边界情况/义务清单/覆盖矩阵/AC 转表格;行为环转字符画;公式、Variables 与验算数据全保留;语义与 2026-09-09 定稿及 2026-09-11 基础攻击裁决对齐,零规则变更
基础攻击裁决批 2026-09-11 HeroTable.atk = 基础攻击恒存在:域 [1,999]、0 加载期校验拒绝(零基线死锁自 schema 层杜绝)、MVP = 6(原型锚 provisional 归 C3);主角每结算战斗段先手攻击;B4 道具/增益转为规划面伤害(非唯一伤害来源);原"atk MVP=0 机制开关、胜利路径依赖 B4 先行"条款与 OQ3 左臂悬空投影退役;OQ9 恒零死局分支随之收窄
C3 修订批回写 2026-09-14 /design-review C3 修订批(X-7 回执,registry 同批):spawn 增 override 参数 n(B1 encounter 骰定本战实际数量——区间语义 [unit_count, unit_count_max] 实例化后不增,EC5 记号调和)· Rule 10 DifficultyTable 接口已定(registry difficulty_table——施加点 = 行值快照前套乘,MVP 空表零修饰)· EnemyTable schema +2 字段(unit_count_max / armor_type——护甲克制批,克制矩阵归 SettlementTable)· 物种集扩容三敌种 {goblin, bugbear, ogre_chief}(AC-14/AC-16① 十键/AC-16③/结构定值断言随批;DND 更名批对齐)· 默认根遭遇分布 = C3 行值总表 v3(provisional)
Rev 1(full 评审批) 2026-09-09 lean 定稿同日 full 评审(六专员 + CD 终裁)8 项 blocking 同日核销后用户拍板收口(A3/A4/A1/B3 同日核销先例、免独立 re-review):① 胜利路径声明 ② AC-7 恒假判别前提 + SKIP ③ 多敌夹具根改 bugbear 行 ④ OQ6 事件源类更正 + F3 重验触发补支 ⑤ 精英/Boss 编码位预登记 OQ7 ⑥ Rule 8 预告时序 ⑦ 资产下限补受击/死亡/顺位 ⑧ 主角推进域排除;同批定稿四项口径:cap 默认 4(旧默认 8 使溢出协议不可达)、死亡即不动手、条款 3 单结算自然边界、C 节三处回写;F2 判别改域内值、F4 结构上界 min 收紧、方向性预检裕度改 2.3×——明细见 design/gdd/reviews/b2-enemy-system-review-log.md
v1(lean 定稿) 2026-09-09 一次会话定稿:十一核心规则 + F1–F4 + 17 AC + 义务台账(B1×6 / D1×4);九项结构决策用户拍板(多敌 / HeroTable / 视觉推测型 / Peglin 行为环 / 每行集恰一敌种 / side-wide / 固定顺位 / unit_count 字段 / cap=4);lean 门禁:systems-designer 起草 Formulas、qa-lead 起草/验证 AC