# 《躺平发育》规则、像素复刻依据与心理机制

研究日期：2026-10-09。**本文是原包静态研究，不是实机试玩报告。** 微信登录已恢复并已录制首局，首局未成功入房后失败，其后已恢复原窗口并补录失败结算无损 PNG 与 240 秒录像。实机截图、操作与录像事实由 01 试玩报告单独记录；本文仍仅陈述静态源码证据，不把代码分析称作实机测量。以下把「代码已证实」「UI 文案已证实」「推断」「待验证」分开。

## 证据与解码方法

原始主程序是 `artifacts/original/unpacked/js/game.js` 的 `define("js/bundle.js", ...)` 模块，另有启动模块 `js/game.js`。`artifacts/original/unpacked/game.js` 注册 Babel helpers、Laya 运行库、微信适配器、SDK、启动 UI 与 `index.js` 等 38 个 define 模块。

本文引用的行号均为 [静态解码格式化文件](../../artifacts/reverse/bundle.decoded.formatted.js)，不是另写的游戏逻辑。对应原始来源始终是上述 `js/bundle.js`。工具 [decode-fortify.mjs](../../tools/reverse/decode-fortify.mjs) 只解析 AST、反转字符串和进行有限常量替换，不运行原游戏或 SDK：

- 原代码 `Cl` 把字符串逐字符反转，`String.prototype.s` 按固定宽度切片，写入 `Gl[0..48]`。恢复 49 个池、11,326 条字符串。
- `El` 为带偏移的定长 alphabet 进制数字串，解成 `Rl`，共 420 个数值。
- 只替换能由局部作用域全部写入证明一致的常量及精确池访问；动态符号、状态机和条件分支仍保留。共 176,689 次替换。
- 解码后再次 AST 解析确认语法有效。`bundle.decoded.js.evidence.json` 保存源/输出 SHA256、池和每次替换的原始字符位置；`.constants.json` 保存常量来源。不保证解码输出适合作为未经回归的发布版本。

## 游戏闭环与状态

**UI 文案已证实：** 开局红色倒计时要求离开走廊；进入空房间后上床，睡觉赚金币、建造装备；发现床上有人应离开；门遭攻击时可维修；别人房间灯熄灭时被告诫不要查看或拆遗物。原包还故意把蜜獾商店写成不可进入/购买的禁忌。来源：bundle 常量 `Wi`，格式化文件 1236（以搜索「如果出现红色倒计时」定位更可靠）。这些是怪谈式叙事，不能把「不要买道具」直接当作程序禁止购买。

**代码已证实：** 内部事件支持 `GMSelectMap`、`GMStartGame`、`GMGameOver`、`GMPauseGame`、`GMResumeGame`；地图管理器 `T_` 的 `yzk` 注册处理方法分别为 `eux/lax/zrr/cfi/kzg`。来源：事件表 4576–4582；注册 310260–310345。可据此把原生状态分成大厅/地图选择 → 匹配/入场 → 移动找房 → 房间发展/战斗 → 结算，但完整转移守卫仍需动态核对。

**代码已证实：** 玩家伤害方法 `okc(t)` 减少 `HP`，普通分支 `HP<=0` 发出玩家受击/淘汰事件，并有免死/天使例外。淘汰处理清除床、关闭房间灯、显示「玩家：…已被淘汰！」，自己被淘汰会触发 `GMGameOver(false)`。来源：37885–37950、72440–72510、89115–89220。伥鬼、天使、猎梦者模式有不同结算分支；不可把经典模式的判断用于所有模式。

**后续核查更新：** 普通击杀胜利、真实入场倒计时、原攻击伤害、撤退寻路/回血、经验阈值和维修冷却/恢复量已追加源码证明与浏览器原引擎回归，见 [原包玩法契约](05-gameplay-source-contracts.md) 和 [81 项回归证据](06-gameplay-regression.md)。完整原版双端对照与全部特殊装备组合仍待验证。代码存在大量扁平化条件和模式覆盖；未逐项完成路径证明的部分不应写成固定规则。原代码事件 `TrollLogicState`、`MainLgTrollUpData` 已恢复（4626、4597），说明有明确怪物状态/升级消息，但仅这些符号不足以证明数值。

