diff --git a/design/gdd/02-系统清单.md b/design/gdd/02-系统清单.md index 198358f4..ad0e25ff 100644 --- a/design/gdd/02-系统清单.md +++ b/design/gdd/02-系统清单.md @@ -45,6 +45,7 @@ | `关卡节点图生成.md` | 单关节点图的逐局随机来源:图模板池、抽签与实例化(实施排队 ADR-0007 裁决后) | 设计草案·拍板点全落文 | | `冒险结构.md` | 整局冒险的关卡序列、失败与大奖励 | 已定稿·自旧体系迁移 | | `难度曲线与Boss.md` | 难度曲线、期望值带与 Boss 设计 | 已定稿·自旧体系迁移 | +| `特性.md` | 一次冒险内角色自身得到的提升(规则改写型 / 属性加成型两种形态) | 已实现·2026-10-05 新立定义 | ### 跨局循环(`systems/跨局循环/`) @@ -96,6 +97,7 @@ | 冒险循环 | 关卡节点图生成 | `NODE_MAP_GENERATION` | —(新立无旧代号) | | 冒险循环 | 冒险结构 | `ADVENTURE_STRUCTURE` | c2 | | 冒险循环 | 难度曲线与Boss | `DIFFICULTY_CURVE` | c3 | +| 冒险循环 | 特性 | `ADVENTURE_FEATURE` | —(新立无旧代号) | | 跨局循环 | 元进度 | `META_PROGRESS` | c4 | | 表现与支撑 | HUD框架 | `HUD_FRAMEWORK` | d1 | | 表现与支撑 | 数据配置 | `DATA_CONFIG` | d2 | @@ -126,3 +128,4 @@ | v1.0 | 2026-09-27 | 节点图生成立项批(用户拍板立项——06 条目「关卡内结构随机生成」随批改状态):`systems/冒险循环/` 新建 `关卡节点图生成.md` 设计草案 v0.1(图模板/模板池/抽签三概念、三级台阶路线、MC 测量对账条款、五拍板点);文档树补行 + 命名对照表补 `NODE_MAP_GENERATION` 行 | | v1.1 | 2026-09-27 | 关卡画面 UX spec 建档(关卡画面 UX 批):`ux/` 表补 `level-map.md` 行——选路枢纽三停点布局、GP 常驻徽章、交互映射与 AC 成文,三项设计提案挂 06 待拍板 | | v1.2 | 2026-10-03 | R3 清账批(gdd_lint 分域随批):四处状态单元格日期批注迁出——敌人系统行事件见敌人系统.md 版本历史 v0.5(技能池批);元进度行见本表 v0.8;camp/shop 行=两文 v1.0 落文(2026-09-30 三裁决执行批);语义零变更 | +| v1.3 | 2026-10-05 | 立《特性》:一次冒险内角色自身得到的提升——此前按内部分类被叫成三个名字(规则类称"流派件"、属性类称"数值件"、界面称"本关强化"),现收敛为一个对象的两种形态枚举;文档树冒险循环补行 + 命名对照表补 `ADVENTURE_FEATURE` 行 | diff --git a/design/gdd/06-待办清单.md b/design/gdd/06-待办清单.md index dd8a5ea0..cd018c3e 100644 --- a/design/gdd/06-待办清单.md +++ b/design/gdd/06-待办清单.md @@ -27,17 +27,17 @@ #### 冒险 BD 两类加强物品获取同渠道、纯概率差(用户口径:获取途径须区分开,2026-10-04 提问登记) -**现状**:BD 分层口径(用户定):基础 BD(账号级,局外天赋树+同调装配)与冒险 BD(局内一次冒险的构筑)两层;冒险 BD 的加强物品两类——**流派件**(机制件,改规则、带流派标签与档位激活,构筑核心,真正改变局内强度)与**数值件**(属性加成,UI 呈现名「本关强化」,写统一加算区;账本实为冒险域、关间不清零)。现行两类**共用同一获取渠道**:三选一(奖励节点+通关)+ 商店货架 + 格面令牌同属 98 张固定配额池(普通 70/稀有 25/罕见 3),流派件只占稀有/罕见档(与数值大件混编),商店仅「货架零流派件挤掉一张普通卡」保底——获取途径与条件完全相同、仅概率不同,构筑核心的获取节奏纯看脸。 +**现状**:BD 分层口径(用户定):基础 BD(账号级,局外天赋树+同调装配)与冒险 BD(局内一次冒险的构筑)两层;冒险 BD 的加强物 = **特性**(2026-10-05 定名,定义见 [特性](systems/冒险循环/特性.md)):规则改写型(改规则、带流派标签与档位激活,构筑核心)与属性加成型(属性加成,写统一加算区;账本实为冒险域、关间不清零)两种形态。旧称「流派件 / 数值件 / 本关强化」一律作废。现行两类**共用同一获取渠道**:三选一(奖励节点+通关)+ 商店货架 + 格面令牌同属 98 张固定配额池(普通 70/稀有 25/罕见 3),规则改写型只占稀有/罕见档(与属性大件混编),商店仅「货架零规则改写型挤掉一张普通卡」保底——获取途径与条件完全相同、仅概率不同,构筑核心的获取节奏纯看脸。 -**用户期望改动**:将两类的获取途径区分开,流派件获取节奏不依赖纯概率。已呈四备选(均未拍板):① Boss/精英击杀后流派件**专属三选一**,流派件整体退出共享池〔我方推荐:确定性最高,杀戮尖塔/以撒/哈迪斯参照系全支持,与钥石逐杀 Boss 节奏同构;代价=令牌池配额回收+商店保底改向+MC 锚换代〕;② 行为条件投放(累计玩法行为定向出件,防滚雪球工程量大);③ 计步保底(每 N 奖励面必含流派件,改动最小只缓解不根除);④ 双池分离(每面必见流派件,决策密度过强,不推荐)。 +**用户期望改动**:将两种形态的获取途径区分开(规则改写型走战场奖励、属性加成型走商店训练),规则改写型的获取节奏不依赖纯概率。已呈四备选(均未拍板):① Boss/精英击杀后规则改写型**专属三选一**,规则改写型整体退出共享池〔我方推荐:确定性最高,杀戮尖塔/以撒/哈迪斯参照系全支持,与钥石逐杀 Boss 节奏同构;代价=令牌池配额回收+商店保底改向+MC 锚换代〕;② 行为条件投放(累计玩法行为定向出件,防滚雪球工程量大);③ 计步保底(每 N 奖励面必含规则改写型,改动最小只缓解不根除);④ 双池分离(每面必见规则改写型,决策密度过强,不推荐)。 **归属**:[node-reward](ux/node-reward.md)(令牌池与奖励面)+ [冒险结构](systems/冒险循环/冒险结构.md)(商店货架保底);与上条「双层 BD 延期与备选内容总登记」二期件组相关但不同面。 **状态**:待讨论(2026-10-04 用户提问登记,后续展开) -#### 内部分类禁写入玩家可见面——流派件呈现三处违规待改(2026-10-04 用户立意登记) +#### 内部分类禁写入玩家可见面——特性呈现三处违规待改(2026-10-04 用户立意登记) -**现状**:用户立意(方向已明确):流派/数值等内部分类**不得写进玩家可见的道具名称、介绍词或界面**——玩家可根据效果自行推断类别,游戏不得直接点破。查证实态:26 件流派件 display_name 全风味名(奥术余烬/贯穿射击/矿工的执拗等,合规,符合 2026-09-29 playnote 既有批评);**违规三处**(均系迭代 12 呈现补齐批所落,承载用户「局内奖励选了什么看不到」反馈——缺口承载需求仍成立,撤的只是分类字样):① 三选一+商店流派件卡面第二行印流派名(`battle_narrator.gd` relic_card_text,「奥术余烬 · 魔法」式);② 战斗屏 C 区列表标题「流派件」+逐流派聚合行「魔法 ×2 · 档一」(`hero_info_panel_view.gd` + `hud_presenter.gd` relic_holdings_lines);③ 关卡选择页复用同一聚合文案(`level_map_screen.gd`)。**边界**:效果摘要行(「普攻附加必中伤害」)保留——那是件本身在做什么,是玩家推断归类的依据。 +**现状**:用户立意(方向已明确):形态(规则改写型/属性加成型)等内部分类**不得写进玩家可见的名称、介绍词或界面**——玩家可根据效果自行推断类别,游戏不得直接点破。查证实态:26 项规则改写型特性的 display_name 全风味名(奥术余烬/贯穿射击/矿工的执拗等,合规,符合 2026-09-29 playnote 既有批评);**违规三处**(均系迭代 12 呈现补齐批所落,承载用户「局内奖励选了什么看不到」反馈——缺口承载需求仍成立,撤的只是分类字样):① 三选一+商店特性卡面第二行印流派名(`battle_narrator.gd` relic_card_text,「奥术余烬 · 魔法」式);② 战斗屏 C 区列表标题(现为「特性」)+逐流派聚合行「魔法 ×2 · 档一」(`hero_info_panel_view.gd` + `hud_presenter.gd` relic_holdings_lines);③ 关卡选择页复用同一聚合文案(`level_map_screen.gd`)。**边界**:效果摘要行(「普攻附加必中伤害」)保留——那是件本身在做什么,是玩家推断归类的依据。 **连带裁点**:档位激活(同标签 2 件档一/4 件档二)若完全不呈现,玩家只能靠悟——三路待裁:甲=纯隐藏、机制照跑(以撒套装式,最贴用户「流派是玩家挖掘出来的」原则);乙=档位达成那一刻给一次性风味反馈、不点破流派名;丙=连档位机制一起退役。 @@ -45,6 +45,12 @@ **状态**:方向已明确(禁写类别),违规改法与档位呈现三路待讨论(2026-10-04 登记,后续展开) +#### 特性命名统一后续——代码标识符与文件名的对齐(2026-10-05 立) + +**现状**:概念已统一为「特性」(定义见 [特性](systems/冒险循环/特性.md))。本期完成三件——① 定义文档落位;② 称谓统一(代码注释与玩家可见文案,94 处);③ 数据层标识符统一(`adventure_table.gd` / `adventure.tres` 的常量与字段整体换到 feature_* 词族,112 处,值零变更)。**未完三件**:① 规则改写型那套的 relic 词族(RelicTable / relics.tres / relic_id / _relics)与统一词族对齐——文件名与 class_name 改名须同步 Godot `.uid` 与 `.tscn` 引用,非文本层可自证;② 运行层标识符(`_bonus_deck` / `bonus` 加算区 / `_bonus_taken` / `pick_bonus` / BonusInteractController / BonusPickOverlay)换名;③ 断点与存档键(`bonus_deck` / `bonus_taken` / `bonus_pending` / `bonus_result` / `bonus_aux_carry`)为存档兼容沿用历史名,是否随存档版本迁移一并换名待定。 + +**状态**:待实施——须在可跑冒烟的迭代批次内完成(本会话按测试执行两入口铁规零测试,改名无法自证) + #### 棋盘战斗键盘/手柄输入(2026-10-04 用户提问登记,排期 Beta) **现状**:战斗棋盘操作现行唯一输入 = 鼠标——左键已开格 = 移动 / 未开格 = 挖掘,右键 = 封印(旗一次性承诺,无拔旗),悬停承载合法性反馈(可挖域微光 + BFS 路径点迹);全仓无 InputEventKey/JoypadButton 处理,project.godot 无自定义 InputMap 动作。**可行性已核(2026-10-04):可做**——分发接缝现成,board_view `action_requested(cell, kind)`(kind ∈ {dig, move, flag_place, flag_pull})是唯一出口,键盘/手柄作第二输入前端产出同款信号即可,规则引擎合法性校验零改动(非法目标两条路径同拦);Godot InputMap 原生支持键盘与手柄(十字键/摇杆)绑定同一动作,与鼠标并存不冲突。用户期望操作形态:十字方向移动;挖掘/封印各一独立键;方向控制选定 8 向挖掘或封印目标(斜向 = 双方向键组合)——8 向恰与现行可挖域(8 向相邻未开格)同集,十字移动与立绘 4 向既有裁决一致;键盘移动语义 = 逐格步进(现行点击 = 任意已开格 BFS 全程,逐格为等价交互变体)。连带设计点(实施批先裁):① 键盘模式需屏上光标格承载现行悬停反馈(无鼠标 hover,合法性指示改挂光标);② 键盘默认键位与手柄键位映射待定;③ 弹层界面(结算/三选一/商店/设置等)现行全鼠标,手柄全覆盖需焦点导航——本条范围 = 棋盘战斗操作,界面焦点导航是否同批待裁;④ 键位自定义是否进设置面待裁。 diff --git a/design/gdd/systems/冒险循环/特性.md b/design/gdd/systems/冒险循环/特性.md new file mode 100644 index 00000000..013fe5db --- /dev/null +++ b/design/gdd/systems/冒险循环/特性.md @@ -0,0 +1,143 @@ +# 特性(Feature) + +> 一次冒险之内,角色**自身得到提升**的载体。它不是包里的东西,而是角色本人的变化——这点决定了它和持有物是两类完全不同的概念,下面的「关联与边界」一节写了怎么区分。 +> +> 同一个概念下有**两种形态**:改写规则的,和抬高属性的。它们是同一个对象的形态枚举值(`form`:规则改写型 / 属性加成型),不是两类东西。 +> +> 状态:**已实现**(2026-10-04 双层 BD 实施批落地)。本文件是特性的唯一定义文档。 +> +> 数值纪律:本文件只写概念、取值域与指路;每件加多少、效果是什么一律不进正文,事实源是 `game/data/tables/relics.tres` 与 `game/data/tables/adventure.tres`。 + +## 设计目的 + +一次冒险要走三关,如果走完时角色和开局毫无区别,中途的每一次取舍就都不算数了。特性就是那个把"这一局玩成了什么样"落下来的东西:让玩家在冒险过程中不断变强,且每一局变强的方向不同。 + +它同时要和跨冒险的成长隔开:永久保留的东西是[魔法道具](../排雷循环/魔法道具.md)(带在身上的物品)与[元进度](../跨局循环/元进度.md)(账号级的树),特性只在当局存在,冒险收束即清零——它不是"你的存档变强了",而是"这一次下矿的你变强了"。 + +**为什么定为"自身提升"而不是"获得物品"**:一旦把它当成捡到的东西,就和魔法道具(持有物)在玩家心里混成一团——而两者的接入方式、生命周期、获取条件都不同。定为自身的提升,边界一句话就能说清:**带在自己身上的是特性,拿在手里的是魔法道具**。 + +## 系统范围 + +| 负责 | 不负责 | +|---|---| +| 特性的定义与形态枚举 | 每件效果怎么接入结算——归挂点所属文档([战斗结算](../战斗循环/战斗结算.md)、[行动经济](../排雷循环/行动经济.md)、[地形变异](../排雷循环/地形变异.md)) | +| 生命周期边界:何时出现、何时生效、何时清零 | 卡面排版与界面呈现细则——见 [HUD框架](../表现与支撑/HUD框架.md) | +| 获取途径的口径与约束 | 魔法道具与元进度——归上表两份文档 | +| 与相邻概念的边界 | 格面资源、关卡节点、商店本身的规则——归各自所属文档 | + +## 在核心循环中的位置 + +``` +【关内】排雷推理 → 战斗结算 → 通关 ──┐ + ├─→ 得到一项特性 ─→ 后续关卡带着它继续 + 奖励节点・商店 ┘ +``` + +特性处在「一次冒险」这一层:它不是一场战斗里的临时状态,也不跨冒险留存。上游是两个获取口,下游是之后所有关卡的排雷与结算——拿到了,下一关就开始生效。 + +## 核心规则 + +### 1. 形态枚举(form) + +特性只有一个名词;需要区分时才描述它的形态,不给形态另起名字。 + +| 形态 | 它改的是什么 | 落在哪里 | 事实源 | +|---|---|---|---| +| `rule` 规则改写型 | 改规则本身:在结算管线的某个挂点上给自己加一条规则;同一标签的持有件数达到阈值时发生质变 | 各结算段挂点;标签与档位由求值服务统一算 | `relics.tres`(逐项定义) | +| `stat` 属性加成型 | 改数值:把自己某项属性抬高,直接改写角色的基础数字 | 冒险加算区(攻击 / 生命上限 / 护甲 / 行动点四轴)、钱包与即时恢复 | `adventure.tres`(配额与值) | + +两种形态的共性:都在当局获得、当局携带、当局失效;都不写账号进度——出现与否由抽取决定,玩家的账号强弱不影响它出现在哪一局。 + +**为什么是同一个对象的两种枚举而不是两个东西**:它们共用一份获取流程、一份持有集、一份生命周期。分成两个名字只会让读者以为有两套系统,而实际上代码里只有一个持有集。 + +### 2. 作用对象与范围 + +- **作用对象**:角色本人,以及角色参与的结算过程。特性不改敌人、不改棋盘生成、不改关卡内容。 +- **时间范围**:整局冒险。两种形态都自获得起对本局剩余所有关卡生效;属性加成型写入加算区后,关与关之间不清零。 +- **归属范围**:不进账号永久进度,不带到下一次冒险。 + +### 3. 生命周期 + +``` +未获得 → 进入候选池 → 作为候选出现 → 选定 → 持有 → 生效 →(冒险收束)清零 + ↑ ↓ + 断点恢复 持有集持续累积 +``` + +| 阶段 | 说明 | +|---|---| +| 候选池构建 | 冒险开局时一次建成。两种形态的候选**现同处一个令牌池**:属性加成型按配额铺开,规则改写型按定义表的有效行铺开。 | +| 出现 | 玩家在两个获取口之一看到若干候选(三选一的形式),看不到整个池。 | +| 选定 | 玩家选定一项后,它从池中剔除,此后任何获取口都不会再见。 | +| 持有与生效 | 进入持有集后立即生效,跨关携带。规则改写型按同一标签的持有项数决定处于哪一档。 | +| 清零 | 冒险以任一结局收束时整集清空;下次开局重建。 | +| 断点恢复 | 进行中的冒险把持有集与剩余候选池一并写入断点,续玩后恢复到同一状态(断点里的键名沿用历史形态,不随本次改名变动)。 | + +### 4. 获取途径 + +| 获取口 | 说明 | 目标渠道分工(尚未实施) | +|---|---|---| +| 战场奖励 | 每关通关给一次三选一(最终关不给——提升只对后续关卡有意义,最终关没有后续);关卡节点图上的奖励节点同样给一次三选一,与之共用同一个候选池。 | 规则改写型今后主要从这里出 | +| 商店 | 花局内金币购买在架的特性;同一种至多一张,买走即从在架令牌移除。 | 属性加成型今后主要从这里出,口径是**训练** | + +**关于商店口径的说明**:商店这一侧走的叙事是「**训练**」——花代价向某位师父学习、借某种卷轴修炼、或把战斗攒下的钱换成一身本领。它不是买一个东西回来,而是把钱换成自己的本领,所以落到命名空间上和奖励那一侧完全相同:都是往同一个持有集里加一项特性。 + +**在册事项**:现行两个获取口完全共用同一个候选池,两种形态出现条件一样、只有出现概率不同。用户已决定把两种形态按渠道分开(规则改写型走战场奖励,属性加成型走商店训练),四个备选方案与执行批次登记在 [06-待办清单](../../06-待办清单.md) 的 BD 分层条目下,本文件不复制。**本文件 4 节表格里的渠道分工写的是目标状态,尚未实施。** + +### 5. 关联与边界 + +| 相邻概念 | 关系(只写关系,不写对方的规则) | +|---|---| +| [魔法道具](../排雷循环/魔法道具.md) | 最需要分清的一对:**魔法道具是拿在手里的物品,特性是角色自身的变化**。两者互不相通——特性永不进同调位,魔法道具永不进当局随机渠道。魔法道具跨冒险保留,特性当局清零。 | +| [元进度](../跨局循环/元进度.md)(树) | 树管账号永久的规则与容量,特性管当局构筑,两层互不代替。 | +| [战斗结算](../战斗循环/战斗结算.md) | 规则改写型的挂点位于结算管线的各段;挂点清单与语义归结算文档。 | +| [行动经济](../排雷循环/行动经济.md)、[地形变异](../排雷循环/地形变异.md) | 部分挂点落在行动点结转与地形处理上,语义归各自文档。 | +| [地图战斗资源](../战斗循环/地图战斗资源.md)(格面资源) | 无关:格面资源是单格的一次性产出,不进持有集。 | +| [关卡节点地图](关卡节点地图.md)、商店 | 是获取口的载体,不是特性的属性。 | +| [存档序列化](../表现与支撑/存档序列化.md) | 断点负载记录持有集与剩余候选池;键名与版本迁移策略归存档文档。 | + +## 依赖与输出 + +| 类型 | 内容 | +|---|---| +| 依赖(概念) | 角色、结算管线、行动点、地形、关卡节点地图、局内金币钱包 | +| 依赖(数据) | `relics.tres`(规则改写型定义行)、`adventure.tres`(属性加成型配额与值)、`shop.tres`(货架取舍) | +| 输出(对外) | 持有集、生效中的形态投影、剩余候选池、档位求值结果 | +| 明确边界 | 不写账号进度、不改敌人与关卡内容、不承载具体数值 | + +## P0 最小闭环 / P1・P2 后置 + +- **P0(已实现)**:两种形态可定义 → 进入候选池 → 在两个获取口之一被选中 → 当局生效 → 收束清零。 +- **P1 后置**:两种形态按渠道分开(见第 4 节的在册事项);两项合成高阶项;同一标签收集到四项以上的后期表达。 +- **P2 后置**:商店里的攻击类型转换服务;喂雷流派是否保留(尚未拍板,登记在 [06-待办清单](../../06-待办清单.md))。 + +## 调参表 + +数值所有权归 [难度曲线与Boss](难度曲线与Boss.md);本文件只列参数与取值域,**不列现行值**。 + +| 参数 | 取值域 | 事实源 | +|---|---|---| +| 规则改写型定义行(标识 / 显示名 / 稀有度 / 标签 / 挂点 / 效果字典) | 各字段封闭枚举,行键白名单封闭 | `game/data/tables/relics.tres` | +| 属性加成型种类 | 封闭词表:攻击 / 生命上限 / 护甲 / 金币 / 行动点 / 恢复 | `game/data/schemas/adventure_table.gd` | +| 属性加成型稀有度档位 | 封闭三档(普通 / 稀有 / 罕见);三档配额是结构锚,改总量须重新拍板而非调参 | 同上 | +| 各形态种类 × 档位的配额与值 | 整数 | `game/data/tables/adventure.tres` | +| 一次三选一的候选展示数 | [1,6] | 同上 | + +## 验收标准 + +1. 两种形态走同一套获取流程,代码里只有一个表示"已持有特性"的集合。 +2. 一次冒险内获得的特性在之后任何关卡都生效;开新冒险后持有集为空。 +3. 一项被选定的特性不再出现在任何后续获取口。 +4. 每个标签至少有一项挂在排雷侧的结算触发点上(防止规则改写型沦为纯战斗数值)。 +5. 玩家可见的文案不出现形态名与内部分类标签——只写效果,归类让玩家自己推断。 +6. 文档与代码里提到它时只有"特性"这一个名字;需要区分形态时用"规则改写型/属性加成型"描述,不得另造称呼。 + +## 待办 + +全部待办单点登记于 [06-待办清单](../../06-待办清单.md)(BD 分层条目、呈现三处待改条目),本节不复制。 + +## 版本历史 + +| 版本 | 日期 | 变更 | +|---|---|---| +| v1.0 | 2026-10-05 | 首次为本概念立定义文档。此前它按内部分类被叫成三个名字,各处互相冲突的定义以本文档为准:统一名词"特性",把原先分开称呼的两类收敛为形态枚举;把性质定为「角色自身得到提升」而非「获得物品」,以此与魔法道具(持有物)划清。 | diff --git a/design/gdd/systems/表现与支撑/HUD框架.md b/design/gdd/systems/表现与支撑/HUD框架.md index bdec3ab5..492afa9e 100644 --- a/design/gdd/systems/表现与支撑/HUD框架.md +++ b/design/gdd/systems/表现与支撑/HUD框架.md @@ -216,7 +216,7 @@ HUD框架站在玩家与全部玩法系统之间:挖掘期它是输入的翻 | [地图战斗资源](../战斗循环/地图战斗资源.md) | 已开格的奖励身份常读;未开格类型微光(英雄周围 8 格内的未开格显示资源类型——概念定义见本篇「未开格类型微光」节) | | [魔法道具](../排雷循环/魔法道具.md) | 库存条常读;使用交互与目标拾取;板级叠加层信息呈现 | | [棋盘生成](../排雷循环/棋盘生成.md) | 零合法板的诚实告知(数据面经战斗结算上抛,本系统只管提示形态) | -| [地形变异](../排雷循环/地形变异.md) | 全局作用域型三层预告(2026-10-04 首发批——语义正主=地形变异 §全局作用域型):①开战横幅一行(板级变异非空时显示;减动效=静态驻留,轮横幅先例同款双态)②HUD 常驻角标(C 区战斗全程可见防中局遗忘,空态整节隐藏=流派件段先例;摆位 provisional)③帮助手册一行(零交互教学,承载=玩法帮助文案块);数据面经呈现快照 board_variants 投影(核心→呈现唯一读取面),普通图三层恒空态零打扰 | +| [地形变异](../排雷循环/地形变异.md) | 全局作用域型三层预告(2026-10-04 首发批——语义正主=地形变异 §全局作用域型):①开战横幅一行(板级变异非空时显示;减动效=静态驻留,轮横幅先例同款双态)②HUD 常驻角标(C 区战斗全程可见防中局遗忘,空态整节隐藏=特性段先例;摆位 provisional)③帮助手册一行(零交互教学,承载=玩法帮助文案块);数据面经呈现快照 board_variants 投影(核心→呈现唯一读取面),普通图三层恒空态零打扰 | ## P0 最小闭环 @@ -300,6 +300,6 @@ HUD框架站在玩家与全部玩法系统之间:挖掘期它是输入的翻 | v0.10 | 2026-09-26 | 渲染技术注记(战斗舞台 Node2D 迁移批 Phase B,代码实装同批;上位裁决 ADR-0006):B 区战斗舞台 Node2D 化——BattleStageView 内部由 PanelContainer+Control 站桩改为 Control 壳 + SubViewportContainer + SubViewport + Node2D 世界(StageWorld/StandeeBody),类名/setter 面/公共方法契约不变、调用点零改造;状态图标行与悬停 tooltip 保留 Control 载体挂壳层(伴随件);C6 字体注入挂点复用(set_world_font);三区布局与性能预算(同屏 draw calls < 200)不变;占位表现等价平移(时序常量逐字对照——等价证明=git 提交 7f24b64,文件已按生命周期条款退役) | | v0.11 | 2026-09-27 | 关卡画面 UX spec 建档([level-map](../../ux/level-map.md),关卡画面 UX 批——用户拍板立项):义务清单「关卡节点地图」行挂屏级 spec 指针;屏级权威行与不负责表改按屏分治口径(战斗屏 = battle.md / 关卡画面 = level-map.md)。文档面零机制改动 | | v0.12 | 2026-09-30 | **未开格类型微光概念收口批(用户裁决落位)**:新增「未开格类型微光」节=全项目唯一正主定义(五要素——作用对象=英雄周围 8 格内的未开格〔与可挖域同圈〕/信息内容=只类型不泄雷安/生命周期=入圈亮出圈灭开格灭/关联边界/实装状态=契约定稿〔样张 v2〕游戏内待实施批);核心规则章六节改七节;呈现义务来源清单「地图战斗资源」行补微光指路;验收标准补微光呈现线。背景:该概念此前只活在 06 登记与 art-bible 复述,「常显/全部未开格」无范围表述酿成理解事故(2026-09-30 用户纠正口径),本批落位正主、他文只许指路 | -| v0.13 | 2026-10-04 | **地形变异三层预告义务批(全局作用域变异首发批——迭代 14 ③号卡,代码同批)**:呈现义务来源清单补「地形变异」行(开战横幅一行〔减动效=静态驻留,轮横幅先例同款双态〕+ C 区常驻角标〔空态整节隐藏=流派件段先例,摆位 provisional〕+ 帮助手册一行〔零交互教学〕);验收标准补三层预告线(普通图恒空态零打扰);数据面走呈现快照 board_variants 投影(核心→呈现唯一读取面)。语义正主=地形变异.md §全局作用域型,本文只锁呈现承载 | +| v0.13 | 2026-10-04 | **地形变异三层预告义务批(全局作用域变异首发批——迭代 14 ③号卡,代码同批)**:呈现义务来源清单补「地形变异」行(开战横幅一行〔减动效=静态驻留,轮横幅先例同款双态〕+ C 区常驻角标〔空态整节隐藏=特性段先例,摆位 provisional〕+ 帮助手册一行〔零交互教学〕);验收标准补三层预告线(普通图恒空态零打扰);数据面走呈现快照 board_variants 投影(核心→呈现唯一读取面)。语义正主=地形变异.md §全局作用域型,本文只锁呈现承载 | | v0.14 | 2026-10-03 | **视野迷雾实施批落籍注记(迭代 11 第④批)**:迷雾节补「实施状态」注记(四裁决逐条对账:纯呈现两态逐位一致/暗淡记忆态灰显可读/LIGHT_RADIUS=8 参数化〔提灯 +2 插值位预留未接〕/类型微光仍贴身 8 邻格);实装状态行「待实施批」改「已实装」;验收标准迷雾行去「待实施批落地后验收」括注转正式验收。机制定义零改动(定义一句话/作用范围/生命周期/关联边界/配套拍板全段原样);黑暗区域渲染规格落 art-bible §6.5(v3.5) | | v0.13 | 2026-09-30 | **视野迷雾概念落位批(用户拍板立项)**:新增「视野迷雾」节=正主定义(菱形灯光区+黑暗边界;区外已开格=暗淡记忆态灰显可读、区外未开格=全黑;灯光半径起步=微光环 8 格同圈;纯呈现层,与已退役雾格无关);验收标准补迷雾线;配套拍板随节登记(魔法提灯灯甲外扩 +2 格、类型微光不随视野扩、初始展开收窄后置 Alpha 差异化批)。实施待主线编卡 | diff --git a/design/gdd/ux/battle.md b/design/gdd/ux/battle.md index 8d5e0128..9cdfd734 100644 --- a/design/gdd/ux/battle.md +++ b/design/gdd/ux/battle.md @@ -105,7 +105,7 @@ - 攻击值 + 修正来源角标(战斗在消费、且站桩上无展示) - 护甲 AC(2026-09-26 二轮拍板补入——我方 AC 的唯一展示面;掷点判定轴,受击侧可读性) - 魔法道具槽(**已实装**:四槽两步交互,详见 [node-reward.md](node-reward.md)——随身战斗用道具的唯一展示面) - - 本关强化列表(**预留**——锻造/大奖励/关卡奖励节点获得的属性提升;与战斗内状态效果分区呈现,防「战斗结束被清」误读) + - 特性列表(**预留**——锻造/大奖励/关卡奖励节点获得的属性提升;与战斗内状态效果分区呈现,防「战斗结束被清」误读) - **D 区扫雷图 · AP 条** - AP 点阵 + 停手按钮(现行) - **RAP 读数(点阵+数字)**——自 C 区迁入,置于弃图刷新按钮旁(2026-09-26 拍板:RAP 唯一消费口 = 弃图刷新,资源数字贴消费按钮) @@ -120,7 +120,7 @@ | 区 | 位置与尺寸 | 内容 | |---|---|---| | **B 战斗画面** | 全宽 × 252px | 主角站桩立绘(左)+ 兑现演出区(中)+ 敌人站桩立绘 ×1–3(右)——**全站桩形态(2026-09-20 用户拍板,敌人卡形态待办裁决收口):主角与敌人均为无框立绘+底座,零卡片**;主角与敌人站桩 = **HP 与状态效果的唯一展示面(2026-09-26 信息归属拍板)**;底部结算明细带(24px 摘要 / 结算期 84px 实时流);顶部中央轮次·阶段指示 | -| **C 角色信息** | 左下 240px × 548px | 攻击值(含修正显示)、护甲 AC;魔法道具槽(预留)、本关强化列表(预留)——HP 条/RAP 池/状态效果槽/立绘占位/钱包行退役(2026-09-26 信息归属拍板:HP 与状态唯一展示面 = B 区站桩;RAP 迁 D 区 AP 条;GP/钥石迁出战斗屏) | +| **C 角色信息** | 左下 240px × 548px | 攻击值(含修正显示)、护甲 AC;魔法道具槽(预留)、特性列表(预留)——HP 条/RAP 池/状态效果槽/立绘占位/钱包行退役(2026-09-26 信息归属拍板:HP 与状态唯一展示面 = B 区站桩;RAP 迁 D 区 AP 条;GP/钥石迁出战斗屏) | | **D 扫雷图** | 中下 ~1036px × 548px(原右下面板删除后横向加宽,吸收其宽度) | 顶部 AP 条(44px:左——AP 点阵 + 停手按钮;中——RAP 点阵+数字〔自 C 区迁入,贴弃图刷新按钮,2026-09-26 拍板〕;右——图例按钮 + 弃图刷新按钮〔雷图右上角,2026-09-12 拍板〕);棋盘主体(居中,格 36–45px 见方);toast 槽(上缘内侧) | > 布局为 B/C/D 三区——关卡进度条不在战斗屏(节点链进度常驻关卡画面,见 Navigation Position;字母不重编沿用 B/C/D)。 @@ -147,7 +147,7 @@ | B | 结算明细回看 | 模态 overlay | 完整流水逐行(现行 9 类行协议;未生效类行聚合计数) | 关闭 | battle_log_view.gd 改造 | | C | 攻击数据框 | 直角细线数据框 | 攻击值 + 修正来源角标 + 护甲 AC(AC 二轮拍板 2026-09-26 补入——我方 AC 唯一展示面;原「HP/攻击/RAP 显示」——HP 与 RAP 随信息归属拍板迁出本组件) | 只读 | HUDView 拆分 | | C | 魔法道具槽(已实装:四槽两步交互,详见 [node-reward.md](node-reward.md)) | 图标槽 ×4 | 随身战斗用道具的唯一展示面;库存已随迭代 7 落地(C 区四槽+关卡域库存),清库反馈呈现待批 | 悬停 tooltip(道具语义) | 新建(随魔法道具批,已落地) | -| C | 本关强化列表(预留) | 列表/图标行 | 锻造/大奖励/关卡奖励节点获得的属性提升——中循环数据,因改变战斗数学且无其他展示面准入战斗屏;与战斗内状态效果(B 区站桩)分区,防「战斗结束被清」误读 | 只读 | 新建 | +| C | 特性列表(预留) | 列表/图标行 | 锻造/大奖励/关卡奖励节点获得的属性提升——中循环数据,因改变战斗数学且无其他展示面准入战斗屏;与战斗内状态效果(B 区站桩)分区,防「战斗结束被清」误读 | 只读 | 新建 | | D | AP 条 | 点阵 + 按钮组 | 本轮 AP 点阵、停手按钮(左)、**RAP 点阵+数字(自 C 区迁入 2026-09-26——RAP 唯一消费口 = 弃图刷新,资源数字贴消费按钮;RAP 清零可见反馈〔行动经济〕载体随迁)**、弃图刷新按钮(右端·雷图右上角;RAP−8 · 本轮剩 N 次——上限 2 次已随行动经济 2026-09-12 修订生效) | 点击提交意图 | HUDView 拆分 | | D | BoardView | 网格 | 棋盘全部格态 + 小人 + 旗 + 变异纹带 + 奖励身份 icon(已开格;绘制优先级 数字>小人>旗>奖励徽章>变异纹带>底色——徽章不进数字区,样张验收项) | 左/右键意图提交 | ✅ board_view.gd 迁移 | | D | 悬停预承诺光标 | 光标态 | 移动/挖/旗三语义光标 + 目标格边框高亮 | 自动 | 新建(排雷玩法×6③) | @@ -204,7 +204,7 @@ │ │ 魔法道具槽(预留) │ │ │ │AP不足·剩0点 │ 12 12 1 ░ 2 ▓▓ ▓▓ │ │ │ │ ◇ ◇ ◇ ◇ │ │ │ └──────────────────┘ 12 █ 1 1 2 ▓▓ ▓▓ │ │ │ ├──────────────────┤ │ │ 1 2 2 🚩 █ 2 1 1 ▓▓ 👫 1 1 ░ │ │ -│ │ 本关强化(预留) │ │ │ ░ 1 ▓▓ 👫 1 1 ░ ▓▓ 1 1 ░ ░ 2 │ │ +│ │ 特性列表(预留) │ │ │ ░ 1 ▓▓ 👫 1 1 ░ ▓▓ 1 1 ░ ░ 2 │ │ │ │ 锻造+2攻 │ │ │ ▓▓ 1 1 ░ ░ 2 ▓▓ │ │ │ │ (空态=隐藏) │ │ │ ( █=可挖域微光 👫=小人) │ │ │ └──────────────────┘ │ └─────────────────────────────────────────────────┘ │ @@ -440,7 +440,7 @@ | 2026-09-23 | 实现注记(棋盘 Node2D 迁移批 Phase A,代码实装同批;上位裁决 ADR-0006):棋盘渲染 Node2D 化(BoardView = Control 壳 + SubViewportContainer + SubViewport + Node2D 世界,信号/click_cell/_cells 契约保持,新增 push_input 端到端输入探针);格尺寸公式锚点不变(set_cell_area = floor((min(宽,高) − 预留 − (N−1)×格间距) / N) 单点可调),布局与交互语义零改动 | | 2026-09-26 | 实现注记(战斗舞台 Node2D 迁移批 Phase B,代码实装同批;上位裁决 ADR-0006):B 区战斗画面 Node2D 化(BattleStageView = Control 壳 + SubViewportContainer + SubViewport + Node2D 世界,站桩本体 StandeeBody 世界精灵;set_enemies/clear_enemies/on_step_row_fx/gray_all_enemies 等 setter 面签名保持,弹道落点锚点=壳层口径 world_to_shell 单点);状态图标行与悬停 tooltip 保留 Control 载体挂壳层;三区布局尺寸零改动(B 区外框 252px 逐位) | | 2026-09-26 | **封印紫批**(用户拍板):插旗呈现色 旗朱 #C63D22 → 封印紫 #7C3AA8(色相 ≈267°,避开禁入带)——旗字形/已承诺封印框/旗化暴击弹道随批换色;拒绝边框闪语义归危险红;Boss 节点描边归紫赤本色。修订记录历史行旗朱字样系当时口径留痕不改 | -| 2026-09-26 | **战斗屏信息归属批(用户 2026-09-26 三轮纠偏后拍板;代码实装另批——hero_info_panel_view.gd / hud_presenter.gd 改造 + 探针断言迁移,登记待办)**:立两条信息归属原则并全屏贯行——①循环口径原则(战斗屏只展小循环内被消费、影响当下决策的数据;中/大循环资源不得入侵)②单一展示面原则(同一信息全屏唯一展示面;单位本体已承载的信息数据框不重复;资源数字贴唯一消费口)。随拍板落地:① B 区站桩 = HP 与状态效果唯一展示面——C 区 HP 条/HP 文字/立绘占位/状态效果槽×4 退役(重复展示;证据链 = hud_presenter.gd 同一 s.hero.hp/s.hero_effects 双投喂 B/C 两区);② RAP 读数(点阵+数字)迁 D 区 AP 条、置弃图刷新按钮旁(RAP 唯一消费口 = 弃图刷新——就近原则);③ C 区状态槽悬停 tooltip 职责并入 B 区站桩状态小图标;④ GP(中循环)/钥石(大循环)迁出战斗屏,去向挂 OQ14;⑤ C 区改「攻击数据框 + 魔法道具槽(预留)+ 本关强化列表(预留)」——预留区来自魔法道具与关卡内属性提升的既有立项;⑥ 空态/清零反馈/悬停交互/AC/§13 义务表载体同步改写。**批内遗留两项待拍板(OQ13/14)**:护甲 AC 是否补入 C 区数据框;GP/钥石去向 | +| 2026-09-26 | **战斗屏信息归属批(用户 2026-09-26 三轮纠偏后拍板;代码实装另批——hero_info_panel_view.gd / hud_presenter.gd 改造 + 探针断言迁移,登记待办)**:立两条信息归属原则并全屏贯行——①循环口径原则(战斗屏只展小循环内被消费、影响当下决策的数据;中/大循环资源不得入侵)②单一展示面原则(同一信息全屏唯一展示面;单位本体已承载的信息数据框不重复;资源数字贴唯一消费口)。随拍板落地:① B 区站桩 = HP 与状态效果唯一展示面——C 区 HP 条/HP 文字/立绘占位/状态效果槽×4 退役(重复展示;证据链 = hud_presenter.gd 同一 s.hero.hp/s.hero_effects 双投喂 B/C 两区);② RAP 读数(点阵+数字)迁 D 区 AP 条、置弃图刷新按钮旁(RAP 唯一消费口 = 弃图刷新——就近原则);③ C 区状态槽悬停 tooltip 职责并入 B 区站桩状态小图标;④ GP(中循环)/钥石(大循环)迁出战斗屏,去向挂 OQ14;⑤ C 区改「攻击数据框 + 魔法道具槽(预留)+ 特性列表(预留)」——预留区来自魔法道具与关卡内属性提升的既有立项;⑥ 空态/清零反馈/悬停交互/AC/§13 义务表载体同步改写。**批内遗留两项待拍板(OQ13/14)**:护甲 AC 是否补入 C 区数据框;GP/钥石去向 | | 2026-09-26 | **信息归属二轮拍板(用户 2026-09-26,OQ13/14 收口)**:① 我方护甲 AC 补入 C 区攻击数据框(唯一展示面——布局表/组件清单/线框图同步);② GP/钥石去向定案:GP = 关卡画面常驻总量 + 战斗结算画面总量+增量,钥石 = 结算画面 + 营地(具体呈现归对应 UX spec 批次);③ 敌方 AC 展示面挂起——用户口径「敌方 AC 无任何展示」与现行代码冲突(standee_view.gd 底库名字行渲染「名字·护甲·AC%d」,系敌人技能池批克制对策可读性义务),证据链已呈报待终裁,本 spec 暂不改敌人站桩行 | | 2026-09-26 | **敌方 AC 展示终裁收口(用户 2026-09-26 终裁)**:敌方 AC 数值全屏退役(任何区不直接展示)、护甲类型改图标方式展示(形状+色相双通道,终稿图标资产归美术批)、敌人站桩底座下名字行退回纯名字+护甲类型图标;旧「克制对策可读性义务」降级承载——类型保留、数值退役。终裁理由(用户口径):HP 信息已足够,攻防数值不直接写上;护甲类型图标保留克制对策可读性。同步改写:信息归属树敌人站桩行、Component Inventory 敌人站桩立绘行、OQ13。**代码实装说明**:`standee_view.gd` 改造(站桩名字行去 AC 数值 + 护甲类型图标化)由并行代码批执行,本批只做文档同步 | | 2026-09-27 | **UX 文档欠账处置批(用户四项拍板:player-journey 不建 / accessibility 不另立改指 HUD框架 / node-reward 改挂魔法道具内容重定批 / level-clear 建档 design/gdd/ux/level-clear.md)**:① 删 §Player Context ⚠️ player-journey 未建注记,OQ1 改收口注记;② §Accessibility 头、§Transitions 减动效行、OQ2 改指 HUD框架「可访问性基线」节 + 设置与本地化待设计清单 #1(tools/doc_link_known.txt 欠账行随之清空);③ 导航残留修正——§Navigation Position 图胜利分支、§Entry/Exit 离开表、§Interaction Map 胜利 overlay 行改按现行代码实态(胜利后返回关卡画面选路;节点覆盖层 = 关卡画面域、落地奖励/恢复节点时开出;胜利/失败 overlay 组件锚 battle_end_overlay.gd)——原「胜利 → 节点奖励/恢复覆盖层」系停点前移批前残留;④ OQ3 过期陈述更正(interaction-patterns.md 2026-09-12 已建成)、OQ8 改收口注记。本批只动文档面,代码零改动 | diff --git a/design/gdd/ux/level-map.md b/design/gdd/ux/level-map.md index 7bc902e0..972bf000 100644 --- a/design/gdd/ux/level-map.md +++ b/design/gdd/ux/level-map.md @@ -91,7 +91,7 @@ **布局决策 3 —— 放弃冒险二次确认(2026-09-27 拍板)**:放弃 = 整局冒险终结,不可逆(pattern 7 破坏性确认)。首击转入确认态(按钮文案变「再点一次确认放弃——不可逆」,危险红边框脉冲约 3 秒,超时回落),二击才提交。代价语义(已获大奖励保留、同失败结算)常驻按钮文案。 -**布局决策 4 —— 底部状态栏(2026-09-27 拍板,原提案为顶栏 HP 读数)**:底栏作为状态展示——生命、属性、本关已选加成三项常读;顶栏保持关卡名 + GP 两件。单一展示面注记:与 [battle.md](battle.md) C 区「本关强化列表(预留)」为不同屏的不同展示面——两屏循环口径各自独立(选路规划消费 vs 战斗内决策消费),不构成同屏重复。 +**布局决策 4 —— 底部状态栏(2026-09-27 拍板,原提案为顶栏 HP 读数)**:底栏作为状态展示——生命、属性、本关已选加成三项常读;顶栏保持关卡名 + GP 两件。单一展示面注记:与 [battle.md](battle.md) C 区「特性列表(预留)」为不同屏的不同展示面——两屏循环口径各自独立(选路规划消费 vs 战斗内决策消费),不构成同屏重复。 ### ASCII Wireframe diff --git a/design/registry/entities.yaml b/design/registry/entities.yaml index 30eddaf3..385a1614 100644 --- a/design/registry/entities.yaml +++ b/design/registry/entities.yaml @@ -574,6 +574,20 @@ entities: mvp_content: L1 全行(切片转正——7 节点链〔单链特例,合法图形态〕、rest_heal_pct=30);L2 全行已落地(2026-09-17 分支节点图批——首张分支图:9 节点〔入口 0 → 中间三层 2/3/2 → Boss 8〕、真实岔路 4 处、奖励点+恢复点各 1、战斗节点 6 + Boss;行值 provisional 归 难度曲线与Boss v0.7;首页直入口已退役〔2026-09-23 用户拍板〕);**L3 全行已落地(2026-09-20 第三关内容批——「第三层 · 灰矮人矿城」:九节点图复用 L2 同模板〔6 战 + Boss + 奖励 + 恢复、真实岔路 4 处〕,行值全 provisional 归 难度曲线与Boss;测试直入口已退役〔2026-09-23〕)**;2026-09-20 GP+商店房批 rewiring:L2/L3 图版 Boss 重编号 8→9、各新增 (8, shop, next[9]) 商店房节点(Boss 前一位必经位),L1 零改动,图合法性六检零新增——必经位由冒烟断言承载;**2026-09-21 冒险结构实现批:三关正式序列生效**(首页「开始冒险」= L1→L2→L3 连探,AdventureRunner 编排——大奖励/生命账本/GP 冒险账本/主种子归冒险结构层,冒烟断言在案)** referenced_by: [冒险结构, 关卡节点地图, 难度曲线与Boss, 棋盘生成, 数据配置] + - name: feature + type: concept + owner: design/gdd/systems/冒险循环/特性.md + attributes: + definition: 一次冒险之内角色自身得到的提升。它不是持有物——带在自己身上的是特性,拿在手里的是魔法道具;两者由此分开 + form: 封闭枚举 {rule, stat}。rule 规则改写型——在结算管线的某个挂点上给自己加一条规则,同标签持有项数达阈值时质变;stat 属性加成型——抬自己的某项属性数值,写入冒险加算区。两者同属一个对象、共用一份持有集与一份生命周期,是形态枚举而非两个系统 + scope: 作用对象 = 角色本人与其参与的结算(不改敌人、不改棋盘生成、不改关卡内容);时间范围 = 整局冒险,跨关携带、关间不清零;归属范围 = 不进账号永久进度,不带到下一次冒险 + lifecycle: 候选池构建(冒险开局一次)→ 在两个获取口之一出现(三选一形式)→ 选定(自池中剔除不再复现)→ 持有生效(跨关携带)→ 冒险以任一结局收束时整集清零;断点记录持有集与剩余候选池 + acquisition: 两个获取口——战场奖励(每关通关一次,最终关不给;关卡节点图奖励节点共用同一候选池)与商店(花局内金币,口径为「训练」)。**现行两口共用同一候选池**,两形态按渠道分离已定尚未实施,登记于 06-待办清单 BD 分层条目 + boundary: 特性永不进同调位,魔法道具永不进当局随机渠道;与元进度天赋树两层互不代位 + data_sources: relics.tres(rule 形态逐项定义)/ adventure.tres(stat 形态配额与值)/ shop.tres(货架取舍) + naming_note: 2026-10-05 命名统一——此前按内部分类被叫成三个名字(规则类称「流派件」、属性类称「数值件」、界面称「本关强化」),现统一为「特性」,需要区分时以形态修饰语描述,不另造称呼 + referenced_by: [冒险结构, 关卡节点地图, 战斗结算, 行动经济, 地形变异, HUD框架, 魔法道具, 元进度, 数据配置] + - name: adventure_table type: schema_data owner: design/gdd/systems/冒险循环/冒险结构.md @@ -582,11 +596,12 @@ entities: fields: | 退役两字段(迭代 10 奖励重构批,2026-09-30 用户拍板):level_clear_hp_bonus(「血回满+上限提升」件随大奖励三件套退役——回血改 clear_heal_pct 部分回血、上限提升改三选一件值列)、keystone_per_level(钥石退役出大奖励改 Boss/精英击杀掉落)。 clear_heal_pct: int [0,100](knob 默认 20——非末关通关部分回血回复生效上限的百分比,封顶上限不回满、满血回 0 合法;难度上压方向,带重扫义务归 难度曲线与Boss) - bonus_attack_flat / bonus_max_hp_flat / bonus_armor_flat: int [0,999](三选一属性件兑付值——加算区攻击/生命上限/护甲轴累加,经覆盖值通道;值锚与上调约束归 难度曲线与Boss) - bonus_gp_amount: int [0,999](GP 袋件定额入钱包);bonus_ap_flat: int [0,10](AP 件每场战斗首轮行动点基线增量);bonus_aux_item_count: int [1,9](魔法道具件授予件数) + **2026-10-05 命名统一批**:本表的属性加成型特性字段与常量整体换名(旧 → 新)——BONUS_IDS → FEATURE_KINDS、bonus_token_count() → feature_quota()、bonus_value() → feature_value()、bonus_candidate_count → feature_candidate_count、token_{kind}_{tier} → feature_quota_{kind}_{tier}、bonus_*_flat/_amount(_large) → feature_value_{kind}_{tier};值零变更(句柄改称不改数),断点附随键名沿用历史形态不动(存档兼容)。换名动因见 特性 条目。 + feature_value_attack_common / feature_value_max_hp_common / feature_value_armor_common: int [0,999](三选一属性加成型特性兑付值——加算区攻击/生命上限/护甲轴累加,经覆盖值通道;值锚与上调约束归 难度曲线与Boss) + feature_value_gp_common: int [0,999](GP 袋件定额入钱包);feature_value_ap_rarest: int [0,10](AP 件每场战斗首轮行动点基线增量);bonus_aux_item_count: int [1,9](魔法道具件授予件数) ~~bonus_weight_*(E-S 加权洗牌权重族)~~ / ~~bonus_cap_*(种类次数上限族)~~:**v2.2 令牌池换代退役(迭代 12 TP0——2026-10-03 追认 b 实施批;洗牌改令牌 Fisher-Yates、池消耗即上限)** - token_{kind}_{tier}: int [0,99](**TP0 令牌配额族**——kind×tier 计数:attack 18/5 · max_hp 17/5 · armor 17/5 · gp 18/5 · heal 0/5 · ap 0/0/3〔common/rare/rarest〕;未列组合=0;档位结构锚 70/25/3=98 张入 schema validate 硬断言〔罕见档原列「道具件 2」随 aux_item 池种退役收窄——台账自决披露项〕) - bonus_attack_flat_large / bonus_max_hp_flat_large / bonus_armor_flat_large / bonus_gp_amount_large: int [0,999](稀有档大数值对——+2/+10/+2/50);bonus_heal_flat: int [0,999](恢复件 +6 当即回血——新入池种类 rare 档);MC 策略 316-f(autoplay 1 级最稀有/2 级最左)随批落地 + feature_quota_{kind}_{tier}: int [0,99](**TP0 令牌配额族**——kind×tier 计数:attack 18/5 · max_hp 17/5 · armor 17/5 · gp 18/5 · heal 0/5 · ap 0/0/3〔common/rare/rarest〕;未列组合=0;档位结构锚 70/25/3=98 张入 schema validate 硬断言〔罕见档原列「道具件 2」随 aux_item 池种退役收窄——台账自决披露项〕) + feature_value_attack_rare / feature_value_max_hp_rare / feature_value_armor_rare / feature_value_gp_rare: int [0,999](稀有档大数值对——+2/+10/+2/50);feature_value_heal_rare: int [0,999](恢复件 +6 当即回血——新入池种类 rare 档);MC 策略 316-f(autoplay 1 级最稀有/2 级最左)随批落地 transitional_sync_slots: int [0,9](同调位过渡读数源,默认 1——道具持有上限;正主 = attunement_growth.tres 里程碑谓词表,同调实施批落地后切换读数源) mvp_content: 单行全局默认值即 MVP 行(provisional 归 曲线调参批——迭代 10 扩列批注) extension_reserve: 大奖励形态扩列位已消费(迭代 10 奖励重构批落地三选一/攻击型——本键使命完成退役;冒险结构 OQ2 收口) diff --git a/game/core/adventure_runner.gd b/game/core/adventure_runner.gd index cb7e866d..90980f74 100644 --- a/game/core/adventure_runner.gd +++ b/game/core/adventure_runner.gd @@ -80,8 +80,8 @@ var _save_manager = null # 断点承载注入(迭代 8 卡① var _resume_bp := {} # 续玩快照暂存(resume_adventure → _start_current_level 单跳传递) # ---- 三选一停点态(迭代 10 奖励重构批)---- var _bonus_taken := {} # 件获取次数计数(kind 维度派生账本——断点附随件与摘要读数承载;池库存正主=_bonus_deck) -var _bonus_deck: Array = [] # 令牌池(TP0 v2.2——持久多重集,元素 {"kind","tier"};洗牌抽候选/选中踢池未选回池/池耗即枯竭;商店货架同库共账;迭代 12 T1 起机制件带=relic 令牌随表追加) -var _relics: Array[String] = [] # 流派件持有集(迭代 12 T1——局内随机渠道获得、冒险级跨关携带、收束清零;🔴 层级纪律承载面:不入同调位不入局外树) +var _bonus_deck: Array = [] # 令牌池(TP0 v2.2——持久多重集,元素 {"kind","tier"};洗牌抽候选/选中踢池未选回池/池耗即枯竭;商店货架同库共账;迭代 12 T1 起规则改写型特性带=relic 令牌随表追加) +var _relics: Array[String] = [] # 特性持有集(迭代 12 T1——局内随机渠道获得、冒险级跨关携带、收束清零;🔴 层级纪律承载面:不入同调位不入局外树) var _tree_rules: Array = [] # 树 rule 键集(迭代 12 T10——Fork 激活侧 effects 透传;下传 enc.tree_rules 消费面) var _bonus_pending := {} # 停点态:{"candidates": Array, "payload": Dictionary, "chosen"/"incoming": 替换在途}——空 = 无停点 var _bonus_result := {} # 已兑付待推进态(bonus_resolved 载荷副本——中断续玩不重兑付) @@ -128,8 +128,8 @@ func start_adventure(seed_val: int, params: Dictionary = {}) -> bool: _attunement = params.get("attunement", []) if params.get("attunement", []) is Array else [] # additive(迭代 11 第①批 T5) _attune_refresh_y = maxi(0, int(params.get("attune_refresh_y", 0))) # additive(迭代 11 第①批 T5b——Y 冒险周期池) _seed_attune_charges() # 迭代 11 第①批 T6——冒险开始充能账本按装备主动件重置(每冒险充能语义) - # 流派件开局注入(迭代 12 T7——MC 成型画像载体:params.relics_seed 非空=开局持有集〔七流派 - # 各 2 件档一成型——测量面专用;真实局流派件只走局内随机渠道,红线②层级纪律不破〕) + # 特性开局注入(迭代 12 T7——MC 成型画像载体:params.relics_seed 非空=开局持有集〔七流派 + # 各 2 件档一成型——测量面专用;真实局规则改写型特性只走局内随机渠道,红线②层级纪律不破〕) var relic_seed: Array = params.get("relics_seed", []) if params.get("relics_seed", []) is Array else [] _tree_rules = params.get("tree_rules", []) if params.get("tree_rules", []) is Array else [] # 迭代 12 T10——A/B 面 rule 键集 if not relic_seed.is_empty(): @@ -190,7 +190,7 @@ func resume_adventure(bp: Dictionary, params: Dictionary = {}) -> bool: rtok["relic_id"] = String(tok.get("relic_id", "")) restored.append(rtok) _bonus_deck = restored - # 流派件持有集还原(迭代 12 T1——缺键 = 旧版断点防御空集) + # 特性持有集还原(迭代 12 T1——缺键 = 旧版断点防御空集) _relics = [] for r in (bp.get("relics", []) as Array): _relics.append(String(r)) @@ -267,14 +267,14 @@ func _reset_bonus_state() -> void: _node_bonus_pending = {} -# 令牌池构建(TP0 v2.2——按表 kind×tier 配额展开为持久多重集;构建序确定 = BONUS_IDS×TIERS 逐层, -# 随机性只发生在洗牌消费 reward_pick 封闭流的时刻。迭代 12 T1:机制件带=relic 活行每件 1 张追加 +# 令牌池构建(TP0 v2.2——按表 kind×tier 配额展开为持久多重集;构建序确定 = FEATURE_KINDS×TIERS 逐层, +# 随机性只发生在洗牌消费 reward_pick 封闭流的时刻。迭代 12 T1:规则改写型特性带=relic 活行每件 1 张追加 # (rarity common/rare→稀有令牌档、rarest→罕见令牌档——relic 永不入普通档;空表=零追加零扰动)) func _build_bonus_deck() -> Array: var deck: Array = [] - for kind in db.adventure.BONUS_IDS: + for kind in db.adventure.FEATURE_KINDS: for tier in db.adventure.TIERS: - for i in int(db.adventure.bonus_token_count(String(kind), String(tier))): + for i in int(db.adventure.feature_quota(String(kind), String(tier))): deck.append({"kind": String(kind), "tier": String(tier)}) for row in db.relic_rows(): var rtier := "rarest" if String(row.get("rarity", "")) == "rarest" else "rare" @@ -282,7 +282,7 @@ func _build_bonus_deck() -> Array: return deck -# 令牌唯一身份(抽签去重/兑付匹配共用——数值件=kind,机制件=relic_id;同档多张不同 relic 可同屏) +# 令牌唯一身份(抽签去重/兑付匹配共用——属性加成型特性=kind,规则改写型特性=relic_id;同档多张不同 relic 可同屏) func _token_identity(tok: Dictionary) -> String: if String(tok.get("kind", "")) == "relic": return "relic:" + String(tok.get("relic_id", "")) @@ -337,7 +337,7 @@ func continue_to_next_level() -> bool: # ---- 提升三选一(迭代 10 奖励重构批——选择停点零自动推进、重复兑付被拒;兑付恰一件、未选项零生效)---- -# 候选令牌匹配(身份键恒等——数值件 kind+tier、机制件 relic_id;迭代 12 T1 机制件带) +# 候选令牌匹配(身份键恒等——属性加成型特性 kind+tier、规则改写型特性 relic_id;迭代 12 T1 规则改写型特性带) func _find_token(candidates: Array, kind: String, tier: String, relic_id: String = "") -> Dictionary: for t in candidates: var tok: Dictionary = t as Dictionary @@ -351,7 +351,7 @@ func _find_token(candidates: Array, kind: String, tier: String, relic_id: String # 玩家点选兑付(呈现层/冒烟/自动模拟确认入口):令牌 ∈ 停点候选(身份键精确匹配——relic 件 # 另须 relic_id)。属性件写加算区、AP 件写第四轴、GP 件走钱包「奖励入账」入口、恢复件当即回血、 -# relic 件入流派件持有集(🔴 层级纪律:只走局内随机渠道)、道具件受同调位约束(随池种退役不可达)。 +# relic 件入特性持有集(🔴 层级纪律:只走局内随机渠道)、道具件受同调位约束(随池种退役不可达)。 # 消费=选中令牌踢池(未选回池由「抽签不摘牌、兑付才摘牌」语义承载——TP0 v2.2)。 func pick_bonus(kind: String, tier: String = "", relic_id: String = "") -> bool: if state != "running" or _bonus_pending.is_empty(): @@ -361,7 +361,7 @@ func pick_bonus(kind: String, tier: String = "", relic_id: String = "") -> bool: if _find_token(candidates, kind, tier, relic_id).is_empty(): push_error("[冒险结构] pick_bonus 拒绝——令牌不在候选: %s|%s|%s" % [kind, tier, relic_id]) return false - var value: int = int(db.adventure.bonus_value(kind, tier)) + var value: int = int(db.adventure.feature_value(kind, tier)) var hp_before := int(ledger.get("hero_hp", 0)) if kind == "aux_item": return _pick_aux_item(value) # 道具件分派通关渠道(持有容器 = 跨关携带——与节点渠道分轨;池种退役后不可达) @@ -435,7 +435,7 @@ func _consume_deck_token(kind: String, tier: String, relic_id: String = "") -> b return false -# 流派件持有集读面(效果接线/求值/摘要唯一取数口——副本防外部改写) +# 特性持有集读面(效果接线/求值/摘要唯一取数口——副本防外部改写) func relics_held() -> Array: return _relics.duplicate() @@ -457,10 +457,10 @@ func pool_stock(kind: String) -> int: # 写加算区+账本+摘牌(与奖励三选一真单点——买一件=奖励面少一件的库存语义由同库成立)。 # 未知 kind 拒绝(货架词表封闭的前置防御)。 func _consume_pool_purchase(kind: String, tier: String) -> bool: - if not db.adventure.BONUS_IDS.has(kind): + if not db.adventure.FEATURE_KINDS.has(kind): push_error("[冒险结构] 商店购买消费拒绝——件不在池词表: %s" % kind) return false - return _apply_bonus_pick(kind, tier, int(db.adventure.bonus_value(kind, tier))) + return _apply_bonus_pick(kind, tier, int(db.adventure.feature_value(kind, tier))) # 终局池快照(_settle 清账前调用——_reset_bonus_state 会重置 _bonus_taken,摘要 additive 键 @@ -552,7 +552,7 @@ func apply_node_bonus(kind: String, tier: String = "", relic_id: String = "") -> if _find_token(candidates, kind, tier, relic_id).is_empty(): push_error("[冒险结构] apply_node_bonus 拒绝——令牌不在候选: %s|%s|%s" % [kind, tier, relic_id]) return false - var value: int = int(db.adventure.bonus_value(kind, tier)) + var value: int = int(db.adventure.feature_value(kind, tier)) if kind == "aux_item": return _apply_node_aux(value) # 道具件分派节点渠道(持有容器 = 关卡域库存——与通关渠道分轨;池种退役后不可达) if not _apply_bonus_pick(kind, tier, value, relic_id): @@ -573,7 +573,7 @@ func _apply_node_aux(count: int) -> bool: var records: Array = [] if _runner != null and _runner.aux_inventory != null: records = _runner.aux_inventory.holding_records() - # 迭代 11 第①批 T7——守卫随过渡键退役拆除(BONUS_IDS 已除名 aux_item,本分支不可达; + # 迭代 11 第①批 T7——守卫随过渡键退役拆除(FEATURE_KINDS 已除名 aux_item,本分支不可达; # 替换子交互路由随容量闸一并退役——能力件容量闸正主 = 营地装配面满位禁选) if _runner != null: for iid in picked: @@ -739,7 +739,7 @@ func _draw_bonus_candidates() -> Array: if ident.begins_with("relic:"): cand["relic_id"] = String((tok as Dictionary).get("relic_id", "")) out.append(cand) - if out.size() >= int(db.adventure.bonus_candidate_count): + if out.size() >= int(db.adventure.feature_candidate_count): break return out @@ -828,7 +828,7 @@ func _start_current_level() -> bool: if ok: _runner.set_attunement(_attunement) # 迭代 11 第①批 T5——同调装配下传(enc 携带进战斗结算) _runner.set_attune_charges(attune_charges) # 迭代 11 第①批 T6——充能账本下传(能力件骑库存面注入) - _runner.set_relics(_relics) # 迭代 12 T1——流派件持有集下传(begin_battle enc.relics 求值面) + _runner.set_relics(_relics) # 迭代 12 T1——特性持有集下传(begin_battle enc.relics 求值面) _runner.set_tree_rules(_tree_rules) # 迭代 12 T10——树 rule 键集下传(A/B 面消费) if _shop_mode == "pool": # 商店共享池注入(迭代 11 第②批 T3——库存账本引用+消费 handler 双下传;legacy 模式零注入零扰动) @@ -908,7 +908,7 @@ func _settle(result: String) -> void: "aux_cleared_last": _last_aux_cleared, # additive 扩签(迭代 7 T4——末关清空反馈;非末关走 bonus 载荷) "keystone_drops": _keystone_drops.duplicate(true), # additive 扩签(迭代 10——逐杀掉落明细;settle 入账明细/复盘归因数据源) "pool_stock": _pool_stock_snapshot(), # additive 扩签(迭代 11 第②批 T5——终局池读数:清账前快照,商店买走 vs 奖励领走 vs 枯竭的终局面) - "relics": _relics.duplicate(), # additive 扩签(迭代 12 T1——流派件终局持有集:清账前快照,成型判读取数面) + "relics": _relics.duplicate(), # additive 扩签(迭代 12 T1——特性终局持有集:清账前快照,成型判读取数面) } # 败退明细(数值验证工具取数面 2026-09-22——tools/balance_verifier.py 止步节点分布数据源; # 仅失败局附加,键缺省 = 未败退,既有五件事消费方零感知) @@ -941,7 +941,7 @@ func _forward_choices_presented(candidates: Array) -> void: # ---- 断点快照(迭代 8 卡①——七字段拍板面+恢复必需附随件)---- -# 七字段(拍板面):关卡序号/节点位/生命/本关加成区/GP 钱包/商店已购档/已抽模板; +# 七字段(拍板面):关卡序号/节点位/生命/属性加成区/GP 钱包/商店已购档/已抽模板; # 附随件(续玩正确性必需,随批注记):主种子+取数计数器(rng 快照契约回填——续接原时间线)、 # 钥石累计(大奖励中途值——终局摘要五件事不失真)、已到节点序(呈现层图条重建)、道具库存 # (奖励节点已选件——防静默丢失)。注入缺省 null = 整面静默(模拟/冒烟零扰动)。 @@ -976,7 +976,7 @@ func _snapshot_breakpoint() -> void: "aux_items": aux_items, "bonus_taken": _bonus_taken.duplicate(true), # 三选一件获取次数(kind 维度派生账本——断点附随件与读数承载) "bonus_deck": _bonus_deck.duplicate(true), # 令牌池余库(TP0 v2.2——池消耗即上限,续玩余库逐枚还原) - "relics": _relics.duplicate(), # 流派件持有集(迭代 12 T1——局内随机渠道获得态续玩防丢失) + "relics": _relics.duplicate(), # 特性持有集(迭代 12 T1——局内随机渠道获得态续玩防丢失) "bonus_pending": _bonus_pending.duplicate(true), # 三选一停点态(空 = 无停点——选择停点可中断契约) "bonus_result": _bonus_result.duplicate(true), # 已兑付待推进态(空 = 无——中断续玩不重兑付) "bonus_aux_carry": _bonus_aux_carry.duplicate(true), # 道具件跨关携带(注入前中断防静默丢失) diff --git a/game/core/battle_orchestrator.gd b/game/core/battle_orchestrator.gd index 694d9389..a1bfd0be 100644 --- a/game/core/battle_orchestrator.gd +++ b/game/core/battle_orchestrator.gd @@ -72,7 +72,7 @@ var attunement: Array = [] # 装备中同调件 item_id 集 var _attune_charges_ref: Dictionary = {} # 充能账本共享引用(迭代 11 第①批 T6——use_aux 消费直改) var _attune_bank := 0 # 掘进蓄能积点(battle 域——每 charge_n 安全格 +1 点) var _attune_safe_seen := 0 # 掘进蓄能 battle 域安全开格计数 -# 流派件运行态(迭代 12 T2——relic 持有集经 enc.relics 注入;求值旗注 damage_controller.relic_flags; +# 特性运行态(迭代 12 T2——relic 持有集经 enc.relics 注入;求值旗注 damage_controller.relic_flags; # 魔矢每战首次计数 battle 域。空集=零扰动) var _relic_first_dig_used := false var _relic_combo := 0 # 矿脉直觉连击计数(battle 域——safe +1/mine 清零) @@ -94,7 +94,7 @@ func _attune_mag(item_id: String) -> int: return int(_attune_row(item_id).get("magnitude", 0)) -# 流派件求值(迭代 12 T2——持有集 × relic_table → damage_controller.relic_flags 注入面): +# 特性求值(迭代 12 T2——持有集 × relic_table → damage_controller.relic_flags 注入面): # rider_flat = Σ rider 件 value(奥术余烬 +1 / 魔能共鸣 +2);magic 档一(≥2 件)rider +1、 # 档二(≥4 件)rider 可暴击;clamp 两件直调键;first_dig_spell 旗(魔能共鸣第二效果——魔矢值 # = 件 effects.value)。空集/空表 = 零旗零扰动。 @@ -247,7 +247,7 @@ func begin_battle(enc: Dictionary) -> bool: _attune_safe_seen = 0 _damage.attune_venom = _attune_mag("venom_edge") if _attune_has("venom_edge") else 0 _reward_economy.luck_bias = _attune_mag("luck_coin") if _attune_has("luck_coin") else 0 - # 流派件运行态注入(迭代 12 T2 魔法流——enc.relics 携带持有集;RelicsEngine 求值后注伤害控制器 + # 特性运行态注入(迭代 12 T2 魔法流——enc.relics 携带持有集;RelicsEngine 求值后注伤害控制器 # relic_flags;空集/空表=零扰动。魔矢每战首次开格计数同步归零) _relic_flags_for((enc.get("relics", []) as Array)) _relic_first_dig_used = false @@ -680,7 +680,7 @@ func set_aux_unlocked(ids: Dictionary) -> void: func _grant_routed(snap: Dictionary, polarity: String, source_class: String, cell: Vector2i, ri: int, highlight: String = "", label_suffix: String = "") -> bool: # 迭代 11 第①批 T7——aux 授予分支随掉落/停点渠道退役拆除(reward 词表第十型 aux_item 保留但零投放: - # 无 aux 行入池、BONUS_IDS 词表已除名);剩余类型走极性字典路由。 + # 无 aux 行入池、FEATURE_KINDS 词表已除名);剩余类型走极性字典路由。 var row: Dictionary = _reward_economy.polarity_row(String(snap.get("cell_type", "")), polarity) if row.is_empty(): _fatal("极性字典缺行: %s %s" % [String(snap.get("cell_type", "")), polarity]) diff --git a/game/core/config_db.gd b/game/core/config_db.gd index 3423f028..7e1ff3ee 100644 --- a/game/core/config_db.gd +++ b/game/core/config_db.gd @@ -27,7 +27,7 @@ const TABLE_MANIFEST := { "aux_items": "aux_items.tres", # 迭代 7 T1 魔法道具内容批(AuxItemTable 六行——定义表 Rule 4 豁免;罗盘 retired/失义件 deferred 标记见 schema 头注) "adventure": "adventure.tres", # 冒险结构实现批 2026-09-21(AdventureTable 建表——大奖励与钥石行值单点) "attunement_growth": "attunement_growth.tres", # 迭代 11 第①批 同调实施批 T1(AttunementGrowthTable 单行全局——同调位里程碑谓词表;单行先例 Rule 4 豁免) - "relics": "relics.tres", # 迭代 12 T1 双层 BD 机制件基建(RelicTable 定义表 Rule 4 豁免——AuxItemTable 先例;空表合法态=主时间线零扰动) + "relics": "relics.tres", # 迭代 12 T1 双层 BD 规则改写型特性基建(RelicTable 定义表 Rule 4 豁免——AuxItemTable 先例;空表合法态=主时间线零扰动) } var action_economy: ActionEconomyTable @@ -154,7 +154,7 @@ func relic_row(relic_id: String) -> Dictionary: return relics.row_by_id(relic_id) if relics != null else {} -# 机制件带令牌构建源(池接线——adventure_runner._build_bonus_deck 消费;行 rarity→投放档映射) +# 规则改写型特性带令牌构建源(池接线——adventure_runner._build_bonus_deck 消费;行 rarity→投放档映射) func relic_rows() -> Array: return relics.rows if relics != null else [] diff --git a/game/core/config_db_cross_validator.gd b/game/core/config_db_cross_validator.gd index ad201114..d784a86c 100644 --- a/game/core/config_db_cross_validator.gd +++ b/game/core/config_db_cross_validator.gd @@ -99,18 +99,18 @@ func cross_validate(loaded: Dictionary, push_diag: Callable) -> void: for e in validate_skill_pool_links(skt, en, loaded.get("status_effects")): push_diag.call("error", e.category, e.message) # ⑥ 商店货架 × 冒险共享池跨表校验(M-4 迭代 11 第②批 T1——次数上限域): - # pool_shelf kind 须命中 adventure.BONUS_IDS 且为有限库存种(cap ∈ [1,99]——gp 无上限种/牌库外种 - # 入货架 = 库存账本无锚,加载致命;gp 袋负交易切边/机制件三轴切边由 ShopTable 词表封闭另拦) + # pool_shelf kind 须命中 adventure.FEATURE_KINDS 且为有限库存种(cap ∈ [1,99]——gp 无上限种/牌库外种 + # 入货架 = 库存账本无锚,加载致命;gp 袋负交易切边/规则改写型特性三轴切边由 ShopTable 词表封闭另拦) var adv = loaded.get("adventure") var shp = loaded.get("shop") if adv != null and shp != null: for row in shp.pool_shelf: var kind: String = String(row.get("kind_id", "")) - if not adv.BONUS_IDS.has(kind): - push_diag.call("error", "shelf_dangling_kind", "ShopTable.pool_shelf kind %s 不在 AdventureTable.BONUS_IDS(共享池牌库外种)" % kind) + if not adv.FEATURE_KINDS.has(kind): + push_diag.call("error", "shelf_dangling_kind", "ShopTable.pool_shelf kind %s 不在 AdventureTable.FEATURE_KINDS(共享池牌库外种)" % kind) continue # TP0 令牌池——货架件须为有限令牌种(配额 >0;种类次数上限退役后库存=剩余令牌数) - var quota := int(adv.bonus_token_count(kind, adv.TIER_COMMON)) + int(adv.bonus_token_count(kind, adv.TIER_RARE)) + int(adv.bonus_token_count(kind, adv.TIER_RAREST)) + var quota := int(adv.feature_quota(kind, adv.TIER_COMMON)) + int(adv.feature_quota(kind, adv.TIER_RARE)) + int(adv.feature_quota(kind, adv.TIER_RAREST)) if quota < 1: push_diag.call("error", "shelf_zero_quota", "ShopTable.pool_shelf kind %s 令牌配额为 0(牌库空种入货架 = 库存无锚)" % kind) diff --git a/game/core/damage_controller.gd b/game/core/damage_controller.gd index f2ec3a43..161dce06 100644 --- a/game/core/damage_controller.gd +++ b/game/core/damage_controller.gd @@ -60,7 +60,7 @@ var _outcomes := {} # ticket_id → "redeemed"/"zero"/"voided"( var _seq := 0 # 流水号 var _halted := false # 主角倒下终止旗(死亡事件置位——flush 余单作废) var _hero_ac_override := -1 # 主角护甲等级合流入参(begin_battle 显式设定——-1 = 表值兜底,口径同战斗编排器) -# 流派件求值旗(迭代 12 T2——begin_battle 编排器经 RelicsEngine 求值后注入;空字典=零扰动。 +# 特性求值旗(迭代 12 T2——begin_battle 编排器经 RelicsEngine 求值后注入;空字典=零扰动。 # rider_flat=英雄侧必中附加值〔奥术余烬族〕/rider_crit=档二 rider 可暴击/first_dig_spell=每战首次 # 开安全格追加魔法矢〔消费在编排器授予段〕/clamp_magic_light·clamp_magic_heavy=克制点直调) var relic_flags: Dictionary = {} @@ -418,7 +418,7 @@ func _counter_delta(attack_type: String, armor: String) -> int: return int(row.get(armor, 0)) -# 克制点直调(迭代 12 T2 魔法流/T4 穿刺流 clamp_modifier 件——克制矩阵查表值后的流派件调整; +# 克制点直调(迭代 12 T2 魔法流/T4 穿刺流 clamp_modifier 件——克制矩阵查表值后的特性调整; # 空旗=0 零扰动):魔网织者=magic vs magic(矩阵罚 −1 → 0/正);湛蓝誓约=magic vs heavy(+1 → +2); # 猎手刺剑=pierce vs light(+1——对轻甲敌穿刺提升,对重甲无增益=正负双修)。hero_attack 与 # board_typed 两消费面同享。 diff --git a/game/core/level_runner.gd b/game/core/level_runner.gd index 286d1630..13b9cec2 100644 --- a/game/core/level_runner.gd +++ b/game/core/level_runner.gd @@ -589,7 +589,7 @@ func set_attunement(ids: Array) -> void: _attunement = ids.duplicate() -# 流派件持有集注入(迭代 12 T1——AdventureRunner._start_current_level 唯一调用方;begin_battle +# 特性持有集注入(迭代 12 T1——AdventureRunner._start_current_level 唯一调用方;begin_battle # enc.relics 携带进战斗求值;**共享引用不复制**——关内奖励节点兑付的 relic 须当关后续战斗生效 # (attune_charges 共享账本同款);空集=零扰动) var _relics: Array = [] @@ -599,7 +599,7 @@ func set_relics(ids: Array) -> void: _relics = ids -# 流派件持有集读面(迭代 12 呈现补齐——HUD C 区流派件段数据源) +# 特性持有集读面(迭代 12 呈现补齐——HUD C 区特性段数据源) func relics_held() -> Array: return _relics.duplicate() @@ -776,7 +776,7 @@ func _shop_draw_shelf() -> void: _shop_shelf.append(tok) if _shop_shelf.size() >= 3: break - # 商店保底(迭代 12 T6——「本关变异交互件必刷」简化口径:货架零流派件时**挤掉最后一张普通卡** + # 商店保底(迭代 12 T6——「本关变异交互件必刷」简化口径:货架零特性时**挤掉最后一张普通卡** # 换吞噬流件〔地形交互件广义映射——按关变异精细绑定归数值批,台账披露待追认〕;占位制货架恒 # ≤3;池内无 devour 令牌=不保底合法态) var has_relic := false @@ -831,10 +831,10 @@ func shop_shelf() -> Array: var tier := String((tok as Dictionary).get("tier", "")) var row: Dictionary = db.shop_pool_row(kind) var display := String(row.get("display_name", kind)) - var value := int(db.adventure.bonus_value(kind, tier)) + var value := int(db.adventure.feature_value(kind, tier)) if row.is_empty() and kind == "relic": var rrow: Dictionary = db.relic_row(String(tok.get("relic_id", ""))) - display = String(rrow.get("display_name", "流派件")) + display = String(rrow.get("display_name", "特性")) value = 0 out.append({ "kind_id": kind, diff --git a/game/data/schemas/adventure_table.gd b/game/data/schemas/adventure_table.gd index 634f9546..508c5be5 100644 --- a/game/data/schemas/adventure_table.gd +++ b/game/data/schemas/adventure_table.gd @@ -13,9 +13,13 @@ class_name AdventureTable extends Resource +## 概念指路:本表的属性加成型特性,与 relics.tres 的规则改写型特性,同属一个对象—— +## 「特性」(一次冒险内角色自身得到的提升)。定义见 design/gdd/systems/冒险循环/特性.md。 +## 两者是它的形态枚举(form = rule / stat),不是两个系统;本表承载 stat 形态的配额与值。 +## (2026-10-05 命名统一:旧称「数值件」→ 属性加成型特性;常量与字段随之前缀 feature_*。) ## 三选一提升池 kind 词表(封闭——断点附随件与牌库剔除态依赖它;扩件走本表+registry 修订)。 ## aux_item 池种退役(迭代 11 第①批 T7——同调批出池);heal 恢复件新入池(v2.2 令牌池追认 b)。 -const BONUS_IDS: Array[String] = ["attack", "max_hp", "armor", "gp", "ap", "heal"] +const FEATURE_KINDS: Array[String] = ["attack", "max_hp", "armor", "gp", "ap", "heal"] ## 令牌档位词表(v2.2 三档位——稀有度命名对齐 MC 策略判读序 316-f:1 级最稀有=rarest 优先) const TIERS: Array[String] = ["common", "rare", "rarest"] const TIER_COMMON := "common" @@ -30,62 +34,62 @@ const TIER_QUOTAS := {"common": 70, "rare": 25, "rarest": 3} @export var clear_heal_pct: int = 20 # [0,100] knob——回复生效上限的百分比,封顶上限不回满 # —— 三选一候选数(2026-10-02 修复批 T2 魔法数结构化)—— -@export var bonus_candidate_count: int = 3 # [1,6] knob——令牌洗牌不放回抽取张数上界 +@export var feature_candidate_count: int = 3 # [1,6] knob——令牌洗牌不放回抽取张数上界 # —— 令牌配额(kind × tier 计数;未列组合 = 0——heal 只入稀有/ap 只入罕见,v2.2 档位构成)—— -@export var token_attack_common: int = 18 # [0,99] -@export var token_attack_rare: int = 5 # [0,99] -@export var token_max_hp_common: int = 17 # [0,99] -@export var token_max_hp_rare: int = 5 # [0,99] -@export var token_armor_common: int = 17 # [0,99] -@export var token_armor_rare: int = 5 # [0,99] -@export var token_gp_common: int = 18 # [0,99] -@export var token_gp_rare: int = 5 # [0,99] -@export var token_heal_rare: int = 5 # [0,99]——恢复件(新入池种类,当即回血) -@export var token_ap_rarest: int = 3 # [0,99]——AP 件(罕见档;道具件 2 席位随池种退役收窄) +@export var feature_quota_attack_common: int = 18 # [0,99] +@export var feature_quota_attack_rare: int = 5 # [0,99] +@export var feature_quota_max_hp_common: int = 17 # [0,99] +@export var feature_quota_max_hp_rare: int = 5 # [0,99] +@export var feature_quota_armor_common: int = 17 # [0,99] +@export var feature_quota_armor_rare: int = 5 # [0,99] +@export var feature_quota_gp_common: int = 18 # [0,99] +@export var feature_quota_gp_rare: int = 5 # [0,99] +@export var feature_quota_heal_rare: int = 5 # [0,99]——恢复件(新入池种类,当即回血) +@export var feature_quota_ap_rarest: int = 3 # [0,99]——AP 件(罕见档;道具件 2 席位随池种退役收窄) # —— 令牌件值(小/大数值对——v2.2 追认 b 定稿:20/50、+1/+2、+1/+2、+5/+10、恢复+6、AP+1)—— -@export var bonus_attack_flat: int = 1 # [0,999] knob——小增伤 -@export var bonus_attack_flat_large: int = 2 # [0,999] knob——大增伤 -@export var bonus_max_hp_flat: int = 5 # [0,999] knob——小生命 -@export var bonus_max_hp_flat_large: int = 10 # [0,999] knob——大生命 -@export var bonus_armor_flat: int = 1 # [0,999] knob——小护甲 -@export var bonus_armor_flat_large: int = 2 # [0,999] knob——大护甲 -@export var bonus_gp_amount: int = 20 # [0,999] knob——小GP -@export var bonus_gp_amount_large: int = 50 # [0,999] knob——大GP -@export var bonus_heal_flat: int = 6 # [0,999] knob——恢复(当即回血,封顶生效上限) -@export var bonus_ap_flat: int = 1 # [0,10] knob——AP 件每场战斗首轮行动点基线增量 +@export var feature_value_attack_common: int = 1 # [0,999] knob——小增伤 +@export var feature_value_attack_rare: int = 2 # [0,999] knob——大增伤 +@export var feature_value_max_hp_common: int = 5 # [0,999] knob——小生命 +@export var feature_value_max_hp_rare: int = 10 # [0,999] knob——大生命 +@export var feature_value_armor_common: int = 1 # [0,999] knob——小护甲 +@export var feature_value_armor_rare: int = 2 # [0,999] knob——大护甲 +@export var feature_value_gp_common: int = 20 # [0,999] knob——小GP +@export var feature_value_gp_rare: int = 50 # [0,999] knob——大GP +@export var feature_value_heal_rare: int = 6 # [0,999] knob——恢复(当即回血,封顶生效上限) +@export var feature_value_ap_rarest: int = 1 # [0,10] knob——AP 件每场战斗首轮行动点基线增量 ## 令牌配额读数(未列 kind×tier 组合 = 0——heal 无普通档/ap 无普通稀有档按 v2.2 构成) -func bonus_token_count(kind: String, tier: String) -> int: +func feature_quota(kind: String, tier: String) -> int: match [kind, tier]: - ["attack", TIER_COMMON]: return token_attack_common - ["attack", TIER_RARE]: return token_attack_rare - ["max_hp", TIER_COMMON]: return token_max_hp_common - ["max_hp", TIER_RARE]: return token_max_hp_rare - ["armor", TIER_COMMON]: return token_armor_common - ["armor", TIER_RARE]: return token_armor_rare - ["gp", TIER_COMMON]: return token_gp_common - ["gp", TIER_RARE]: return token_gp_rare - ["heal", TIER_RARE]: return token_heal_rare - ["ap", TIER_RAREST]: return token_ap_rarest + ["attack", TIER_COMMON]: return feature_quota_attack_common + ["attack", TIER_RARE]: return feature_quota_attack_rare + ["max_hp", TIER_COMMON]: return feature_quota_max_hp_common + ["max_hp", TIER_RARE]: return feature_quota_max_hp_rare + ["armor", TIER_COMMON]: return feature_quota_armor_common + ["armor", TIER_RARE]: return feature_quota_armor_rare + ["gp", TIER_COMMON]: return feature_quota_gp_common + ["gp", TIER_RARE]: return feature_quota_gp_rare + ["heal", TIER_RARE]: return feature_quota_heal_rare + ["ap", TIER_RAREST]: return feature_quota_ap_rarest return 0 ## 令牌件值(kind × tier;v2.2 数值对——小/大两档) -func bonus_value(kind: String, tier: String = TIER_COMMON) -> int: +func feature_value(kind: String, tier: String = TIER_COMMON) -> int: match [kind, tier]: - ["attack", TIER_COMMON]: return bonus_attack_flat - ["attack", TIER_RARE]: return bonus_attack_flat_large - ["max_hp", TIER_COMMON]: return bonus_max_hp_flat - ["max_hp", TIER_RARE]: return bonus_max_hp_flat_large - ["armor", TIER_COMMON]: return bonus_armor_flat - ["armor", TIER_RARE]: return bonus_armor_flat_large - ["gp", TIER_COMMON]: return bonus_gp_amount - ["gp", TIER_RARE]: return bonus_gp_amount_large - ["heal", TIER_RARE]: return bonus_heal_flat - ["ap", TIER_RAREST]: return bonus_ap_flat + ["attack", TIER_COMMON]: return feature_value_attack_common + ["attack", TIER_RARE]: return feature_value_attack_rare + ["max_hp", TIER_COMMON]: return feature_value_max_hp_common + ["max_hp", TIER_RARE]: return feature_value_max_hp_rare + ["armor", TIER_COMMON]: return feature_value_armor_common + ["armor", TIER_RARE]: return feature_value_armor_rare + ["gp", TIER_COMMON]: return feature_value_gp_common + ["gp", TIER_RARE]: return feature_value_gp_rare + ["heal", TIER_RARE]: return feature_value_heal_rare + ["ap", TIER_RAREST]: return feature_value_ap_rarest return 0 @@ -101,8 +105,8 @@ func tier_rank(tier: String) -> int: ## 档位令牌总数(货架/校验读面) func tier_total(tier: String) -> int: var total := 0 - for kind in BONUS_IDS: - total += bonus_token_count(kind, tier) + for kind in FEATURE_KINDS: + total += feature_quota(kind, tier) return total @@ -115,18 +119,18 @@ func validate() -> Array: var errs: Array[Dictionary] = [] if clear_heal_pct < 0 or clear_heal_pct > 100: errs.append({"category": "domain", "message": "clear_heal_pct 越域 [0,100]: %d" % clear_heal_pct}) - for kind in BONUS_IDS: + for kind in FEATURE_KINDS: for tier in TIERS: - var c := bonus_token_count(kind, tier) + var c := feature_quota(kind, tier) if c < 0 or c > 99: errs.append({"category": "domain", "message": "token_count(%s,%s) 越域 [0,99]: %d" % [kind, tier, c]}) - var v := bonus_value(kind, tier) + var v := feature_value(kind, tier) if v < 0 or v > 999: - errs.append({"category": "domain", "message": "bonus_value(%s,%s) 越域 [0,999]: %d" % [kind, tier, v]}) + errs.append({"category": "domain", "message": "feature_value(%s,%s) 越域 [0,999]: %d" % [kind, tier, v]}) for tier in TIERS: var total := tier_total(tier) if total != int(TIER_QUOTAS.get(tier, -1)): errs.append({"category": "domain", "message": "档位配额结构失锚(v2.2 追认 b——%s 应=%d 实=%d;改总量须重裁)" % [tier, int(TIER_QUOTAS.get(tier, -1)), total]}) - if bonus_candidate_count < 1 or bonus_candidate_count > 6: - errs.append({"category": "domain", "message": "bonus_candidate_count 越域 [1,6]: %d" % bonus_candidate_count}) + if feature_candidate_count < 1 or feature_candidate_count > 6: + errs.append({"category": "domain", "message": "feature_candidate_count 越域 [1,6]: %d" % feature_candidate_count}) return errs diff --git a/game/data/schemas/meta_tree_table.gd b/game/data/schemas/meta_tree_table.gd index 6560f672..603458c7 100644 --- a/game/data/schemas/meta_tree_table.gd +++ b/game/data/schemas/meta_tree_table.gd @@ -13,8 +13,8 @@ # requires Array[node_id](显式前置——父开子脉内链)/ effects Dictionary(stat 四线 flat: # atk/max_hp/hit/armor_class;rule 键封闭 RULE_KEYS)/ fork_group/fork_side(a/b——同组互斥、 # 营地免费切换)。 -# 🔴 层级纪律(任务书红线 2):局外树只放全局规则件——effects 禁流派标签(relic 流派件永不入树, -# archetype 键出域=加载致命);流派件只走局内随机渠道。 +# 🔴 层级纪律(任务书红线 2):局外树只放全局规则件——effects 禁流派标签(relic 特性永不入树, +# archetype 键出域=加载致命);规则改写型特性只走局内随机渠道。 # A/B 只放规则面(定稿 1.3——全树互斥面 ≤10-15% 首期 4 组);两侧「不同强非强弱」MC 验差 <~3pp(T10)。 # 彩蛋 ≤3(定稿 1.4——点满某脉某排免费觉醒;发现率 <5% 改灰色预告——T10 追认单呈报)。 class_name MetaTreeTable @@ -76,9 +76,9 @@ func validate() -> Array: for ek in fx.keys(): if not (STAT_KEYS.has(String(ek)) or RULE_KEYS.has(String(ek))): errs.append({"category": "zero_flat", "message": "%s effects 键出域(四线/rule 词表封闭): %s" % [nid, String(ek)]}) - # 🔴 层级纪律:局外树禁流派件(archetype 键出域=加载致命) + # 🔴 层级纪律:局外树禁规则改写型特性(archetype 键出域=加载致命) if fx.has("archetype"): - errs.append({"category": "load_bearing", "message": "%s effects 含 archetype(🔴 层级纪律——流派件禁入局外树)" % nid}) + errs.append({"category": "load_bearing", "message": "%s effects 含 archetype(🔴 层级纪律——特性禁入局外树)" % nid}) # A/B 互斥对结构:fork 行必带 fork_group+side;同组恰 a/b 各一 if kind == "fork": var fg := String(row.get("fork_group", "")) diff --git a/game/data/schemas/relic_table.gd b/game/data/schemas/relic_table.gd index f6487ef7..f8881546 100644 --- a/game/data/schemas/relic_table.gd +++ b/game/data/schemas/relic_table.gd @@ -1,8 +1,13 @@ # VERTICAL SLICE - NOT FOR PRODUCTION # Validation Question: 七核心流派各 ≥3 件入局内随机渠道后,标签+档位激活引擎能否机械判「成型」、 -# 机制件带能否挂进令牌池稀有/罕见档随机投放(P0——迭代 12 双层 BD 实施批 T1) +# 规则改写型特性带能否挂进令牌池稀有/罕见档随机投放(P0——迭代 12 双层 BD 实施批 T1) # Date: 2026-10-04(双层 BD 实施批 T1——任务书五裁定稿;设计权威 双层BD体系-整合定稿-2026-10-03 v3) -# 数据配置 RelicTable schema(双层BD/机制件 回填 owner 批末落文;行 = Dictionary 键 relic_id,Rule 4 豁免 +# 概念指路:本表的规则改写型特性,与 adventure.tres 的属性加成型特性,同属一个对象—— +# 「特性」(一次冒险内角色自身得到的提升)。定义见 design/gdd/systems/冒险循环/特性.md。 +# 两者是它的形态枚举(form = rule / stat),不是两个系统;本表承载 rule 形态的逐项定义。 +# (2026-10-05 命名统一:旧称「流派件」→ 规则改写型特性;表名与 relic_id 沿用历史命名, +# 与统一词族对齐归后续批次——见 06-待办清单「命名统一」条目。) +# 数据配置 RelicTable schema(特性·规则改写型定义表;行 = Dictionary 键 relic_id,Rule 4 豁免 # 定义表——AuxItemTable 先例)。 # 行字段:relic_id 主键 / display_name / rarity ∈ {common, rare, rarest}(对齐令牌池三档命名—— # 投放档映射:common/rare→稀有令牌档、rarest→罕见令牌档;relic 令牌永不入普通档=「挂稀有/罕见档」 @@ -12,7 +17,7 @@ # 仅校验键域不禁纯增益(专项论证件以 positive_only 批注登记,人工清单呈报)。 # 档位激活(整合定稿 设计工具 1——以撒套装/小骨铭文):同标签计数 ≥2→档一(流派核心规则)/≥4→档二 # (完全体);散件单体保底=每件效果独立生效,档位只做质变(反例 B-2)——引擎纯函数 RelicsEngine。 -# 🔴 层级纪律(任务书红线 2):流派件只走局内随机渠道(三选一/商店/格面)——本表行永不入同调位 +# 🔴 层级纪律(任务书红线 2):规则改写型特性只走局内随机渠道(三选一/商店/格面)——本表行永不入同调位 # (aux_items 表)/局外树(T8 节点表);扫雷触发点铁律:每流派 ≥1 行 hook ∈ MINE_HOOKS(加载校验, # 违反=红线①触碰面)。 class_name RelicTable diff --git a/game/data/schemas/shop_table.gd b/game/data/schemas/shop_table.gd index 0595196c..46b2acb7 100644 --- a/game/data/schemas/shop_table.gd +++ b/game/data/schemas/shop_table.gd @@ -10,7 +10,7 @@ # 现价公式 = base_price + price_level_bonus(关卡) + price_increment × 该商品已购档数(已购档数在 冒险结构)。 # price_level_bonus = 关级定价加值行(level_index 连续从 1 递增)。 # pool_shelf = 共享池货架行(M-4 迭代 11 第②批 T1——任务书 v1.3 P1 共享池/P4 ceil):键 kind_id 词表 -# 封闭 = 四切边后种(SHELF_KINDS:attack/max_hp/armor/ap——GP 袋负交易切边、机制件三轴 doctrine 切边); +# 封闭 = 四切边后种(SHELF_KINDS:attack/max_hp/armor/ap——GP 袋负交易切边、规则改写型特性三轴 doctrine 切边); # 库存=上限即库存(账本在 冒险结构 _bonus_taken 单点共享,行族不记库存);price_a/price_b = 乘法价格 # 因子(公式 ceil(base × b^(关序−1) × A^(本次进店已购次数)),provisional 投值——P5 甲研究拍板后置追认)。 # products 行族 + 加法定价随 legacy 模式(shop=off 对照承载)保留,退役归 off 锚换代批。 diff --git a/game/data/tables/adventure.tres b/game/data/tables/adventure.tres index 6144b9f0..e1ce4c3a 100644 --- a/game/data/tables/adventure.tres +++ b/game/data/tables/adventure.tres @@ -5,27 +5,27 @@ [resource] script = ExtResource("1") clear_heal_pct = 20 -bonus_candidate_count = 3 -token_attack_common = 18 -token_attack_rare = 5 -token_max_hp_common = 17 -token_max_hp_rare = 5 -token_armor_common = 17 -token_armor_rare = 5 -token_gp_common = 18 -token_gp_rare = 5 -token_heal_rare = 5 -token_ap_rarest = 3 -bonus_attack_flat = 1 -bonus_attack_flat_large = 2 -bonus_max_hp_flat = 5 -bonus_max_hp_flat_large = 10 -bonus_armor_flat = 1 -bonus_armor_flat_large = 2 -bonus_gp_amount = 20 -bonus_gp_amount_large = 50 -bonus_heal_flat = 6 -bonus_ap_flat = 1 +feature_candidate_count = 3 +feature_quota_attack_common = 18 +feature_quota_attack_rare = 5 +feature_quota_max_hp_common = 17 +feature_quota_max_hp_rare = 5 +feature_quota_armor_common = 17 +feature_quota_armor_rare = 5 +feature_quota_gp_common = 18 +feature_quota_gp_rare = 5 +feature_quota_heal_rare = 5 +feature_quota_ap_rarest = 3 +feature_value_attack_common = 1 +feature_value_attack_rare = 2 +feature_value_max_hp_common = 5 +feature_value_max_hp_rare = 10 +feature_value_armor_common = 1 +feature_value_armor_rare = 2 +feature_value_gp_common = 20 +feature_value_gp_rare = 50 +feature_value_heal_rare = 6 +feature_value_ap_rarest = 1 ; TP0 令牌池换代(2026-10-03,node-reward v2.2 追认 b 落地):三选一池 = 固定配额令牌池—— ; 普通 70/稀有 25/罕见 3 = 98 张(罕见档原列「道具件 2」随 aux_item 池种退役收窄——台账自决披露项); diff --git a/game/data/tables/meta_tree.tres b/game/data/tables/meta_tree.tres index 05c03313..b37942f9 100644 --- a/game/data/tables/meta_tree.tres +++ b/game/data/tables/meta_tree.tres @@ -411,5 +411,5 @@ rows = [{ ; ≥ 4×(row−1));锻造脉 3 节点收编 forge_levels(钥石付价=现行迁移零痛);钥石脉=工坊解锁收编 ; (free 迁移点亮)+刷新升级移植;同调脉 socket 3(钥石=规则面首站)+Fork 4 对(A/B 集中同调脉 ; 营地免费切换——effects 首期两 rule 键真实接线余组 stat 面 provisional);彩蛋 1(锻造满排觉醒)。 -; 🔴 层级纪律:局外树只放全局规则件——零 archetype 键(schema 校验强制);流派件只走局内随机渠道。 +; 🔴 层级纪律:局外树只放全局规则件——零 archetype 键(schema 校验强制);规则改写型特性只走局内随机渠道。 ; 数值全 provisional 归 M-4 数值批;A/B 两侧差 <~3pp 验收=T10 MC。 diff --git a/game/data/tables/relics.tres b/game/data/tables/relics.tres index 461c09c5..4dfbeb1d 100644 --- a/game/data/tables/relics.tres +++ b/game/data/tables/relics.tres @@ -260,15 +260,15 @@ rows = [{ } }] -; 双层 BD 实施批(2026-10-04):机制件表——行 = 流派件定义 +; 双层 BD 实施批(2026-10-04):规则改写型特性表——行 = 特性定义 ; (relic_id/display_name/rarity/archetype/hook/effects)。 ; T2 魔法流四件(整合定稿 §2.3 S1):奥术余烬〔普通·rider+1 必中附加〕/魔网织者〔稀有·magic vs ; magic 克制罚修正〕/湛蓝誓约〔稀有·magic vs heavy 克制加成〕/魔能共鸣〔罕见锚点·rider+2+每战首次 ; 开格奥术矢——「每关首次」字面落地为「每战首次」台账披露待追认〕;magic 档一(≥2 件)rider+1 / ; 档二(≥4 件)rider 可暴击——引擎 tiers_for 承载。T3-T6 逐流派续填(flag 4/pierce 4/normal 4/ -; dig 4/charge 3/devour 4——整合定稿 §2.3 七流派件面)。 +; dig 4/charge 3/devour 4——整合定稿 §2.3 七流派的件面)。 ; 稀有度→投放档映射:common/rare → 稀有令牌档、rarest → 罕见令牌档(relic 永不入普通令牌档 -; ——「机制件带挂稀有/罕见档」追认 b 接线口径,普通档 70 张纯数值维持)。 -; 🔴 层级纪律:本表行永不入同调位(aux_items)/局外树(T8 节点表)——流派件只走局内随机渠道。 +; ——「规则改写型特性带挂稀有/罕见档」追认 b 接线口径,普通档 70 张纯数值维持)。 +; 🔴 层级纪律:本表行永不入同调位(aux_items)/局外树(T8 节点表)——规则改写型特性只走局内随机渠道。 ; 数值全 provisional 归 M-4 数值批;effects 键白名单封闭(零裸 flat 同族护栏)。 diff --git a/game/data/tables/shop.tres b/game/data/tables/shop.tres index 3976983b..bd1203c1 100644 --- a/game/data/tables/shop.tres +++ b/game/data/tables/shop.tres @@ -94,7 +94,7 @@ price_b = 1.1 ;(用户拍板骨架先行、数值整体后置,行值归 难度曲线与Boss)。 ; GP 商店房重构批(M-4 迭代 11 第②批 T1,2026-10-03——任务书 v1.3 全裁 P1 共享池/P4 ceil/P5 甲): ; pool_shelf 行族 = 共享池货架(kind_id 词表封闭四切边后种 attack/max_hp/armor/ap——GP 袋负交易切边、 -; 机制件三轴 doctrine 切边;库存=上限即库存,账本在 冒险结构 _bonus_taken 单点共享,行族不记库存); +; 规则改写型特性三轴 doctrine 切边;库存=上限即库存,账本在 冒险结构 _bonus_taken 单点共享,行族不记库存); ; 价格公式换代(pool 模式)= ceil(base_price × b^(关序−1) × A^(本次进店已购次数)),price_a=1.8/price_b=1.1 ; provisional 投值(零人工令改 provisional+后置追认,原 P5 甲研究拍板后置);products 行族 + 加法定价 ; 随 legacy 模式(shop=off 对照承载)保留不退役,退役归 off 锚换代批。货架行值全部 provisional 归 diff --git a/game/presentation/battle_narrator.gd b/game/presentation/battle_narrator.gd index f0d917e5..db5b90be 100644 --- a/game/presentation/battle_narrator.gd +++ b/game/presentation/battle_narrator.gd @@ -131,11 +131,11 @@ static func bonus_result_text(result: Dictionary) -> String: return "已选择:%s\n其余选项已丢弃(不可反悔)" % name -# 流派件卡片文案(迭代 12 T1;2026-10-04 呈现补强——第三行=hook 效果摘要,用户反馈「不知道件是 +# 特性卡片文案(迭代 12 T1;2026-10-04 呈现补强——第三行=hook 效果摘要,用户反馈「不知道件是 # 干嘛的」缺口承载;摘要=静态映射表 provisional 文案归代拍板白名单「件文案微调」) static func relic_card_text(row: Dictionary) -> String: if row.is_empty() or String(row.get("relic_id", "")) == "": - return "流派件\n???" + return "特性\n???" var arch_names := {"magic": "魔法", "pierce": "穿刺", "normal": "普攻", "dig": "开格", "flag": "标旗", "charge": "蓄力", "devour": "吞噬"} var arch := String(arch_names.get(String(row.get("archetype", "")), "流派")) @@ -167,7 +167,7 @@ static func relic_card_text(row: Dictionary) -> String: var summary := String(summaries.get(String(row.get("hook", "")), "")) if summary != "": return "%s · %s\n%s" % [String(row.get("display_name", row.get("relic_id", ""))), arch, summary] - return "流派件 · %s\n%s" % [arch, String(row.get("display_name", row.get("relic_id", "")))] + return "特性 · %s\n%s" % [arch, String(row.get("display_name", row.get("relic_id", "")))] # Boss 胜利战斗总结结算行(settlement-summary v1.1——钥石增量行;组合根拼 GP 行后追加) diff --git a/game/presentation/bonus_interact_controller.gd b/game/presentation/bonus_interact_controller.gd index 6abe4178..d6930cbc 100644 --- a/game/presentation/bonus_interact_controller.gd +++ b/game/presentation/bonus_interact_controller.gd @@ -127,9 +127,9 @@ func _bonus_card_texts(candidates: Array, aux_detail: Array = []) -> Array: elif kind == "aux_item": var iid := String(aux_detail[aux_i]) if aux_i < aux_detail.size() else "" aux_i += 1 - text = Narrator.bonus_card_text(kind, tier, int(db.adventure.bonus_value(kind, tier)), _aux_card_line(iid)) + text = Narrator.bonus_card_text(kind, tier, int(db.adventure.feature_value(kind, tier)), _aux_card_line(iid)) else: - text = Narrator.bonus_card_text(kind, tier, int(db.adventure.bonus_value(kind, tier))) + text = Narrator.bonus_card_text(kind, tier, int(db.adventure.feature_value(kind, tier))) out.append({"id": cid, "text": text}) return out diff --git a/game/presentation/hud_presenter.gd b/game/presentation/hud_presenter.gd index f2d6d235..d6e48f48 100644 --- a/game/presentation/hud_presenter.gd +++ b/game/presentation/hud_presenter.gd @@ -19,7 +19,7 @@ extends RefCounted # HP/状态效果单投喂 B 区站桩(原 B/C 双投喂为重复展示——信息归属拍板单一展示面原则) static func refresh(stage: BattleStageView, info: HeroInfoPanelView, ap_bar: ApBarView, settlement, runner, level_active: bool, db, refresh_remaining: int) -> void: - # 本关强化列表(v3.5 迭代 9 卡⑫ 2026-09-30——runner 统一加算区投影:商店购买与关卡大奖励 + # 特性列表(v3.5 迭代 9 卡⑫ 2026-09-30——runner 统一加算区投影:商店购买与关卡大奖励 # 共账本〔level_runner bonus{atk,max_hp,armor_class}〕;空加算=整节隐藏〔视图内空态纪律〕。 # 呈现只读投影零核心触碰;行文格式=代拍板白名单项) if runner != null and level_active: @@ -34,7 +34,7 @@ static func refresh(stage: BattleStageView, info: HeroInfoPanelView, ap_bar: ApB info.set_level_bonuses(lines) else: info.set_level_bonuses([]) - # 流派件持有投影(迭代 12 呈现补齐 2026-10-04——用户反馈「局内奖励选了什么看不到」: + # 特性持有投影(迭代 12 呈现补齐 2026-10-04——用户反馈「局内奖励选了什么看不到」: # 逐流派聚合行+成型档位;常驻可读+空态隐藏。档位求值=RelicsEngine 纯函数直调) if runner != null and level_active: info.set_relic_holdings(relic_holdings_lines(db, runner.relics_held())) @@ -46,7 +46,7 @@ static func refresh(stage: BattleStageView, info: HeroInfoPanelView, ap_bar: ApB return var s: Dictionary = settlement.presentation_snapshot() # 地形变异常驻角标投影(全局作用域变异首发批 2026-10-04——板级变异快照 → 文案行; - # 空态隐藏=流派件段先例;战斗全程常驻防中局遗忘) + # 空态隐藏=特性段先例;战斗全程常驻防中局遗忘) info.set_board_variants(board_variant_lines(db, s.get("board_variants", []))) var hero: Dictionary = s.hero if hero.is_empty() or not bool(hero.get("alive", false)): @@ -93,7 +93,7 @@ static func _refresh_economy(ap_bar: ApBarView, s: Dictionary, db, refresh_remai ap_bar.set_stop_enabled(bool(s.hero.get("alive", false)) and digging) -# 流派件持有聚合文案(迭代 12 呈现补齐——战斗 C 区与关卡选择页两处共用;空持有=空数组) +# 特性持有聚合文案(迭代 12 呈现补齐——战斗 C 区与关卡选择页两处共用;空持有=空数组) static func relic_holdings_lines(db, held: Array) -> Array[String]: var rlines: Array[String] = [] if db == null or db.relics == null or (db.relics.rows as Array).is_empty() or held.is_empty(): diff --git a/game/presentation/views/hero_info_panel_view.gd b/game/presentation/views/hero_info_panel_view.gd index 513a7701..7e84fd36 100644 --- a/game/presentation/views/hero_info_panel_view.gd +++ b/game/presentation/views/hero_info_panel_view.gd @@ -1,6 +1,6 @@ # VERTICAL SLICE - NOT FOR PRODUCTION # 实现 GDD:design/ux/battle.md(C 区角色信息 240×548——2026-09-26 信息归属拍板精简: -# 攻击(+修正来源角标)/护甲 AC 数据框 + 魔法道具槽(预留)+ 本关强化列表(预留)。 +# 攻击(+修正来源角标)/护甲 AC 数据框 + 魔法道具槽(预留)+ 特性列表(预留)。 # HP 条/立绘占位/状态效果槽/RAP 池/GP/钥石退役——HP 与状态唯一展示面 = B 区站桩(同一数据 # hud_presenter 双投喂 B/C 两区的重复展示);RAP 迁 D 区 AP 条(贴弃图刷新消费口); # GP(中循环)/钥石(大循环)迁出战斗屏)。 @@ -19,9 +19,9 @@ var item_slots: HBoxContainer # 魔法道具槽(迭代 7 T4 接 var _slot_panels: Array = [] # 槽 PanelContainer 引用(选中高亮/置灰重刷) var _selected_handle := 0 # 选中态(0=无;组合根回写维持单源) var _slot_handles: Array = [] # 槽位→handle 映射(set_aux_inventory 刷新) -var _bonus_section: VBoxContainer # 本关强化(预留——空态隐藏,接线归大奖励/锻造呈现批) +var _bonus_section: VBoxContainer # 特性(预留——空态隐藏,接线归大奖励/锻造呈现批) var _bonus_list: VBoxContainer -var _relic_section: VBoxContainer # 流派件持有段(迭代 12 呈现补齐——空态隐藏) +var _relic_section: VBoxContainer # 特性持有段(迭代 12 呈现补齐——空态隐藏) var _relic_list: VBoxContainer var _board_variant_section: VBoxContainer # 地形变异常驻角标(全局作用域变异首发批——空态隐藏) var _board_variant_list: VBoxContainer @@ -70,19 +70,19 @@ func _init() -> void: item_slots.add_child(slot) _slot_panels.append(slot) - # 流派件持有段(迭代 12 呈现补齐 2026-10-04——三选一流派件兑付后常驻可读:逐流派聚合行+成型档位; + # 特性持有段(迭代 12 呈现补齐 2026-10-04——三选一特性兑付后常驻可读:逐流派聚合行+成型档位; # 空态整节隐藏。用户试玩反馈「局内奖励选了什么看不到」缺口承载;2026-10-04 二次反馈上移—— # 构筑核心信息优先级高于临时强化,且防 C 区下部裁切不可见) _relic_section = VBoxContainer.new() _relic_section.add_theme_constant_override("separation", 4) _relic_section.visible = false col.add_child(_relic_section) - _relic_section.add_child(UiKit.label("流派件", 16, true)) + _relic_section.add_child(UiKit.label("特性", 16, true)) _relic_list = VBoxContainer.new() _relic_list.add_theme_constant_override("separation", 2) _relic_section.add_child(_relic_list) # 地形变异常驻角标(全局作用域变异首发批 2026-10-04——Boss 图整图型战斗全程可见防中局遗忘; - # 空态整节隐藏=流派件段先例;摆位/文案 provisional 归 HUD 框架批与本地化批) + # 空态整节隐藏=特性段先例;摆位/文案 provisional 归 HUD 框架批与本地化批) _board_variant_section = VBoxContainer.new() _board_variant_section.add_theme_constant_override("separation", 4) _board_variant_section.visible = false @@ -91,13 +91,13 @@ func _init() -> void: _board_variant_list = VBoxContainer.new() _board_variant_list.add_theme_constant_override("separation", 2) _board_variant_section.add_child(_board_variant_list) - # 本关强化(预留):锻造/大奖励/关卡奖励节点的属性提升——中循环数据因改变战斗数学准入; + # 特性(预留):锻造/大奖励/关卡奖励节点的属性提升——中循环数据因改变战斗数学准入; # 与战斗内状态效果(B 区站桩,随战斗消散)分区,防「战斗结束被清」误读;空态整节隐藏 _bonus_section = VBoxContainer.new() _bonus_section.add_theme_constant_override("separation", 4) _bonus_section.visible = false col.add_child(_bonus_section) - _bonus_section.add_child(UiKit.label("本关强化", 16, true)) + _bonus_section.add_child(UiKit.label("特性", 16, true)) _bonus_list = VBoxContainer.new() _bonus_list.add_theme_constant_override("separation", 2) _bonus_section.add_child(_bonus_list) @@ -113,7 +113,7 @@ func set_armor(ac: int) -> void: _armor_label.text = "护甲 AC %d" % ac -# 流派件持有段(迭代 12 呈现补齐):lines = 聚合文案行(「魔法 ×2 · 档一」式)——空数组 = 整节隐藏 +# 特性持有段(迭代 12 呈现补齐):lines = 聚合文案行(「魔法 ×2 · 档一」式)——空数组 = 整节隐藏 func set_relic_holdings(lines: Array) -> void: for c2 in _relic_list.get_children(): _relic_list.remove_child(c2) @@ -135,7 +135,7 @@ func set_board_variants(lines: Array) -> void: _board_variant_section.visible = not lines.is_empty() -# 本关强化列表(预留接线面):lines = 文案行数组(如「锻造 +2 攻击」)——空数组 = 整节隐藏 +# 特性列表(预留接线面):lines = 文案行数组(如「锻造 +2 攻击」)——空数组 = 整节隐藏 func set_level_bonuses(lines: Array) -> void: for c in _bonus_list.get_children(): _bonus_list.remove_child(c) diff --git a/game/presentation/views/level_map_screen.gd b/game/presentation/views/level_map_screen.gd index a03bb209..71dcbe4c 100644 --- a/game/presentation/views/level_map_screen.gd +++ b/game/presentation/views/level_map_screen.gd @@ -6,7 +6,7 @@ # 悬停预承诺(描边加粗+指针)后点击提交;press_candidate 探针入口改走图上命中同路径 # ③ 放弃冒险二次确认(布局决策 3)——首击转确认态(文案+危险红脉冲约 3 秒超时回落),二击提交 # ④ 顶栏语境:关卡名(level_row.display_name)+ GP 常驻徽章(2026-09-26 二轮拍板去向落地面) -# ⑤ 底部状态栏(布局决策 4):生命/属性/本关加成三组常读(零加成隐藏),放弃按钮右端异位 +# ⑤ 底部状态栏(布局决策 4):生命/属性/特性三组常读(零加成隐藏),放弃按钮右端异位 # 关卡画面(独立屏,Level Map Screen——2026-09-28 形态升格批 M-2 迭代 3 T2:原 RouteOverlay 模态 # 覆盖层升格独立屏,spec level-map.md 形态章节同批改写):全屏不透明独占呈现——激活期战斗屏宿主 # 由组合根整体隐藏(非暗幕半透、零透出)。零自动推进的玩家停点语义不变:唯一前进通道 = @@ -56,7 +56,7 @@ var _hp_bar: Control var _attr_value: Label var _bonus_row: HBoxContainer var _bonus_value: Label -var _relic_value: Label # 流派件持有行(迭代 12 呈现补齐——组合根投喂聚合文案) +var _relic_value: Label # 特性持有行(迭代 12 呈现补齐——组合根投喂聚合文案) var _cand_ids: Array[int] = [] # 本停点候选 id 集(图上命中合法集) var _content_size := Vector2(620, 240) # 图内容包络(open_choices 按图拟合——画布 min 尺寸随它) var _hover_id := -1 # 悬停预承诺候选(-1 = 无) @@ -118,13 +118,13 @@ func _init() -> void: _canvas.draw.connect(_draw_graph.bind(_canvas)) _canvas.gui_input.connect(_on_canvas_input) box.add_child(_canvas) - # 底部状态栏(布局决策 4:生命/属性/本关加成三组 + 放弃按钮右端异位) + # 底部状态栏(布局决策 4:生命/属性/特性三组 + 放弃按钮右端异位) var bottom := HBoxContainer.new() bottom.add_theme_constant_override("separation", 10) box.add_child(bottom) bottom.add_child(_status_box("生命", true)) bottom.add_child(_status_box("属性", false)) - # 本关加成框(零加成隐藏——spec 布局决策 4) + # 特性框(零加成隐藏——spec 布局决策 4) _bonus_row = HBoxContainer.new() _bonus_row.add_theme_constant_override("separation", 10) var bonus_box := PanelContainer.new() @@ -132,11 +132,11 @@ func _init() -> void: _bonus_row.add_child(bonus_box) var bonus_inner := VBoxContainer.new() bonus_box.add_child(bonus_inner) - var bonus_cap := UiKit.label("本关加成", 12, false, UiKit.WARM_SOFT) + var bonus_cap := UiKit.label("特性", 12, false, UiKit.WARM_SOFT) bonus_inner.add_child(bonus_cap) _bonus_value = UiKit.label("", 15, true, UiKit.WARM) bonus_inner.add_child(_bonus_value) - # 流派件持有行(迭代 12 呈现补齐 2026-10-04——用户反馈关卡选择页看不到局内奖励;组合根投喂) + # 特性持有行(迭代 12 呈现补齐 2026-10-04——用户反馈关卡选择页看不到局内奖励;组合根投喂) _relic_value = UiKit.label("", 13, false, UiKit.WARM_SOFT) _relic_value.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART bonus_inner.add_child(_relic_value) @@ -189,7 +189,7 @@ func _draw_hp_bar(bar: Control) -> void: # 放弃入口可见性(组合根在冒险启动时开、默认关——语义对象 = 整局冒险) -# 流派件持有投影(迭代 12 呈现补齐——组合根投喂聚合文案;空文案=行隐藏) +# 特性持有投影(迭代 12 呈现补齐——组合根投喂聚合文案;空文案=行隐藏) func set_relic_holdings(text: String) -> void: _relic_value.text = text @@ -324,7 +324,7 @@ func _refresh_status() -> void: if ac_bonus > 0: parts.append("AC +%d" % ac_bonus) _bonus_value.text = " · ".join(parts) - # 流派件持有行可见性(与加成行并框——任一非空整框显示;文案归组合根 set_relic_holdings) + # 特性持有行可见性(与加成行并框——任一非空整框显示;文案归组合根 set_relic_holdings) _bonus_row.visible = not parts.is_empty() or _relic_value.text != "" diff --git a/game/smoke/adventure_monte_carlo.gd b/game/smoke/adventure_monte_carlo.gd index fbc69165..50eb9131 100644 --- a/game/smoke/adventure_monte_carlo.gd +++ b/game/smoke/adventure_monte_carlo.gd @@ -42,8 +42,8 @@ func _initialize() -> void: var shop_mode := "off" if args.size() >= 6 and args[5] in ["off", "on"]: shop_mode = args[5] - # 流派件/树分层开关(迭代 12 T7/T10——off=基线;formed=成型画像开局注入七流派各 2 件档一成型集 - # 〔测量面专用 params.relics_seed——真实局流派件只走局内随机渠道〕;ab_a/ab_b=Fork posture 两侧 + # 特性/树分层开关(迭代 12 T7/T10——off=基线;formed=成型画像开局注入七流派各 2 件档一成型集 + # 〔测量面专用 params.relics_seed——真实局规则改写型特性只走局内随机渠道〕;ab_a/ab_b=Fork posture 两侧 # rule 键集——A/B 面两侧差 <~3pp 验收载体) var relic_mode := "off" if args.size() >= 7 and args[6] in ["off", "formed", "ab_a", "ab_b"]: diff --git a/game/smoke/level_autoplay.gd b/game/smoke/level_autoplay.gd index d80d25eb..ce8160ea 100644 --- a/game/smoke/level_autoplay.gd +++ b/game/smoke/level_autoplay.gd @@ -134,7 +134,7 @@ static func run_adventure(db, seed_val: int, atk_pct: int, hp_pct: int, collect_ "log_path": "", "policy": policy, "refreshes": 0, "mine_hits": 0, "mine_dmg": 0, "visited_ids": [], "choices": 0, "last_battle_enemies": [], "summary": {}, "wallet_events": [], "encounter_max_hp_seq": [], "reward_events": [], - "relic_mode": String(relic.get("mode", "off")), # 流派件分层开关(迭代 12 T7——off=316-f 通用竞争/on=成型画像优先捕捞 relic) + "relic_mode": String(relic.get("mode", "off")), # 特性分层开关(迭代 12 T7——off=316-f 通用竞争/on=成型画像优先捕捞 relic) "shop_gp_seq": [], # 商店房到达余额序(逐关 1 次——GP 跨关延续验收取数面) "prng": _policy_rng(seed_val), "mine_slips": 0, "skip_digs": 0, "shop_buys": 0, "adv": true, # v3 档位行为开关(选路评分/失误注入/商店购买只挂冒险测量面——单关夹具保持旧语义零扰动) @@ -156,7 +156,7 @@ static func run_adventure(db, seed_val: int, atk_pct: int, hp_pct: int, collect_ if not attune.is_empty(): adv_params["attunement"] = attune.get("equipped", []) adv_params["attune_refresh_y"] = int(attune.get("refresh_y", 0)) - # 流派件注入(迭代 12 T7——formed 画像=开局注入七流派各 2 件档一成型集;测量面专用) + # 特性注入(迭代 12 T7——formed 画像=开局注入七流派各 2 件档一成型集;测量面专用) if relic.has("seed_ids"): adv_params["relics_seed"] = relic.get("seed_ids", []) # 树规则键注入(迭代 12 T10——A/B 面读数载体:fork 激活侧 effects rule 键集透传) @@ -185,7 +185,7 @@ static func run_adventure(db, seed_val: int, atk_pct: int, hp_pct: int, collect_ # 终局池读数(迭代 11 第②批 T5——摘要 additive 键 pool_stock:_settle 清账前快照, # 商店买走 vs 奖励领走 vs 枯竭的终局面;事后读 adr.pool_stock 会被收束清账重置=满库假象) st["pool_stock"] = (st.get("summary", {}).get("pool_stock", {}) as Dictionary).duplicate(true) - st["relics"] = (st.get("summary", {}).get("relics", []) as Array).duplicate() # 流派件终局持有集(迭代 12 T1——摘要 additive 键清账前快照,同 pool_stock 模式) + st["relics"] = (st.get("summary", {}).get("relics", []) as Array).duplicate() # 特性终局持有集(迭代 12 T1——摘要 additive 键清账前快照,同 pool_stock 模式) st.log_path = logger.log_path() if own_session: logger.close_session() @@ -268,7 +268,7 @@ static func _on_adventure_bonus(payload: Dictionary, st: Dictionary, adr) -> voi # 三选一确定性选件(TP0 316-f——1 级优先度=最稀有〔档位最高 rarest>rare>common〕、2 级=最左; # 候选并列同档取最左=稳定序保证。空候选/未知档位 = 回退最左防御口径。 # 成型画像(迭代 12 T7——relic 模式 on:候选含 relic 令牌时优先在 relic 集内按 316-f 择一 -# 〔贪心捕捞→流派件入局→成型画像全流派覆盖——R3 乙单锚承载〕;off=relic 与数值件同规则竞争) +# 〔贪心捕捞→特性入局→成型画像全流派覆盖——R3 乙单锚承载〕;off=relic 与属性加成型特性同规则竞争) static func _pick_token(candidates: Array, relic_mode: String = "off") -> Dictionary: var pool: Array = candidates if relic_mode == "on": diff --git a/game/smoke/smoke_all.gd b/game/smoke/smoke_all.gd index 8acb1cc5..333069c7 100644 --- a/game/smoke/smoke_all.gd +++ b/game/smoke/smoke_all.gd @@ -220,12 +220,12 @@ func _smoke_adventure_table() -> void: check(int(_db.adventure.tier_total(tier)) == int(_db.adventure.TIER_QUOTAS[tier]), "档位配额结构锚(v2.2 追认 b):%s = %d 张" % [tier, int(_db.adventure.TIER_QUOTAS[tier])]) check(int(_db.adventure.deck_total()) == 98, "令牌池总量 = 98 张(普通 70/稀有 25/罕见 3——罕见档随道具件池种退役收窄)") - check(int(_db.adventure.bonus_value("gp", "common")) == 20 and int(_db.adventure.bonus_value("gp", "rare")) == 50 - and int(_db.adventure.bonus_value("attack", "common")) == 1 and int(_db.adventure.bonus_value("attack", "rare")) == 2 - and int(_db.adventure.bonus_value("max_hp", "common")) == 5 and int(_db.adventure.bonus_value("max_hp", "rare")) == 10 - and int(_db.adventure.bonus_value("armor", "common")) == 1 and int(_db.adventure.bonus_value("armor", "rare")) == 2, + check(int(_db.adventure.feature_value("gp", "common")) == 20 and int(_db.adventure.feature_value("gp", "rare")) == 50 + and int(_db.adventure.feature_value("attack", "common")) == 1 and int(_db.adventure.feature_value("attack", "rare")) == 2 + and int(_db.adventure.feature_value("max_hp", "common")) == 5 and int(_db.adventure.feature_value("max_hp", "rare")) == 10 + and int(_db.adventure.feature_value("armor", "common")) == 1 and int(_db.adventure.feature_value("armor", "rare")) == 2, "数值对(v2.2):小GP 20/大GP 50 · 小增伤 +1/大 +2 · 小生命 +5/大 +10 · 小护甲 +1/大 +2") - check(int(_db.adventure.bonus_value("heal", "rare")) == 6 and int(_db.adventure.bonus_value("ap", "rarest")) == 1, + check(int(_db.adventure.feature_value("heal", "rare")) == 6 and int(_db.adventure.feature_value("ap", "rarest")) == 1, "恢复件 +6 当即回血(新入池种类,rare 档)· AP +1(rarest 档)") check(_db.attunement_growth != null and int(_db.attunement_slot_cap()) == 3 and Attunement.slots(_db, null) == 0, @@ -349,7 +349,7 @@ func _smoke_adventure() -> void: var cand_ok := picks.size() == 2 var ks_gain_ok := picks.size() == 2 var resolve_ok := level_resolves.size() == 2 - var max_flat := int(_db.adventure.bonus_max_hp_flat) + var max_flat := int(_db.adventure.feature_value_max_hp_common) var heal_pct := int(_db.adventure.clear_heal_pct) var hp_acc := 0 # max_hp 件累加(回血封顶断言的生效上限推导——TP0 起按兑付令牌实值,大小档分别计) var ks_prefix := 0 @@ -384,7 +384,7 @@ func _smoke_adventure() -> void: var r: Dictionary = level_resolves[i] var rk := String(r.get("picked", "")) var rt := String(r.get("tier", "")) - if _smoke_find_token(p.get("candidates", []) as Array, rk, rt).is_empty() or int(r.get("value", -1)) != int(_db.adventure.bonus_value(rk, rt)): + if _smoke_find_token(p.get("candidates", []) as Array, rk, rt).is_empty() or int(r.get("value", -1)) != int(_db.adventure.feature_value(rk, rt)): resolve_ok = false if rk == "max_hp": hp_acc += int(r.get("value", max_flat)) @@ -397,7 +397,7 @@ func _smoke_adventure() -> void: var exp_base := maxi(1, int(round(float(int(_db.hero.max_hp)) * k))) # 模拟档 v3.4 商店贪心购血(数值修复批)合法抬升——上限窗口 = 基础 + 加算区 3 件 + 购血余量; # TP0 数值对后 max_hp 件有大生命 +10(rare 档)——上界按大件最坏构成 3×10+购血 15=+45(TP0 放宽) - var hp_ceiling := maxi(1, int(round(float(int(_db.hero.max_hp) + 3 * int(_db.adventure.bonus_value("max_hp", "rare")) + 15) * k))) + var hp_ceiling := maxi(1, int(round(float(int(_db.hero.max_hp) + 3 * int(_db.adventure.feature_value("max_hp", "rare")) + 15) * k))) var seq_ok := seq.size() > 0 and int(seq[0]) == exp_base for v in (seq as Array): if int(v) < exp_base or int(v) > hp_ceiling: @@ -592,22 +592,22 @@ func _smoke_adventure() -> void: a13.present_node_bonus(ncands13, ndraw.get("aux_detail", []) as Array) a13.present_node_bonus([{"kind": "gp", "tier": "common"}]) var gp13 := int(a13.ledger.get("gp", 0)) - check(a13.apply_node_bonus("gp", "common") and int(a13.ledger.get("gp", 0)) == gp13 + int(_db.adventure.bonus_value("gp", "common")), - "奖励节点 GP 件入账(钱包「奖励入账」收口——+%d)" % int(_db.adventure.bonus_value("gp", "common"))) + check(a13.apply_node_bonus("gp", "common") and int(a13.ledger.get("gp", 0)) == gp13 + int(_db.adventure.feature_value("gp", "common")), + "奖励节点 GP 件入账(钱包「奖励入账」收口——+%d)" % int(_db.adventure.feature_value("gp", "common"))) check(a13._node_bonus_pending.is_empty(), "节点停点态兑付后清零(恰一次语义同构)") var s10: Dictionary = a10.summary check(String(s10.get("result", "")) == "abandoned" and not bool(s10.get("cleared", true)), "放弃摘要:abandoned · 未打穿(已获大奖励不追回——同失败型结算)") -# ---- 双层 BD 机制件基建冒烟(迭代 12 T1——relic_table/档位激活引擎/机制件带池接线)---- +# ---- 双层 BD 规则改写型特性基建冒烟(迭代 12 T1——relic_table/档位激活引擎/规则改写型特性带池接线)---- func _smoke_relics() -> void: - print("--- 机制件基建(relic_table · 档位激活引擎 · 机制件带接线)---") + print("--- 规则改写型特性基建(relic_table · 档位激活引擎 · 规则改写型特性带接线)---") # ① 现行表牌库构成:七流派 27 件全量入池——98 数值令牌+27 relic 令牌(批次一铺量完成) check(_db.relics != null and (_db.relics.rows as Array).size() == 27, "relic_table 已加载(七流派 27 件全量——批次一 T2-T6 铺量完成)") var a_r0 = load("res://core/adventure_runner.gd").new(_db, _fresh_rng(71)) - check(a_r0.start_adventure(71, {"first_script": true}), "机制件带场景:冒险启动(seed 71)") + check(a_r0.start_adventure(71, {"first_script": true}), "规则改写型特性带场景:冒险启动(seed 71)") var relic_tokens := 0 var rarest_tokens := 0 for t in a_r0._bonus_deck: @@ -616,7 +616,7 @@ func _smoke_relics() -> void: if String((t as Dictionary).get("tier", "")) == "rarest": rarest_tokens += 1 check(relic_tokens == 27 and rarest_tokens == 6 and a_r0._bonus_deck.size() == 125, - "机制件带入池:27 件(rare 档 21 + rarest 锚点 6)——牌库 98+27=125") + "规则改写型特性带入池:27 件(rare 档 21 + rarest 锚点 6)——牌库 98+27=125") check(_db.relics.validate().is_empty(), "relic_table.validate 零违例(有行流派扫雷端铁律——magic first_dig_spell 在案)") # ② 档位激活引擎(纯函数直测——构造表 4 件 magic + 1 件 flag + 1 件 rarest 锚点) var rt := RelicTable.new() @@ -638,17 +638,17 @@ func _smoke_relics() -> void: var hooks := RelicsEngine.hooks_for(["m1", "f1"], rt) check(hooks.size() == 2 and String(hooks[0].get("hook", "")) == "hero_attack_rider", "挂点投影:表序稳定(同集合→同投影)") - # ③ 机制件带接线(临时表注入——relic 令牌入牌库/兑付入持有集/踢池/断点往返;测试尾还原现行表) + # ③ 规则改写型特性带接线(临时表注入——relic 令牌入牌库/兑付入持有集/踢池/断点往返;测试尾还原现行表) var live_rows: RelicTable = _db.relics _db.relics = rt var a_r = load("res://core/adventure_runner.gd").new(_db, _fresh_rng(72)) - check(a_r.start_adventure(72, {"first_script": true}), "机制件带场景:冒险启动(seed 72——注入 5 行临时表)") + check(a_r.start_adventure(72, {"first_script": true}), "规则改写型特性带场景:冒险启动(seed 72——注入 5 行临时表)") var deck_relic := 0 for t in a_r._bonus_deck: if String((t as Dictionary).get("kind", "")) == "relic": deck_relic += 1 check(deck_relic == 5 and a_r._bonus_deck.size() == 103, - "机制件带入池:5 行 relic 每件 1 张(common/rare→稀有档 rarest→罕见档)——牌库 98+5=103") + "规则改写型特性带入池:5 行 relic 每件 1 张(common/rare→稀有档 rarest→罕见档)——牌库 98+5=103") var relic_seen: Dictionary = {} for i in 60: for t in a_r._draw_bonus_candidates(): @@ -726,13 +726,13 @@ func _smoke_relics() -> void: "深挖钻头=开掘 +1 AP/每 4 格深层产出(R4 甲非信息税对价)· 蓄力三件=层值 1/减伤 1/层/满层 ×2") check(orch.action_economy.relic_ap_carry and orch.action_economy.relic_dig_extra == 1, "蓄力/钻头 action_economy 注入(ap_carry 改写停手转存 + 付费开掘对价注入——关着 false/0 零扰动)") - # ⑦c 流派件持有呈现段(2026-10-04 用户反馈补齐——C 区「流派件」节:聚合行+成型档位;空态隐藏) + # ⑦c 特性持有呈现段(2026-10-04 用户反馈补齐——C 区「特性」节:聚合行+成型档位;空态隐藏) var panel = load("res://presentation/views/hero_info_panel_view.gd").new() panel.set_relic_holdings([]) - check(not panel._relic_section.visible, "流派件段空态隐藏(视图空态纪律同本关强化段)") + check(not panel._relic_section.visible, "特性段空态隐藏(视图空态纪律同特性段)") panel.set_relic_holdings(["魔法 ×2 · 档一", "开格 ×1 · 散件"]) check(panel._relic_section.visible and panel._relic_list.get_child_count() == 2, - "流派件段持有呈现(聚合行+成型档位常驻可读——「局内奖励选了什么看不到」缺口承载)") + "特性段持有呈现(聚合行+成型档位常驻可读——「局内奖励选了什么看不到」缺口承载)") # ⑦b 深挖钻头付费开掘回归(2026-10-04 试玩缺陷修复——对价挂付费侧):AP=1 降级照常开格 # (用户实测「AP=1 无法开格只能标旗」的回归闸);AP=2 付全价积付费计数(深层产出配额取数面)。 var ae_dd = load("res://core/action_economy.gd").new(_db) @@ -3773,8 +3773,8 @@ func _smoke_shop_pool() -> void: var val0: int = int(a8.bonus.get(String(val_map[kind]), -999)) check(r8.buy_pool_item(kind), "购买受理(pool 口——%s|%s)" % [kind, tier]) check(int(r8.gp) == gp0 - int(buy_c.get("price", 0)), "钱包扣现价(%d → %d)" % [gp0, int(r8.gp)]) - check(int(a8.bonus.get(String(val_map[kind]), -999)) == val0 + int(_db.adventure.bonus_value(kind, tier)), - "加算区 +令牌档位件值(池件=奖励件本体——%s|%s %+d)" % [kind, tier, int(_db.adventure.bonus_value(kind, tier))]) + check(int(a8.bonus.get(String(val_map[kind]), -999)) == val0 + int(_db.adventure.feature_value(kind, tier)), + "加算区 +令牌档位件值(池件=奖励件本体——%s|%s %+d)" % [kind, tier, int(_db.adventure.feature_value(kind, tier))]) check(int(a8._bonus_taken.get(kind, 0)) == taken0 + 1, "共享池账本 -1(跨渠道单点——taken %d → %d)" % [taken0, int(a8._bonus_taken.get(kind, 0))]) # A 链:同visit 第二购现价 = ceil(base×b^(l2−1)×A^1)(货架已全重抽——新卡新价同公式) var second: Dictionary = {} @@ -3788,7 +3788,7 @@ func _smoke_shop_pool() -> void: check(int(second.get("price", -1)) == expect_p2, "A 链爬价 = ceil(base×b^(关序−1)×A^1)(进店第 2 购——%d)" % expect_p2) check(r8.buy_pool_item(String(second.get("kind_id", ""))), "同 visit 第二购受理(A 链软闸在价不在限)") - # ④ 切边零入店(白-box 重抽 40 次——GP 袋/机制件永不在架;重抽消费 shop_draw 签,场景尾不回写主时间线) + # ④ 切边零入店(白-box 重抽 40 次——GP 袋/规则改写型特性永不在架;重抽消费 shop_draw 签,场景尾不回写主时间线) var cut_seen := false for i in 40: r8._shop_draw_shelf() @@ -3839,7 +3839,7 @@ func _smoke_shop_pool() -> void: for k in ps.keys(): var quota := 0 for tier in _db.adventure.TIERS: - quota += int(_db.adventure.bonus_token_count(String(k), tier)) + quota += int(_db.adventure.feature_quota(String(k), tier)) if int(ps[k]) < 0 or int(ps[k]) > quota: ps_ok = false check(ps_ok, "终局池余量在域 [0,配额](%s)" % str(ps)) @@ -4430,7 +4430,7 @@ func _smoke_save() -> void: and int(bp.get("hero_hp", -1)) == 13, "断点七字段往返:关卡序号/节点位/生命") var bp_bonus: Dictionary = bp.get("bonus", {}) check(int(bp_bonus.get("atk", -1)) == 2 and int(bp_bonus.get("max_hp", -1)) == 5 - and int(bp_bonus.get("armor_class", -1)) == 1, "断点七字段往返:本关加成区") + and int(bp_bonus.get("armor_class", -1)) == 1, "断点七字段往返:属性加成区") check(int(bp.get("gp", -1)) == 17, "断点七字段往返:GP 钱包") var bp_shop: Dictionary = bp.get("shop_purchased", {}) check(int(bp_shop.get("hp_small", -1)) == 2 and int(bp_shop.get("atk_small", -1)) == 1,