# 玩法系统原源码契约与动态回归入口

研究日期：2026-10-09。证据只来自原 `js/bundle.js` 的静态解码副本 [bundle.decoded.js](../../artifacts/reverse/bundle.decoded.js) 与 [格式化副本](../../artifacts/reverse/bundle.decoded.formatted.js)。原件位于 [js/game.js](../../artifacts/original/unpacked/js/game.js)。下文偏移为解码文件中从 0 开始的字符位置，不是行号或字节位置。**已证明**代表直接源码分支；**未证明**代表本轮尚未追全或仍需真实运行。这里没有把调用终局函数或资源存在当作自然玩法回归通过。

## 可以直接用的原对象与入口

假设浏览器桥接只暴露原实例为 `window.__tpfyGame`，记为 `game`。原唯一构造表达式仍是 `new T_(Dx["mpv"])`（解码2774250；原raw2095803 `new T_(Dx[s[1886]])`）。不能为QA再创建第二个T_，全局单例和事件监听会冲突。

| 原对象 | 作用 | 证据位置 |
|---|---|---|
| `game.zbu.script.ncl` / `Vm` | 首页，`lax(mode)`是原启动按钮handler | 705798、756243 |
| `game.zbu.script.qxt` / `Ld` | 匹配UI，准备本局名字、头像、人员名册后启动 | 513495–525710 |
| `game.zbu.script.fca` / `Im` | 战斗UI；`gye()`推进入场倒计时 | 396130、417614 |
| `game.zbu.script.bey` / `km` | 手动维修技能UI，`jys()`含冷却 | 628004、630358 |
| `game.trv` / `Kd`，`.qch` | 建筑/房间管理器，Kw房间列表 | 1822637、1824732、1865988 |
| `game.trv.hln.holySword` / `Fw` | 圣剑建筑管理器 | 1823564 |
| `game.llw` / `J_`，`.player` | 本地角色；`.sev`为生存阵营列表 | 2352871、2362087 |
| `game.cbr` / `Cx`，`.crg` | 主怪物实体（ag继承xw）；`.lns`另有伥鬼实体 | 1060047、1076827 |
| `game.rgy` / `sw`，`.xww` | 当前模式怪物逻辑控制器 | 1880193–1881907 |
| `game.cfi()` / `game.kzg()` | 原模拟暂停/恢复 | 2323812 / 2314037；格式化311060、310469 |

`gm.instance.pxv(event,...args)`是原发布事件接口；`eub(event,...args)`用于返回值查询。已证明的事件常量（141000附近）：syy=`GMSelectMap`，mci=`GMSetPlotMapIndex`，kbt=`GMStartGame`，yny=`GMGameOver`，rxj=`GMPauseGame`，zya=`GMResumeGame`，ogn=`gmGameOverCanotDie`，jdk=`BuildSkillEvent`，jio=`TLLevelUpThing`，gme=`TrollLogicState`。

## 必须先匹配，再开始实体初始化

**已证明：** `game.eux(mapIndex)`仅设置普通地图字段rls；`game.dwo(plotIndex)`仅设置剧情字段xvw。`game.lax()`是GMStartGame实际handler，直接构造本局实体，需要名册已经由匹配阶段准备。因此从首页直接 `.eux(0); .lax()` 不是完整开局链，会缺少J_所需的角色记录；不能据此判定地图或模式坏了。

完整原UI入口是 `game.zbu.script.ncl.lax(mode)`：传参时设置 `sd.mode`，整理首页动画，100ms后通过UIGMshow展示匹配UI。也可以设置模式与地图后 `game.zbu.script.qxt.Show()`。基类 `Show()`将视图加入scene并执行 `.sze()`（266412）；Ld.sze（519207）按模式准备队列、调用player.iou()，并启动1000ms的原Laya匹配回调 `.mbl()`。

Ld.mbl（522495）每次以70%概率从ogr随机取一项；普通角色向 `ciu.awh`写 `{name,index,skin}`，怪物写rwy，填原头像。这里的名称/阵容是原本地生成逻辑，不是实时匹配成功的证据。准备按钮 `.ivb()`（517028）置pky，ogr为空后 `.mbl()`走 `.lax()`（516075），派发GMStartGame。CanotDie额外显示剧情告示，最后 `.ibd()`（524521）才开局。

可用于QA加速匹配的边界：调用一次原Show/sze准备，再有限次数调用原mbl直到ogr为空，最后原ivb与mbl；CanotDie走原ibd。不要手造角色实体、不要重复sze后仍沿用旧名册、不要依赖固定回调次数保证随机队列为空。

