1. 关卡流程系统 (stageFlow.ts)

核心函数

函数 用途
gstsServerCreateStage() 创建关卡:初始化变量 → 清空旧敌人/球 → 生成新元素球 → 生成特殊球
gstsServerWaitForPlayerReady() 轮询等待场景实体 + 玩家角色完全就绪
gstsServerStartStageIntervalTimer() 启动每秒战斗循环(主循环)
gstsServerSettleSuccessStatus() 胜利/失败结算:停止计时器、显示分数、设置结算状态
gstsServerNextStage() 进入下一关:清空→传送→或最终胜利
gstsServerInitializeStageVariables() 初始化关卡变量:从 battleStageConfig 读取配置
gstsServerRestartStage() 重置本关:清空→重新选卡→重新传送
gstsServerCheckDeadlock() 死锁检测:无敌人+无净化+球不足 → true

死锁检测逻辑

// 死锁条件(同时满足):
// 1. enemyCount === 0     —— 场上无敌人
// 2. maxEnemies === 0     —— 本关本来就没有敌人(纯收集关)
// 3. orbsCollected < orbsRequired  —— 球没收集够
// 4. !orbsCollectable     —— 球不可拾取(已变深渊球)
// 5. !hasPurify           —— 玩家没有净化卡牌
// → 卡死!弹窗询问是否重置

重置确认弹窗的两种类型

重置弹窗根据触发方式不同,显示不同的提示信息,通过 showFloatingInteractionPage 信号的 Type 参数区分:

触发方式 Type 值 弹窗内容 实现位置
死锁自动检测 confirmConfig.Type1 “元素球不足且无法继续前进,是否重置本关?” stageFlow.ts 的每秒循环
手动按重置按钮 confirmConfig.Type2 “是否重置本关?” playerMain.ts 的 UI 按钮事件

两种重置最终都调用 gstsServerRestartStage(),执行相同的重置逻辑:清除旧状态→重新选卡→重新传送。


2. 元素系统 (elementSystem.ts)

核心函数

函数 用途
gstsServerGetElementalTypes() 返回 4 种基础元素列表 [冰,火,水,雷]
gstsServerGetSpecialElementalTypes() 返回 4 种特殊元素列表 [风环,岩盾,草色十字,光柱]
gstsServerUpdateElementIcons() 更新 UI 上的主/副元素图标显示
gstsServerElementAttack() 执行元素攻击:调用 f.initiateAttack()
gstsServerGetReactionName() 根据主/副元素组合判定反应名称
gstsServerGetReactionColor() 根据反应类型返回 HEX 颜色
gstsServerApplyBuffEffect() 应用增益效果(风环=加时/岩盾=护盾/草色十字=回血/光柱=全灭)

二段攻击流程

投射物命中
  │
  ├─ 有副元素且副≠主 → 副元素攻击(伤害系数 0,仅附着)
  │
  └─ 10ms 后 → 主元素攻击(伤害系数 1,全额伤害)
       │
       └─ 副元素存在且≠主 → 判定元素反应
            ├─ 反应名称 → 存入 stage.reaction
            └─ 反应颜色 → 存入 stage.reactionColor

元素反应判定表

条件 (主 副 任一为) 另一为 反应 颜色
冰(1) 火(2) 融化 #FF6633  
冰(1) 水(3) 冻结 #99FFFF  
冰(1) 雷(4) 超导 #B065E0  
火(2) 水(3) 蒸发 #FF9933  
火(2) 雷(4) 超载 #FF3366  
水(3) 雷(4) 感电 #CC77FF  

3. 敌人系统 (enemySystem.ts)

核心函数

