Files
gplan-2/game/data/schemas/adventure_table.gd
T
DKChan 072c19b4a5 feat(凭证件裁削): 卡② 同调电池删除+完美保险迁专长+配额净删落地(迭代 31 卡②)
用户 2026-10-18 逐裁四项落码:
- T1/T2 同调电池整件删除:CURIO_KINDS 摘 kind、三字段与三处分发表分支删净、
  runner 侧 _battery_pending/断点键/getter/choose_battery_target 全清(呈现层零接线=有账本无入口)。
- T3 完美保险出池:kind/字段/分发摘除,_pending_insurance 与 level_runner 注入通道
  (voucher_insurance 键、set_voucher_grants 第三参)整链拆除,battle_orchestrator._fx_insurance 删。
- T4 引擎扩签 forgive_seal_miss(EFFECT_KINDS 31→32)+两账相减:新增 _perfect_forgiven 单向累加、
  谓词抽成 perfect_sweep_earned()(有效误标=误标总数−豁免数),_perfect_hit_false 保持纯净=契约 2;
  seal_missed 发射时机与消费点零改动=契约 3(危险直觉·守同事件订阅面在验收组里对拍)。
- T5 feats.tres 第 30 行完美保险专长:rarity rare/cap 省略/domain=battle 显式写出(战斗域首例)/
  desc「本场首次封印落空,不计入完美封印判定」;限次由行 when counter(insurance_used) lt 1 承载,
  do 自带 counter_id 记账由授予段消费点落账(代拍板 3 选型:单行落表,理由见实现报告)。
- T6 配额净删:TIER_QUOTAS rare 9→7、令牌池总量 104→102,validate() 硬断言过;smoke 配额锚/牌库
  构成/专长行数随批换代。
- T7 验收:feat_vouchers_test 39 项全绿(出池反例/断点缺键兼容/账本保留/配额锚/装载/限次一次/
  计数纯净/两账相减真值表/跨战清零/事件不吞)+forge_table 词表闭集断言 31→32。
  变异验证 6 条:5 条证红;「domain battle→adventure」在本 rig 不可观测(未红),已如实登记。
- 存量缺陷顺带修:旧 _emit_row("insurance_used","",…) 空来源会触发行来源断言(旧路径无消费点故从未走红),
  新订阅面给出 source_class=seal_miss。