## 7种模式初始化

原枚举 **Normal0、Troll1、Puppet2、Plot3、Nightmare4、CanotDie5、Compound6**（格式化4785–4791）。T_.lax（2317478）先重置本局状态、时钟、建筑系统，再按模式选地图、创建人物/怪物、注册更新，最后显示战斗UI。

| 模式 | T_.lax地图选择 | sw.xww逻辑控制器 | 已证明的额外初始化 |
|---|---|---|---|
| Normal普通 | 通常rls；新手/开放等级/ocr分支会选择0或每日地图 | Uw；开放等级且wao≥2时50%走zw | map0随机房间与可能活动；调用原普通经济配置分支 |
| Troll猎梦者 | 当日首次地图2；否则tsd按qlj或每日配置选图 | lw | 开局randomRoomBlock；玩家是怪物，倒计时结束开放怪物输入与装备 |
| Puppet伥鬼与天使 | 地图1 | Uw（开放等级随机条件是Normal的ykk，不能无条件套用） | 角色死亡后可以走阵营选择和伥鬼转化 |
| Plot剧情 | xvw指定剧情地图 | 地图11为Jw，其他通常Uw | 7图两人；12图四人；10图特殊转化；多图额外随机房间事件 |
| Nightmare七怪夜谈 | lqm.zxv(lqm.jrp(ciu.pol)) | zw | 发randomRoomBlockNightmare；pol决定怪物技能 |
| CanotDie孙小美不能死 | 地图24 | GM，AI控制器Hm | 匹配预填孙小美；60秒入场；圣剑/多波/复苏状态机 |
| Compound森林有鬼 | 地图25 | fg继承Uw；AI控制器Jm | 专用随机房间、建造配置、暂停时另派发事件 |

逻辑控制器选择直接证据为1880758附近的sw.lax；fg定义1908454继承Uw，仅ocq调用父类。其他模式AI通常bw。Normal的随机zw分支意味着同一普通模式两局可能有不同怪物逻辑，QA需记录控制器实际class和等级设置。

**已证明的模式UI事件：** 首页Nightmare入口设置mode并打开NightmareMap，监听`NightmareStart`；地图窗口 `.mms()`设置ciu.pol后发事件（2715220）。剧情选图`.fju()`派发GMSetPlotMapIndex，开始`.lax()`发`PlotStart`并传 `[cx.Plot]`（2707171、2710877）。CanotDie入口设置dkw=true/trb=0后stage.event(`CanotDie`,[cx.CanotDie])（758073）。Compound正常UI有18–22时与网络时间检查（743998附近），QA直接启动不能算正常入口条件已回归。

**已证明的Nightmare映射：** lqm.jrp（2399277）与zxv（2399620）把pol0→小红_傲慢→map13；1→宿管阿姨_嫉妒→14；2→绷带男_愤怒→15；3→大头鬼_懒惰→16；4→孙婆婆_贪婪→17；5→阿飘_暴食→18；6→魔术师_爱欲→19。传入范围外pol没有默认返回，QA应覆盖0…6。

**未证明：** 剧情每张地图的所有特殊目标、Compound全地图生成规则、广告/远端解锁奖励仍未全部追完。

## 入场、攻击、门破与淘汰

Im.cwf（417614）普通倒计时30秒，CanotDie60秒，注册StartTimer每1秒调用gye。归零时（396130）设置ciu.haf=true，删除StartTimer、提示怪物入场并发布MainLgTrollUpData。sw.tsu（1881907）设置逻辑时间dgk，注册trollUpData更新，调用控制器hgz随机选择首房门或床，再开始寻路。**QA应推进原时钟与事件；不能只设monster.visible=true把未入场状态伪造成已初始化。**

普通控制器Uw.kjf(target)（873717）是一次真实攻击流程：播放怪物攻击、调用装备效果、以怪物xrz伤害执行target.okc；目标死后查人物床/实体，走xkg淘汰，或继续选择下一目标。Nightmare zw.kjf（2180789）有额外技能与 `xrz*vyx`，不能一律按普通伤害验证。

- 原普通建筑Nd.okc(damage)（566255）：无敌直接true；部分屏障分支返回undefined；否则扣绝对血量jya，hp为比例，归零设qdj=false，更新血条，房间解绑/特效/隐藏/回收，返回是否存活。普通门与床可用该接口验证损伤，床还有自身覆盖与保命buff（1181542）。
- Hw角色.okc(damage)（484519）处理HP、保命及角色死亡标记并返回生存；**不会完成全部房间/结算事件**。
- Uw.xkg(player)（881907）先bgp，再player.okc(500)。死亡后解绑床、BuildSetRoomDie、房间灭灯、床回收、提示淘汰；再按模式决定终局或转化。使用该原流程可核查完整淘汰分支。

