战斗阶段与执行顺序
每个战斗阶段、阶段内部的精确执行顺序,以及什么时候可以合法出牌

阶段列表
GCSApi.Phase 返回当前的 BattlePhase,没有活动战斗时返回 BattlePhase.None
| 阶段 | 发生什么 | 玩家输入 |
|---|---|---|
| None | 没有活动战斗 | 不能出牌 |
| Initialize | 正在构建战斗状态 | 不能出牌 |
| PlayerTurnStart | 护甲衰减、能量补充、抽牌阶段、回合开始的状态/卡牌时机 | 进入 PlayerPhase 前不能出牌 |
| PlayerPhase | 玩家可以打出手牌并结束回合 | 卡牌费用可支付且可打出时允许出牌 |
| PlayerTurnEnd | 弃牌阶段、回合结束状态时机、状态衰减、hook ticking、延迟触发 | 不能出牌 |
| EnemyPhase | 每个存活敌人依次结算回合开始状态、行为、回合结束状态和间隔 | 不能出牌 |
| BattleWon | 战斗胜利,可能提供奖励 | 可能需要选择奖励 |
| BattleLost | 战斗失败 | 不能出牌 |
核心循环在四个阶段之间流转;胜负出口由阶段机制在回合转换和出牌之后评估:
战斗启动流程
GCSApi.StartBattle(encounter) 会委托给 manager 和状态机:
- 创建新的
BattleStateView - 从遭遇战玩家单位构建玩家状态
- 从遭遇战敌人构建敌人状态
- 从 run master deck 或玩家初始卡组构建初始抽牌堆
- 洗抽牌堆
- 优先把 Innate 卡放入开局手牌
- 绑定可选的 GES event bridge
- 抽起始手牌
- 触发(Raise)
OnBattleStarted - 解析敌人意图
- 运行 battle-start 状态行为
- 进入
PlayerTurnStart
如果 encounter 为 null,状态机会记录错误并且不启动战斗
玩家回合开始
在 PlayerTurnStart 中,GCS 会:
- 把战斗标记为玩家所有
- 对玩家应用护甲衰减
- 解析最大能量并设置当前能量
- Tick 安排在
PlayerTurnStart的延迟触发 - 清空
PlayedThisTurn - 运行玩家状态的
OnTurnStart - 运行手牌卡牌的回合开始时机
- 从第二回合起,触发
OnDrawPhase,运行 draw-phase 行为,并抽每回合应抽的牌 - 重置每回合攻击标记
- 触发
OnTurnStarted - 如果玩家有待跳过回合,直接跳到玩家回合结束
- 进入
PlayerPhase
护甲衰减遵循遭遇战的 BattleRules.ArmorDecayRule,默认的 ResetOnTurnStart 在单位每个回合开始时重置护甲,Armor Reset Hook 可以改写重置值;Persist 则让护甲原样跨回合保留
第一回合的起始手牌在战斗启动期间抽取,发生在 PlayerTurnStart 之前,第 1 回合没有单独的抽牌阶段
玩家行动阶段
TryPlayCard 只在 PlayerPhase 中可能成功
以下情况会让一次出牌尝试失败:
- 当前阶段不是
PlayerPhase - 卡牌为 null
- 玩家单位缺失
- 卡牌当前不在手牌中
- 卡牌没有 active card definition
- 玩家付不起有效能量费用
- On-play hook 取消了这次打出
- 卡牌带有
Unplayablekeyword - Card playable hook 取消或返回 false
出牌成功时,GCS 会:
- 消耗能量
- 把卡牌加入
PlayedThisTurn - 解析目标;未提供目标时回退到第一个存活敌人
- 触发
OnCardPlayed - 运行卡牌的 on-play FlowGraph
- 注册卡牌 hooks
- 把卡牌从手牌移到弃牌堆或消耗(exhaust)堆
- 检查待处理的胜负转换
- 如果某个效果请求了结束回合,则结束玩家回合
启用卡牌按钮前先调用 GCSApi.CanPlayCard(card),判断 UI 是否需要让玩家选目标时,把卡牌定义传给 GCSApi.RequiresTarget(GCSApi.GetActiveCard(instance))
玩家回合结束
在 PlayerPhase 中调用 GCSApi.EndPlayerTurn() 后,状态机进入 PlayerTurnEnd:
- 触发
OnDiscardPhase - 运行 discard-phase 状态行为
- 把普通手牌移到弃牌堆,保留带
Retain的卡牌,带Ethereal的卡牌移入消耗堆 - 运行玩家状态的
OnTurnEnd - Tick 每回合状态
- Tick active hooks
- Tick 卡牌费用规则
- Tick 安排在
PlayerTurnEnd的延迟触发 - 触发
OnTurnEnded - 如果有待处理的额外回合,进入
PlayerTurnStart - 否则进入
EnemyPhase
敌人阶段
在 EnemyPhase 中,GCS 会:
- 把战斗标记为不再由玩家所有
- 触发
OnEnemyTurnStarted - 按顺序遍历存活敌人
- 对当前行动的敌人应用护甲衰减
- 运行敌人回合开始状态
- 若未被跳过,结算敌人行为
- 运行敌人回合结束状态
- Tick 每回合状态和 hooks
- 在可见的敌人行动之间等待
- Tick 安排在
EnemyPhaseEnd的延迟触发 - 为下一个玩家回合解析所有敌人意图
- 递增
TurnNumber - 进入
PlayerTurnStart
Demo 表现层可以给敌人加攻击前冲和间隔,但阶段逻辑始终归状态机所有
选择与奖励等待
有些图节点和战斗结果会有意暂停推进
| 等待状态 | API 指示器 | 含义 |
|---|---|---|
| Effect choice | GCSApi.IsWaitingForChoice | 一个 Choice 节点正在等玩家选择或跳过 |
| Battle reward | GCSApi.IsWaitingForReward | 胜利的战斗已提供奖励,正在等 ApplyReward 或 SkipReward |
等待期间,排队的转换不会继续,自定义 UI 应禁用无关控件并显示对应的选择器
战斗结束
战斗胜利时:
- 运行 battle-end 状态行为
- 掷出奖励候选
- 触发
OnBattleRewardOffered - 状态机等待奖励选择或跳过
- 触发
OnBattleRewardSelected或OnBattleRewardSkipped - 触发
OnBattleEnded,Won = true
战斗失败时:
- 运行 battle-end 状态行为
- 触发
OnBattleEnded,Won = false
GCSApi.IsBattleOver 在 BattleWon 或 BattleLost 中为 true
安全的阶段检查
| 任务 | 检查 |
|---|---|
| 显示战斗 HUD | GCSApi.IsBattleActive |
| 启用卡牌按钮 | GCSApi.Phase == BattlePhase.PlayerPhase 且 GCSApi.CanPlayCard(card) |
| 显示结束回合按钮 | GCSApi.Phase == BattlePhase.PlayerPhase |
| 显示选择 UI | GCSApi.IsWaitingForChoice |
| 显示奖励 UI | GCSApi.IsWaitingForReward |
| 显示胜利/失败覆盖层 | GCSApi.IsBattleOver 加 OnBattleEnded payload |
事件只表示某件事已经发生,当前阶段应读取 GCSApi.Phase,这样即使同一操作触发多个事件,UI 仍以状态机的实际阶段为准