## 资源与升级：原值保留

资源 `gold1` 是局内金币、`gold2` 是局内闪电；**不要与 `Z_.instance.player.gold` 的持久钱包混同**。累计方法 `ciu.eer(roomId,gold,electricity)` 将金币保留一位小数，累加当前值与 `gold1_Count/gold2_Count`。来源：335360–335414（搜索方法 `eer`）。床生产过程 `woq(t)` 的真实金币公式为 `pR × 房间 qoj × 房间 zql × yrn`，基础 `pR` 从配置第 4 列读入，可能被增益修改。来源：189770–189845，`qhl(t,i)` 设置 `t.pR=i[3]`。

原配置每行形状为 `[名字, 金币价格, 闪电价格, 主属性, 射程/第二属性, 前置建筑键]`。金币/闪电成本有直接扣费证据：309378–309440 比较 `gold1>=s[1] && gold2>=s[2]` 后扣除两值；`igw(type,level)` 返回配置的 `level-1` 行（343027–343205）。以下为 `sml` 基础配置（336173–336350）：

| 床等级 | 名称 | 金币 | 闪电 | 基础金币/秒 | 前置 |
|---|---|---:|---:|---:|---|
| 1 | 发霉小床 | 0 | 0 | 1 | — |
| 2 | 湿冷小床 | 25 | 0 | 2 | — |
| 3 | 破旧小床 | 50 | 0 | 4 | door_2 |
| 4 | 简陋的床 | 100 | 0 | 8 | — |
| 5 | 标准床铺 | 200 | 0 | 16 | door_5 |
| 6 | 温暖床铺 | 400 | 0 | 32 | — |
| 7 | 精装床铺 | 800 | 16 | 65 | door_8 |
| 8 | 标准大床 | 1600 | 32 | 128 | door_10 |
| 9 | 豪华大床 | 3200 | 65 | 256 | door_11 |
| 10 | 多功能大床 | 6400 | 128 | 512 | door_12 |

这些产量也有展示文案交叉证据（338915–338931）。**65 是原值，不能「修正」成 64。**

| 门 | 金币 | 闪电 | 配置生命属性 |
|---|---:|---:|---:|
| 铁门1 / 2 / 3 / 4 / 5 | 0 / 16 / 32 / 65 / 128 | 0 | 50 / 80 / 160 / 200 / 250 |
| 钢门1 / 2 / 3 / 4 / 5 | 256 / 512 / 1024 / 2048 / 4096 | 0 / 16 / 32 / 65 / 128 | 320 / 640 / 1280 / 2560 / 5120 |
| 振金门1 / 2 / 3 | 8192 / 16384 / 32768 | 256 / 512 / 1024 | 10240 / 20480 / 40960 |

来源：336289–336304；具体运行时生命可能受模式、装备和增益覆盖。

| 炮台 | 金币 | 闪电 | 攻击 | 射程 | 前置 |
|---|---:|---:|---:|---:|---|
| 笤帚炮台 | 8 | 0 | 4 | 4 | — |
| 铲铲炮台 | 16 | 0 | 8 | 4.5 | — |
| 鱼叉炮台 | 32 | 0 | 16 | 5 | — |
| 喷射水枪 | 65 | 0 | 32 | 5.5 | — |
| 高压水枪 | 256 | 0 | 65 | 6 | game_1 |
| 气泡发射器 | 512 | 0 | 128 | 6.5 | — |
| 魔力气泡机 | 1024 | 32 | 256 | 7 | game_2 |
| 驱魔气泡机 | 2048 | 65 | 512 | 7.5 | — |
| 初级激光器 | 4096 | 128 | 1024 | 8 | game_3 |
| 恶魔激光器 | 8192 | 256 | 2048 | 8.5 | game_4 |
| 圣光生成器 | 16384 | 512 | 4096 | 9 | game_5 |
| 圣光发射器 | 32768 | 1024 | 8192 | 9.5 | game_6 |
| 圣光炮台 | 65536 | 2048 | 16384 | 10 | — |