函数 用途
gstsServerSpawnEnemy() 生成单个敌人 + 设置阵营 + 附加元素反应监控
gstsServerSpawnSlot() 按槽位配置生成单个敌人
gstsServerSpawnEnemyWave() 生成一波敌人:从展平数组读取当前关卡的 slots 配置
gstsServerClearAllEnemies() 清除场上所有敌人(字典管理敌人类型)
gstsServerClearEnemyType() 清除指定类型的全部敌人
gstsServerHandleEnemyKill() 处理敌人击杀:计分 + 设置元素球可拾取
gstsServerCheckFallenEnemies() 防掉落检测:拉回掉落地板下的敌人
gstsServerGetEnemyPosByIdx() 根据索引获取敌人位置
gstsServerGetEnemyRotByIdx() 根据索引获取敌人旋转

预生成波次 vs 动态波次

  • 预生成:基于 battleStageConfig.slots 配置,每关的敌人种类和数量在配置中声明
  • 动态限制enemyCount < maxEnemies 时才允许生成新波次
  • 生成时机:每 10 秒一波 + 深渊球触发额外波次

防掉落系统

每秒检测所有敌人类型的 Y 坐标:

  • Y >= 2.5:正常
  • Y < 2.5:重生拉回 — 在相同 XZ 坐标、Y=3.5 处重新生成,删除旧实体
  • 使用 f.doubleBranch() 代替 if 做条件分支(Genshin-TS 约束)

4. 元素球系统 (orbSystem.ts)

核心函数

函数 用途
gstsServerBuildOrbPool() 构建无放回随机池(dict 方案)
gstsServerCreateOrbAtSafePos() 在安全位置生成指定类型的球
gstsServerCreateOrbAtRandomPos() 生成随机属性的普通元素球
gstsServerCreateSpecialOrbAtRandomPos() 生成特殊元素球(风环/岩盾/草色十字/光柱)
gstsServerSetOrbCollectable() 设置全场元素球的可见/可拾取状态
gstsServerClearAllOrbs() 删除场上所有元素球(含特殊球)
gstsServerRemoveRandomOrb() 随机删除一个元素球
gstsServerSpawnOrbEnemyAttack() 深渊球触发时生成追踪攻击投射物

安全位置预计算

在模块顶层(编译时)计算安全坐标:

网格:     [-10, 10] × [-10, 10],步长 3 → 7×7 = 49 个候选点
排除:     玩家出生点附近 + 3 个敌人槽位附近(半径 3 内)
剩余:     44 个安全位置

无放回随机池(运行时的巧妙设计)

每关开始时:gstsServerBuildOrbPool()
  └─ 填充 dict: {0:true, 1:true, ..., 43:true}

生成一个球时:
  1. 从 dict 取 keys 列表
  2. 用 f.getRandomInteger(0, len-1) 随机抽一个 key
  3. 用该 key 作为位置索引(safeOrbXs[posIdx], safeOrbZs[posIdx])
  4. 从 dict 移除该 key(确保同关内不重复)
  
下一关开始:重新填充 dict(回到 44 个全量位置)

这同时满足三个要求:

  • 无编译时随机:dict 内容在运行时通过 finiteLoop 填充
  • 不重复:抽过的 key 立即移除
  • 顺序随机:每次用 f.getRandomInteger 独立随机选

5. 卡牌/道具系统 (cardSystem.ts)

核心函数

函数 用途
gstsServerCardEffectToElement() 道具序号 → 特殊元素常量映射
gstsServerCardEffectToIcon() 道具序号 → 图标素材 ID 映射
gstsServerSetESkillIcon() 设置 E 技能按钮的图标
gstsServerShowDeckSelector() 显示卡牌选择器

道具映射

道具序号 道具名 对应特殊元素 图标素材 ID
1 生命回复 草(7) 111128
2 护盾 岩(6) 111111
3 增加时间 风(5) 111016
4 敌人全灭 光(8) 111025
5 净化 无(特殊逻辑) 111048

选卡逻辑

  • fixedCard === 0:从 1~5 中随机选 2 张不同的卡
  • fixedCard !== 0:仅显示该固定卡牌
  • 第1关跳过选卡,第3关起开始选卡