RemoveStatusBattleMutationInterceptor.kt
package io.github.lishangbu.avalon.game.battle.engine.core.runtime.flow
import io.github.lishangbu.avalon.game.battle.engine.core.constant.BattleAttributeKeys
import io.github.lishangbu.avalon.game.battle.engine.core.event.StandardHookNames
import io.github.lishangbu.avalon.game.battle.engine.core.mutation.BattleMutation
import io.github.lishangbu.avalon.game.battle.engine.core.mutation.RemoveStatusMutation
import io.github.lishangbu.avalon.game.battle.engine.core.runtime.support.MutationTargetSelectorResolver
/**
* 主状态移除 mutation 的生命周期拦截器。
*
* 设计意图:
* - 在 `RemoveStatusMutation` 真正落盘前,为目标派发一次 `on_remove_status`;
* - 允许状态本身、能力、道具或其他挂载 effect 拦截这次清除;
* - 保持语义明确:只有目标当前确实存在主状态时,才认为本次移除生命周期成立。
*/
class RemoveStatusBattleMutationInterceptor : BattleMutationInterceptor {
override val order: Int = 25
override fun supports(mutation: BattleMutation): Boolean = mutation is RemoveStatusMutation
override fun intercept(
context: BattleMutationInterceptionContext,
attachedEffectProcessor: BattleAttachedEffectProcessor,
): BattleMutationInterceptionResult {
val mutation =
context.mutation as? RemoveStatusMutation
?: return BattleMutationInterceptionResult(context.snapshot, true, context.mutation)
val targetUnitIds =
MutationTargetSelectorResolver.resolve(
mutation.target,
BattleMutationInterceptorSupport.mutationApplicationContext(context),
)
var currentSnapshot = context.snapshot
var blocked = false
targetUnitIds.forEach { affectedTargetId ->
val affectedUnit = currentSnapshot.units[affectedTargetId] ?: return@forEach
val statusEffectId = affectedUnit.statusState?.effectId ?: return@forEach
val result =
attachedEffectProcessor.process(
snapshot = currentSnapshot,
unitId = affectedTargetId,
hookName = StandardHookNames.ON_REMOVE_STATUS.value,
targetId = affectedTargetId,
sourceId = context.sourceId,
relay = true,
attributes =
buildMap {
put("statusEffectId", statusEffectId)
BattleMutationInterceptorSupport
.resolveTargetRelation(currentSnapshot, context.sourceId, affectedTargetId)
?.let { relation -> put(BattleAttributeKeys.TARGET_RELATION, relation) }
},
)
currentSnapshot = result.snapshot
if (result.cancelled || result.relay == false) {
blocked = true
}
}
return BattleMutationInterceptionResult(
snapshot = currentSnapshot,
allowed = !blocked,
mutation = mutation,
)
}
}