来源：336228–336246。game_1 等对应「发霉游戏机」起的闪电生产链。基础游戏机金币成本 200/400/800/1600/3200/6400/12800/25600/51200/102400；配置主属性 1/2/4/6/8/10/15/20/25/30（336325–336341）。第一台 UI 写「1闪电/2s」，后面写「闪电/s」（338900–338913），**不能把第一级配置值 1 直接解释为 1/秒**。

**模式覆盖已证实：** `igw` 在 Nightmare 取 `eno`、Troll 取 `ceg`，Normal 且地图 0 且 `ciu.dkw` 为真时也取 `ceg`，Plot、CanotDie、Compound 另有配置（343027–343205）。`ceg` 炮台第 3–6 级金币价格为 40/88/176/440，而基础为 32/65/256/512（336708–336744）。因此复刻必须保留模式/开关选择；单凭一张表不能宣称完全同款。

**代码已证实：** 拆除普通建筑可退回 `floor(金币成本/2)` 与 `floor(闪电成本/2)`，特殊对象有例外，64 特意转成 65。来源：解码未格式化文件字符 1,826,000 附近；证据 JSON 可回溯原串。建筑数量达到上限或无法落位时有返还原成本分支（字符 1,851,000–1,854,000）；这和主动拆除不是同一规则。

## 原生坐标与视觉实现

[Main.json](../../artifacts/original/unpacked/gameAssets/asset/Main.json) Scene 设计尺寸 **640×1136**。bundle 舞台也是 width=640、height=1136、scaleMode=fixedwidth、screenMode=vertical、alignV=top、alignH=left（362049–362060）。首次初始化走 Laya WebGL，载入 `version.json`、`fileconfig.json` 后进入 `bx.instance.init()`（361425–361535）。

[StartGame.json](../../artifacts/original/unpacked/gameAssets/asset/Prefabs/StartGame.json) UI 根宽 640、高 1386，ground 中心 (320,693)，部分背景素材高 1136。UI 使用比设计高更长的背景和中心锚点；不能把 1386 当作所有屏幕的设计高度。

[buildMenu.json](../../artifacts/original/unpacked/gameAssets/asset/Prefabs/buildMenu.json) 建筑浮层宽 540、高 140、pivot=(270,70)，图标 110×110（中心 (68,67)），升级按钮 176×106（中心 (439,65)，pivot=(88,53)）。[menu.json](../../artifacts/original/unpacked/gameAssets/asset/Prefabs/menu.json) 宽 570，升级标题 (283,40)，build 内容 (285,139)、540×360。应原样恢复 pivot、sizeGrid、字体、层级和 skin，CSS 凭感觉绘图无法达到像素匹配。

[MatchingUI.json](../../artifacts/original/unpacked/gameAssets/asset/Prefabs/MatchingUI.json) 根 640×1386；head 面板中心 x320、y206，640×766；bottomBox x320、y984，640×402。[GameOverUI.json](../../artifacts/original/unpacked/gameAssets/asset/Prefabs/GameOverUI.json) 根 640×1386，有 red 和 lp 叠层。动态布局仍需在目标手机比例对照截图确认。

[地图配置](../../artifacts/original/unpacked/gameAssets/asset/data/mapsData.json) map0 为 43 行 ×37 列，其他地图有 30×30、41×41、50×50 等；是不同 tile 编号的矩阵。原包有明确坐标转换事件 `MGMGetMapPosTScenePos`/`MGMGetScenePosTMapPos`/`MGMGetMapPosTDataPos`（4534–4536）。目前未证明 tile 编号全部语义和格子缩放，不能把地图矩阵直接画成每格固定屏幕像素。