基线(卡① 合回后 master 4f953ce8):冒烟 1151/0、单元 34 套全绿、探针 --click 全绿(user:// 存档移开态)。
2026-10-19 04:45:49 +08:00

234 lines
15 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## VERTICAL SLICE - NOT FOR PRODUCTION
## 冒险大奖励表(奇物三选一令牌池)schema:档位配额/件值/已拿上限的类型化读取(单行全局;垂直切片验证:三关连探一条命走完)。
## kind/tier 词表封闭——断点附随件与牌库剔除态依赖,扩件走本表+registry 修订,禁调用侧私扩。
## 档位配额总量是结构锚(validate 硬断言):改投放总量=重裁非调参;全部 knob provisional,上调须重扫通关率带。
class_name AdventureTable
extends Resource
## 概念指路:本表的属性值提升与资源,与 feats.tres 的专长,同属一个对象——
## 「奇物」(一次冒险内各渠道给予玩家的增益总称)。定义见 design/gdd/systems/冒险循环/奇物.md。
## 它们是它的分类轴上的枚举(专长 / 属性值提升 / 资源),不是三套系统;
## 本表承载属性值提升与资源的种类配额与件值。
## (2026-10-05 命名统一 + v2.0 改名:旧称「数值件」→ 属性提升;顶层「特性」→「奖励」→「奇物」。
## 常量与字段随之前缀 curio_*,**尚未**随顶层改名换到 reward_*——见 06-待办清单。
## 分类轴三个枚举:属性值提升〔生命上限 / AC / 攻击〕;资源〔行动点上限 /
## 刷新次数 / GP / 回复,命名待定〕——本表两类混编;刷新次数与专长获取两项尚未入表。
## 类内异质性:GP与回复是即时兑付,不进持有集、不持续生效。)
## 三选一提升池 kind 词表(封闭——断点附随件与牌库剔除态依赖它;扩件走本表+registry 修订)。
## treasure_item 池种退役(迭代 11 第①批 T7——同调批出池);heal 恢复件新入池(v2.2 令牌池追认 b)。
## 迭代 20 T4 资源凭证入池五件;迭代 31 卡② 凭证件裁削批(用户 2026-10-18 逐裁)两件出池:
## 同调电池整件删除(呈现层零接线、玩家无分配途径——有 API 有账本唯独没有入口);
## 完美保险整件迁出资源类归专长(它给的是规则豁免而非可调动的余量——判据见奇物.md §1.1,
## 落表 feats.tres 第 30 行,效果类型 forgive_seal_miss)。留任 rap 储备金袋/time_sand 时沙。
const CURIO_KINDS: Array[String] = ["attack", "max_hp", "armor", "gp", "ap", "heal", "refresh",
"rap", "time_sand"] # T6 扩第七类(refresh=资源类成员——作为奇物授予的三选一重抽次数,作用对象=三选一界面非角色;见 registry refresh_boundary)
## 令牌档位词表(迭代 20 T2 换代——跨层四级稀有度框架〔01-核心循环 v1.5 档名映射:普通→普通、
## 稀有→优秀、罕见→稀有、传说=新增头奖位〕;1 级最稀有=legendary 优先)
const TIERS: Array[String] = ["common", "excellent", "rare", "legendary"]
const TIER_COMMON := "common"
const TIER_EXCELLENT := "excellent"
const TIER_RARE := "rare"
const TIER_LEGENDARY := "legendary"
## 档位配额结构锚(迭代 20 换代——T2 四级直映射 70/25/3/0;T4 凭证四件入稀有档投放 +6
## (rap 2/battery 1/时沙 2/保险 1)→ 稀有 9、总量 104;迭代 31 卡② 净删两件投放(battery 1/保险 1)
## → 稀有 7、总量 102(用户裁「净删」,禁把令牌转给别件保住总量)。已裁换代授权内的 provisional 投放
## (卡文 T2「四级配额表重构」+Q3 单迭代全量),偏离 GDD 占位记录随代拍板追认单呈报;
## validate() 硬断言;此后改总量=重裁非调参)。
const TIER_QUOTAS := {"common": 70, "excellent": 25, "rare": 7, "legendary": 0}
# —— 通关部分回血(固定型,非末关通关兑付)——
@export var clear_heal_pct: int = 20 # [0,100] knob——回复生效上限的百分比,封顶上限不回满
# —— 三选一候选数(2026-10-02 修复批 T2 魔法数结构化)——
@export var curio_candidate_count: int = 3 # [1,6] knob——令牌洗牌不放回抽取张数上界
@export var shop_refresh_free: int = 0 # [0,9] knob(MC-1 provisional——进店免费刷新次数;基础 0=Q2 裁,天赋增益位预留)
@export var shop_refresh_cost_base: int = 20 # [1,999] knob(MC-1 provisional——GP 刷新基价)
@export var shop_refresh_cost_curve: float = 1.8 # [1.0,4.0] knob(MC-1 provisional——按已付费刷新数幂曲线,A 链同族)
# —— 令牌配额(kind × tier 计数;未列组合 = 0。迭代 20 T2 四级换代:旧 rare→excellent、
# 旧 rarest→rare 物理承袭〔70/25/3 零偏离〕+凭证四 kind 占位 rare 档配额 0〔T4 落路由同批投放〕)——
@export var curio_quota_attack_common: int = 18 # [0,99]
@export var curio_quota_attack_excellent: int = 5 # [0,99]
@export var curio_quota_max_hp_common: int = 17 # [0,99]
@export var curio_quota_max_hp_excellent: int = 5 # [0,99]
@export var curio_quota_armor_common: int = 17 # [0,99]
@export var curio_quota_armor_excellent: int = 5 # [0,99]
@export var curio_quota_gp_common: int = 18 # [0,99]
@export var curio_quota_gp_excellent: int = 5 # [0,99]
@export var curio_quota_heal_excellent: int = 3 # [0,99]——恢复件(原 5;T6 挤占 2 席位予 refresh——用户 2026-10-05 裁方案B,总量 98 锚不变)
@export var curio_quota_refresh_excellent: int = 2 # [0,99]——刷新次数件(T6 新入池资源类成员;provisional 归曲线调参批)
@export var curio_quota_ap_rare: int = 3 # [0,99]——AP 件(稀有档;旧罕见档物理承袭)
@export var curio_quota_rap_rare: int = 2 # [0,99]——储备金袋(T4 投放 provisional 归调参批)
@export var curio_quota_time_sand_rare: int = 2 # [0,99]——时沙(T4 投放 provisional 归调参批)
# —— 令牌件值(小/大数值对——v2.2 追认 b 定稿:20/50、+1/+2、+1/+2、+5/+10、恢复+6、AP+1)——
@export var curio_value_attack_common: int = 1 # [0,999] knob——小增伤
@export var curio_value_attack_excellent: int = 2 # [0,999] knob——大增伤
@export var curio_value_max_hp_common: int = 5 # [0,999] knob——小生命
@export var curio_value_max_hp_excellent: int = 10 # [0,999] knob——大生命
@export var curio_value_armor_common: int = 1 # [0,999] knob——小护甲
@export var curio_value_armor_excellent: int = 2 # [0,999] knob——大护甲
@export var curio_value_gp_common: int = 20 # [0,999] knob——小GP
@export var curio_value_gp_excellent: int = 50 # [0,999] knob——大GP
@export var curio_value_heal_excellent: int = 6 # [0,999] knob——恢复(当即回血,封顶生效上限)
@export var curio_value_refresh_excellent: int = 1 # [0,9] knob(provisional)——刷新次数件兑付值(三选一重抽次数 +N——_attune_refresh_x 增量,不进加算区)
@export var curio_value_ap_rare: int = 1 # [0,10] knob——AP 件每场战斗首轮行动点基线增量
@export var curio_value_rap_rare: int = 3 # [0,99] knob(provisional)——储备金袋 RAP +N
@export var curio_value_time_sand_rare: int = 2 # [0,99] knob(provisional)——时沙 下轮 AP +N
# —— 已拿上限 cap(迭代 20 T2 概率与上限解耦〔奇物.md 池结构案D〕——案②令牌池+提前退役:
# 概率位=档+令牌数〔牌库物理张数〕、上限=本字段〔拿了才计、刷出不计〕;cap 满后该 kind 从候选
# 视图剔除〔提前退役〕。99=实质无上限占位,实数归调参批;专长 cap 在 feats.tres 行字段〕)——
@export var curio_cap_attack: int = 99 # [1,99]
@export var curio_cap_max_hp: int = 99 # [1,99]
@export var curio_cap_armor: int = 99 # [1,99]
@export var curio_cap_gp: int = 99 # [1,99]
@export var curio_cap_ap: int = 99 # [1,99]
@export var curio_cap_heal: int = 99 # [1,99]
@export var curio_cap_refresh: int = 99 # [1,99]
@export var curio_cap_rap: int = 99 # [1,99]
@export var curio_cap_time_sand: int = 99 # [1,99]
# —— 专长获取门票(迭代 15 卡② T5——非 Boss 渠道的专长入口形态,奇物.md v2.7 渠道轴定位;
# 四口径契约④:拿到即开不可囤积/罕见只在概率不在价格/一局限购一次/计步保底连续 5 展示未出
# 第 6 必出(计数=展示次数、刷新重展计入、节点与商店共享、触发清零、限购满不再触发)。
# 四参数全部 provisional 归曲线调参批;limit/pity_step 系口径定死值调参批可复议)——
@export var feat_ticket_chance: int = 20 # [0,100] knob(provisional)——每次非 Boss 渠道展示门票出现概率 %
@export var feat_ticket_quota: int = 2 # [0,9] knob(provisional)——每局门票出现次数上限
@export var feat_ticket_limit: int = 1 # [1,9] knob(口径定死=1)——一局限购(选中/买下)次数
@export var feat_ticket_pity_step: int = 5 # [1,99] knob(口径定死=5)——保底步数(连续未出展示次数)
## 令牌兑付路由表(内容数据驱动扩展批 T5——_apply_curio_pick match 收敛进效果类型:
## 属性值提升四类 = 「加算落点键」声明路由,加新加算类令牌 = 表行+配额/件值键,零代码;
## 通道面三类(gp 钱包/heal 台账/refresh 界面余量)+relic 持有集 = 副作用通道显式分支不进本表
## ——路由表只承载「纯加算落点」形态,与效果引擎组合规则加法族同构)
const CURIO_APPLY_ROUTES := {
"attack": "atk",
"max_hp": "max_hp",
"armor": "armor_class",
"ap": "ap",
}
## 令牌加算路由读数(空 = 非加算形态——调用方走通道面分支)
func curio_apply_route(kind: String) -> String:
return String(CURIO_APPLY_ROUTES.get(kind, ""))
## 令牌配额读数(未列 kind×tier 组合 = 0——迭代 20 T2 四级构成:属性四类 common/excellent、
## heal/refresh excellent、ap rare、凭证四 kind rare 占位 0)
func curio_quota(kind: String, tier: String) -> int:
match [kind, tier]:
["attack", TIER_COMMON]: return curio_quota_attack_common
["attack", TIER_EXCELLENT]: return curio_quota_attack_excellent
["max_hp", TIER_COMMON]: return curio_quota_max_hp_common
["max_hp", TIER_EXCELLENT]: return curio_quota_max_hp_excellent
["armor", TIER_COMMON]: return curio_quota_armor_common
["armor", TIER_EXCELLENT]: return curio_quota_armor_excellent
["gp", TIER_COMMON]: return curio_quota_gp_common
["gp", TIER_EXCELLENT]: return curio_quota_gp_excellent
["heal", TIER_EXCELLENT]: return curio_quota_heal_excellent
["refresh", TIER_EXCELLENT]: return curio_quota_refresh_excellent
["ap", TIER_RARE]: return curio_quota_ap_rare
["rap", TIER_RARE]: return curio_quota_rap_rare
["time_sand", TIER_RARE]: return curio_quota_time_sand_rare
return 0
## 令牌件值(kind × tier;四级构成随配额表)
func curio_value(kind: String, tier: String = TIER_COMMON) -> int:
match [kind, tier]:
["attack", TIER_COMMON]: return curio_value_attack_common
["attack", TIER_EXCELLENT]: return curio_value_attack_excellent
["max_hp", TIER_COMMON]: return curio_value_max_hp_common
["max_hp", TIER_EXCELLENT]: return curio_value_max_hp_excellent
["armor", TIER_COMMON]: return curio_value_armor_common
["armor", TIER_EXCELLENT]: return curio_value_armor_excellent
["gp", TIER_COMMON]: return curio_value_gp_common
["gp", TIER_EXCELLENT]: return curio_value_gp_excellent
["heal", TIER_EXCELLENT]: return curio_value_heal_excellent
["refresh", TIER_EXCELLENT]: return curio_value_refresh_excellent
["ap", TIER_RARE]: return curio_value_ap_rare
["rap", TIER_RARE]: return curio_value_rap_rare
["time_sand", TIER_RARE]: return curio_value_time_sand_rare
return 0
## 已拿上限读数(迭代 20 T2 案②——kind 维度;专长 cap 走 feats.tres 行字段不走本面)
func curio_cap(kind: String) -> int:
match kind:
"attack": return curio_cap_attack
"max_hp": return curio_cap_max_hp
"armor": return curio_cap_armor
"gp": return curio_cap_gp
"ap": return curio_cap_ap
"heal": return curio_cap_heal
"refresh": return curio_cap_refresh
"rap": return curio_cap_rap
"time_sand": return curio_cap_time_sand
return 99
## Boss 专长三选一按档配比加权(迭代 20 T5——奇物.md v3.1 rarity 语义约束「候选按档配比或
## 加权抽取」兑付面;权重 provisional 归调参批——普通打底/优秀期待/稀有稀缺/传说头奖形态)
func boss_feat_weight(tier: String) -> int:
match tier:
TIER_COMMON: return 100
TIER_EXCELLENT: return 45
TIER_RARE: return 15
TIER_LEGENDARY: return 5
return 1
## 档位判读序(MC 策略 316-f——1 级最稀有:legendary > rare > excellent > common;并列同档取最左由调用方稳定序保证)
func tier_rank(tier: String) -> int:
match tier:
TIER_LEGENDARY: return 4
TIER_RARE: return 3
TIER_EXCELLENT: return 2
TIER_COMMON: return 1
return 0
## 档位令牌总数(货架/校验读面)
func tier_total(tier: String) -> int:
var total := 0
for kind in CURIO_KINDS:
total += curio_quota(kind, tier)
return total
## 牌库总量(结构锚——T2 四级 98 + T4 凭证投放 6 = 104:70+25+9+0)
func deck_total() -> int:
var total := 0
for tier in TIERS:
total += tier_total(tier)
return total
func validate() -> Array:
var errs: Array[Dictionary] = []
for kv in [["feat_ticket_chance", feat_ticket_chance, 0, 100], ["feat_ticket_quota", feat_ticket_quota, 0, 9], ["feat_ticket_limit", feat_ticket_limit, 1, 9], ["feat_ticket_pity_step", feat_ticket_pity_step, 1, 99]]:
if int(kv[1]) < int(kv[2]) or int(kv[1]) > int(kv[3]):
errs.append({"category": "domain", "message": "%s 出域 [%d,%d]: %d" % [kv[0], kv[2], kv[3], kv[1]]})
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 CURIO_KINDS:
for tier in TIERS:
var c := curio_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 := curio_value(kind, tier)
if v < 0 or v > 999:
errs.append({"category": "domain", "message": "curio_value(%s,%s) 越域 [0,999]: %d" % [kind, tier, v]})
if curio_cap(kind) < 1 or curio_cap(kind) > 99:
errs.append({"category": "domain", "message": "curio_cap(%s) 越域 [1,99]: %d" % [kind, curio_cap(kind)]})
for tier in TIERS:
var total := tier_total(tier)
if total != int(TIER_QUOTAS.get(tier, -1)):
errs.append({"category": "domain", "message": "档位配额结构失锚(四级锚 70/25/7/0——%s 应=%d 实=%d;改总量须重裁)" % [tier, int(TIER_QUOTAS.get(tier, -1)), total]})
if curio_candidate_count < 1 or curio_candidate_count > 6:
errs.append({"category": "domain", "message": "curio_candidate_count 越域 [1,6]: %d" % curio_candidate_count})
return errs