BattleSessionActionExecutionSupport.kt
package io.github.lishangbu.avalon.game.battle.engine.core.session
import io.github.lishangbu.avalon.game.battle.engine.core.runtime.flow.BattleRuntimeSnapshot
import io.github.lishangbu.avalon.game.battle.engine.core.runtime.flow.MoveResolutionResult
/**
* session action 执行辅助组件。
*
* 设计意图:
* - 作为 session action 执行相关 helper 的稳定门面;
* - 对外继续维持一个 Bean/构造入口,避免 Spring 配置和测试装配反复跟着改签名;
* - 具体职责拆给独立的小组件,让代码按“一个执行职责一个文件”继续收口。
*/
class BattleSessionActionExecutionSupport(
private val effectExecutionCoordinator: BattleSessionEffectExecutionCoordinator = BattleSessionEffectExecutionCoordinator(),
private val directDamageApplier: BattleSessionDirectDamageApplier = BattleSessionDirectDamageApplier(),
private val switchActionExecutor: BattleSessionSwitchActionExecutor = BattleSessionSwitchActionExecutor(),
private val runActionExecutor: BattleSessionRunActionExecutor = BattleSessionRunActionExecutor(),
) {
/**
* 执行一个已经具备目标信息的 effect。
*
* @param session 当前 battle session。
* @param effectId 当前执行的 effect 标识。
* @param actorUnitId 行动发起者单位标识。
* @param targetUnitId 调用方提供的目标单位标识。
* @param accuracy 命中值输入。
* @param evasion 回避值输入。
* @param basePower 基础威力输入。
* @param damage 基础伤害输入。
* @param attributes 透传给 battle flow 的扩展属性。
* @return effect 结算完成后的聚合结果。
*/
fun executeResolvedEffect(
session: BattleSession,
effectId: String,
actorUnitId: String,
targetUnitId: String,
accuracy: Int?,
evasion: Int?,
basePower: Int,
damage: Int,
attributes: Map<String, Any?>,
): MoveResolutionResult =
effectExecutionCoordinator.executeResolvedEffect(
session = session,
effectId = effectId,
actorUnitId = actorUnitId,
targetUnitId = targetUnitId,
accuracy = accuracy,
evasion = evasion,
basePower = basePower,
damage = damage,
attributes = attributes,
)
/**
* 将直接伤害 mutation 应用到当前快照。
*
* 设计意图:
* - move resolution 主流程当前只把“最终伤害数字”算出来,还没有把这一步自动接进 mutation interceptor 链;
* - 因此这里在真正扣血前,手动为目标派发一次 `on_damage`;
* - 与 `DamageBattleMutationInterceptor` 不同,这里是单目标直接扣血路径,可以安全支持数值 relay 覆盖。
*/
fun applyDirectDamage(
session: BattleSession,
sourceId: String,
targetId: String,
damage: Int,
): BattleRuntimeSnapshot = directDamageApplier.apply(session, sourceId, targetId, damage)
/**
* 记录一次 move 或 item 的最终结算结果。
*/
fun recordMoveExecution(
session: BattleSession,
moveId: String,
attackerId: String,
targetId: String,
result: MoveResolutionResult,
) {
session.recordLog(
"Executed move $moveId from $attackerId to $targetId. " +
"hit=${result.hitSuccessful}, critical=${result.criticalHit}, " +
"basePower=${result.basePower}, " +
(result.damageRoll?.let { "damageRoll=$it, " } ?: "") +
"damage=${result.damage}.",
)
session.recordEvent(
BattleSessionMoveExecutedPayload(
moveId = moveId,
attackerId = attackerId,
targetId = targetId,
hitSuccessful = result.hitSuccessful,
criticalHit = result.criticalHit,
basePower = result.basePower,
damageRoll = result.damageRoll,
damage = result.damage,
),
)
}
/**
* 执行 switch 动作并更新当前 active 列表。
*/
fun applySwitchAction(
session: BattleSession,
action: BattleSessionSwitchAction,
): BattleRuntimeSnapshot = switchActionExecutor.apply(session, action)
/**
* 执行逃跑动作。
*/
fun applyRunAction(
session: BattleSession,
action: BattleSessionRunAction,
): BattleRuntimeSnapshot = runActionExecutor.apply(session, action)
}