门破不等于角色立即淘汰；原怪物会继续攻击床/人物。QA需要覆盖门仍活、门破、床破、角色淘汰各阶段，并检查建筑不可再维修、资源增长停止和灯灭等关联状态。只调用door.okc或只写HP=0不足以证明整条流程。

## 手动维修与维修台

**手动维修已证明：** km构造冷却bgo=20秒（628004）；km.jys（630358）以mba防重入，记录trf=Lx.rvy，发布BuildSkillEvent(roomIndex,0)，CanotDie遍历全部房间发布。UI.pey按原模拟时钟绘制冷却扇形，结束后复位mba。绕过km直接调用房间jdd，不应算冷却回归通过。

Kd.ify(roomIndex,skillId)（1824732）找到Kw房间，Kw.ify(0)（1729181）→Kw.jdd（1689519）。门dwc必须存在且qdj真；否则提示“门已被摧毁”。jdd先立即pbf，随后每1秒注册RepairSkill+iwn。pbf（格式化200036）共调用5次，之后移除注册并清wsj。

每次Kw.wka(hmi,true)（格式化199360）计算 `maxHP*0.1/4`，Kw.ffm（格式化198422）递归4段250ms旋转Tween，**每段完成时**增加门jya，所以每次约1秒恢复10%、5次共50%。Plot地图8另乘 `1+efg.njl`；装备维修能力乘pnt；新手Normal、本地玩家vgb=0且局内<600秒再乘2。最大血量由门setter限制，实际回满后不应越界。

**维修台已证明：** Kw.sdc（格式化197505）需repair已安装，门活且血量非满，Lx.ubs(xsk,1)每秒触发wka(iuc,false)。基础每秒 `maxHP*0.02*rqc`，同样拆4段Tween并乘pnt/相应特殊buff。energyhood组合与装备可能改变rqc/pnt；UI文案“有能量罩+50%”本身不等于本轮所有模式公式已闭环。

暂停边界：原cfi冻结im注册的游戏模拟，但Laya Tween继续。维修已启动后，冻结模拟仍可能完成当前4段回血；不要把该行为误判为模拟时钟未暂停，也不要用暂停中等待真实1秒代替维修台模拟更新。

## 怪物成长、撤退与再攻击

主怪物ag继承xw；xw.cwf（670968）根据模式选zpj攻击数组、qyc血量数组、zni经验数组，初始cnn=1并初始化攻击/当前血量等。**不能把普通数组抄成七模式统一数值**。

xw.rvv setter（678326）把目标值映射为配置wta.xah的经验增量，累计xbn；严格 `xbn > qkc` 才pqv。qkc getter（658452）=`pyq*(1+expRate)`；expRate有等级/模式配置分支（649653）。pqv（696285）重置若干控制系数，再bzo。其他来源包括装备插入+30经验、持续机制+4%阈值；本轮未追全所有触发时刻。

xw.bzo（679565）是真实升级：level++（setter有普通13/Nightmare15和数组长度边界），更新xrz、最大血量ajn、当前血量jya、下一经验pyq、清xbn、播放升级音与Toast，派发TLLevelUpThing。**代码用cnn/level作数组下标的实际表达式必须保留；不可擅自改成推测的level-1。** QA应设置经验阈值边界，再走原经验入口验证，而非直接写level后判为成长通过。

Uw.gjt（885468）在非escape且hp≤ydr时arb。ydr默认0.3/zde默认0.5，初始化又从模式配置读（870059、887946）。arb（893954）检查当前状态/格子、设置escape、获取原撤退位置guv、寻路，切换move/fly动画。无法寻路时有另一原分支；不能仅看到state=escape就当完成撤退。

到达后Uw.btk（896004）记录nqx、nar=true、fzo=sjx。sjx（873439）每模拟1秒ghr（888480）：Normal用实体addHpSpeed；Plot11为20%最大HP；其他通常10%。实体addHpSpeed getter（646781）基础10%最大HP再加ksz项，等级模式可改比率。回满时清恢复标记，ler/gfo重选目标/重新攻击。hfe（895216）为攻击思考时间：普通level<5是10秒、≥5是20秒，等级配置可改。