[装备配置](../../artifacts/original/unpacked/gameAssets/asset/data/equipmentData.json) 90 行，type=0…4，part 字段区分部位，包含 val/newModeVal/lev。它不是建筑升级表；例如木刀 val 从 .4→.8→1.2→2.4…，铁锤等两种模式值不同。复刻中混用装备与炮台成长表会产生规则偏差。

## AI、单机与联网边界

**代码已证实：** 事件表有 `AIStartGame`、`AIAddGold`、`GetAIRoomIndex`、`CallUpAIHelp`、AI 人数限制及 AI 回收；源码还有 AI 比较其它房间床等级后自动购买升级的路径（309205–309440）。这证明有本地模拟同伴/对手的体系，**不等于每个显示头像都是真人在线匹配**。

**代码已证实：** 平台包装对象初始化 `this.bpu=Laya.Browser.window.wx`（343910），广告路径调用 createRewardedVideoAd、onLoad/onError、用户成功/失败回调（解码字符 2,581,200 附近）。启动读取远程分享配置，另有远程游戏配置、地图/活动/资源 URL（28110、361545）。原配置 [config.json](../../artifacts/original/unpacked/gameAssets/asset/data/config.json) 写 version=3.5.15、gm=false、h5=true；h5 是包内字段，不足以证明这个发布包无需微信。

**待验证：** 是否有实时对战或服务端决定战斗结果。bundle 未检出 connectSocket，但 Laya/SDK 模块本身可能包含网络桥；缺少某个 API 字面不能作为「纯离线」证据。浏览器 demo 可复用本地模拟闭环，并把广告、分享、登录、活动配置等平台功能明确适配；不能假装线上匹配、真正奖励或账号同步成功。

## 为什么可能触动用户心理（推断）

以下为设计推断，来自规则与文案，并非已测用户心理或实机行为统计。

1. **低门槛与持续掌控感。** 上床后被动赚钱，点击一个对象升级便立刻改变视觉与产量；把动作负担降到最低，同时不断给出有意义选择。依据：床产量链、金币浮动动画、建筑成本与升级事件。
2. **安全屋幻想与损失厌恶。** 房间是个人领地，门是可见防线；修门能把「马上失去一切」转为即时挽救。依据：门生命链、玩家淘汰后清床熄灯、怪谈安全指令。
3. **增长与防御的机会成本。** 买床提高后续收入，买门提高即时存活，买炮降低长期威胁。相同金币只能满足其中一项；前置门/游戏机把「只堆经济」限制为多条链的权衡。依据：升级价格、前置键与双资源扣费。
4. **先等待、再反击的情绪弧线。** 文案先制造不得下床的无力感，装备从笤帚到圣光炮台提供力量幻想。依据：规则 Wi 与炮台命名/攻击成长。尚未实测怪物强度曲线，不能称其精确制造某个时间点的爽感。
5. **怪谈的好奇心冲突。** 「千万不要」「无法提供保护」的警告同时暗示商店、遗物、窗户有隐藏内容，玩家可能更想点击。依据：Wi、公告窗户怪人、商店道具路径。文案是悬疑诱因，是否实际转化必须观察。
6. **伪社会情境与比较压力。** 其它房间有头像、床等级、淘汰提示和遗产；即使由 AI 驱动，也能让个人防守有「别人发展比我快/别人死了」的参照。依据：AI 升级比较、淘汰广播、事件表。不可说成真实多人社交事实。
7. **失败后的再次尝试与广告奖励。** 已积累的房间发展带来不舍，奖励视频、免费/视频按钮和日次数上限可能借助这种情绪促使继续。依据：353235–353275 的 freeBtn/videoBtn、广告回调、每日上限文案。必须在实机确认按钮对应复活、抽奖或资源补给；现阶段不把具体变现结果写死。

## 恢复试玩后需要补证的关键帧