Troll的lw覆盖gjt为空判断分支与自己的受击/技能逻辑，**不能用Uw自动逃跑预期验证玩家操控怪物模式**。Nightmare zw、Plot11 Jw、CanotDie GM也有覆盖或独立状态流程，必须按实际对象方法验证。

## 自然成败与结算分支

T_.zrr(result)（2320943）是GMGameOver handler，**缺省false；无参数就是失利，不是未知结果**。null为退出，true为胜利。cbr.fhf防重复；它调用清理时钟、动画池、输入/建筑/人物/怪物等，并把ciu.ggh设为result，仅严格true置sta=true。最后xm.bqi(null==result)：null显示首页，布尔显示结算UI（532800）。原事件触发结算可作为底层契约回归，不能单凭QA直接zrr(true)就声称战斗胜利。

| 模式 | 已证明的自然胜/负触发 | 未证明或应扩测 |
|---|---|---|
| Normal | Uw.okc(damage,attackerRoomIndex)怪物HP归零→GMGameOver(true)；Uw.xkg本地角色死亡→无参数GMGameOver(false) | 每种普通活动/装备怪物、多怪物全部清场、全部奖励数值 |
| Troll | lw.xkg淘汰后J_.bzu()全部生存者gan真→true；lw.okc玩家怪物归零→无参数false | 自动攻击、全部技能输入、角色buff复活交叉组合 |
| Puppet | 本地死亡而尚有生存者→PuppetSelect阵营选择，不立即结算；全部生存者死后按阵营cyj/gan分支结算。Uw.okc杀怪：非puppet阵营→true；puppet阵营→Cx.zrr，仅清怪物实体 | 天使击杀伥鬼的最终闭环、转化后每种胜方/奖励、选择超时全链 |
| Plot | 普通怪物死亡/本地死亡沿Uw分支；map7盟友先死→true，倒计时结束且未满足hif→false；map5/6/10/11死亡额外转化/资源 | 每张剧情的所有隐藏目标/特殊玩法须逐图验证，不能汇总为同一普通局 |
| Nightmare | zw继承Uw的okc/xkg：怪物归零true、本地死亡false；七怪由pol产生技能差异 | 原退出会清进度文案及角色uta重置有对应代码，七种pol获胜后的累计与奖励仍未全追完 |
| CanotDie | ex.xkg杀本地或名字孙小美→false；GM.wkk(over)非stagnation→false；圣剑完成御剑动画→ogn(true)→T_.onf(true)→zrr(true) | 复苏波数/剑每级费用、全部遗产与御剑所需完整资源链 |
| Compound | fg继承Uw，已继承主怪物死亡true、本地死亡false的处理 | 原18–22时网络入口、地图生成/独有AI/特殊建造与多目标行为仍需动态覆盖 |

J_.bzu（2362087）并非“列表长度为0”：遍历sev，任一角色gan假就返回undefined，否则true。`gan`所代表的死亡/阵营状态要沿原角色setter，不应在QA直接清sev伪造胜利。

CanotDie特殊契约：gm.ogn=`gmGameOverCanotDie`绑定T_.onf（2314362）。false只隐藏战斗UI并停止输入；true才调用zrr(true)。圣剑管理Fw.qhl(sword,upgradeRow)（1499844）读取upgradeRow[3]，≥100显示御剑按钮；Fw.bsl(sword)（1504394）拒绝resurgence或sword.over，设stagnation、播放孙小美yw.win()与御剑动画，先ogn(false)；Fw.azh（1491316）动画完成后ogn(true)。**不能把中途界面消失误当失败或完成胜利。** 圣剑自然入口可通过 `game.trv.hln.holySword` 找Fw，并用Kd.bun()获得当前剑（1867306）；直接调用bsl只验证已满足条件后的原点击handler，不证明资源/升级任务已完成。

## 回归证据标准

建议每局记录mode、普通/剧情地图、Nightmare pol、控制器class、名册数量、本地房间、门/床/怪物当前与最大HP、怪物level/EXP阈值、原时钟。按顺序验证：匹配准备→开局→移动入房/上床→收入→建造升级→开门受击→手动维修冷却→维修台→怪物升级→低血撤退寻路→回血→再攻击→门破→淘汰或击杀→胜负UI→返回首页再开局。

允许在QA准备HP/EXP边界条件以减少等待，但必须标为**边界探针**，与未改数值的自然操作录像分开。入口执行成功、无异常、最终布尔与UI各是不同证据；需要确认清理后没有遗留更新、下一局可再次正常启动。7模式入口可分别验证，不代表7模式全部玩法已完成回归；上表未证明项不能在用户文档中写成通过。