大厅与规则页；匹配页；倒计时找房；第一张床与初始资源；床/门/炮台的升级菜单；第一次猎梦者到门与维修前后；破门淘汰/成功结算；广告入口但不主动消费；相同设备比例下原版与 web 的逐帧截图。记录当前模式、地图、计时、金币/闪电、建筑等级、敌人血量与每一步动作；这样才能把本文静态证据变成可验证的像素与规则复刻验收标准。

## 浏览器适配补证：存档与输入桥

### 首页隐藏项是进度门槛

`showBtn`（65446–65515）使用 `player.vgb` 与配置阈值比较；`vgb`（328380）返回 `_win+_lose`。默认阈值 `vhj=yde=sqg=1`（319265–319269）。零局新档隐藏六角色选择框 `select`；零局也隐藏商店 `ces=Shop`、ghostBtn、coupleBtn；shareBtn 同样要一局。节点绑定关系见 66869–66922。因此原账号与全新浏览器账号首页不同可以由进度解释，不应先归因于平台差异。

排行榜另由 `Id.instance(Id).isOpen` 控制，getter 读取 `tw.get('isOpenGameLev')`（解码未格式化字符 297307），默认 false。其数据初始化在跨日登录、老用户达到一定局数等条件下开启（字符 336906–337850）。这只是入口显示条件，实际联网排行榜还要另行适配。

### 自造本地样本，不复制账号

player 构造的旧 key=`PlayerData`，现 key=`PlayerDataItem`（319983 附近，解码字符 2409830）。当前 `duo()` 将整个 `_data` JSON 保存到 Laya.LocalStorage.setItem(rmb,…)；rmb getter 返回 ctg=`PlayerDataItem`。`pdt(t)`（325100 附近，字符 2437236）逐字段合并默认数据，缺失字段保留默认，因此可安全使用小型样本：

```json
{
  "_gold": 206,
  "_fragment": 2,
  "_playerSelectIndex": 3,
  "_playerSkin": [0, 1, 2, 3],
  "_win": 0,
  "_lose": 1
}
```

206/2 是基准 UI 展示值，仅用于自造视觉对照样本，不代表连接了微信钱包或获得奖励。后续视觉核对灰衬衫眼镜角色是第四格索引 3，因此样本应选择 3；`_playerSelectIndex` 是零基索引。原默认 `_playerSkin=[0]`；原类 `skin` 的 `[0,6,2,3,4,5]` 不是安全的解锁存档列表；直接加入 6 会导致部分选择节点为空。当前对照使用已验证样本 `[0,1,2,3]`，不要把这份测试状态称作原账号存档。排行榜存档键另为 `isOpenGameLev`，其底层 `tw` 存储结构与 PlayerDataItem 是不同系统。

### WASD 必须桥接原移动

内部所有者链为 `T_.boc (hw) → hw.nlc (EM) → EM.thy (Vg)`。T_ 在资源加载完成后构造（解码字符 2774250）；它不是可直接从场景注册表找到的 Laya Script 单例。EM 构造摇杆宽/高 242、中心 (121,121)、半径 vwl=79，创建 Vg。

- EM.bfr 处理鼠标位置差。
- EM.sgr 约束摇杆向量到圆盘、归一化，调用 `thy.ixn(x,y)`（字符 2001941–2002460）。
- Vg.ixn 内部有模式、player.state、移动与碰撞条件（字符 1901357 起）；Web 键盘应调用这个方法，保留原寻路/碰撞/上床限制。
- EM.sgr(0,0) 只把摇杆图形居中，**没有调用 ixn 停止**。松手应调用原 EM.uvj()（字符 2002837 起），它清理触摸差值、定时动作和移动状态。
- 最小桥建议在 EM 构造完成后仅暴露一个本地引用，keydown/frame 用归一化 WASD 向量调用 `EM.thy.ixn`，keyup/blur 用 `EM.uvj()`。不能让浏览器代码直接改角色 x/y。

这些仅是静态适配建议，需以实测走廊移动、碰墙、入房上床、暂停和结算后的按键行为确认。
