BattleBoostContextSupport.kt
package io.github.lishangbu.avalon.game.battle.engine.core.runtime.support
import io.github.lishangbu.avalon.game.battle.engine.core.constant.BattleAttributeKeys
import io.github.lishangbu.avalon.game.battle.engine.core.constant.BattleBoostDirectionValues
/**
* boost / stage 变化上下文的统一 support。
*
* 设计意图:
* - 收口 boost relay、boost attributes 的规范化与构造逻辑;
* - 避免 `BoostBattleMutationInterceptor`、`ClearBoostsBattleMutationInterceptor`、
* `boost_from_relay`、`invert_boost_relay` 各自重复实现一套 Map 解析规则;
* - 让能力变化主链对外暴露的上下文字段保持稳定、可预测。
*/
object BattleBoostContextSupport {
/**
* 把任意运行期对象按 boost map 语义规范化成 `Map<String, Int>`。
*
* 合法输入:
* - `Map<String, Number>`
* - 使用 `atk/attack`、`spe/speed` 等别名的 map
*
* 非法输入返回 `null`,由上层决定是否回退或忽略。
*/
fun normalizeBoostMap(value: Any?): Map<String, Int>? {
val rawMap = value as? Map<*, *> ?: return null
val rawBoosts = linkedMapOf<String, Int>()
rawMap.forEach { (key, entryValue) ->
val statId = key as? String ?: return null
val delta = entryValue as? Number ?: return null
rawBoosts[statId] = delta.toInt()
}
return BattleStatStageSupport.normalizeBoostPayload(rawBoosts)
}
/**
* 构造 `on_boost` 标准 attributes。
*
* 这些字段会同时服务于:
* - 条件判断,如 `negativeBoostChanged`
* - relay 改写,如 `requestedBoosts` / `appliedBoosts`
* - 调试探针与测试断言
*/
fun createOnBoostAttributes(
currentBoosts: Map<String, Int>,
requestedBoosts: Map<String, Int>,
targetRelation: String? = null,
): Map<String, Any?> {
val normalizedCurrentBoosts = BattleStatStageSupport.normalizeStoredBoosts(currentBoosts)
val normalizedRequestedBoosts = BattleStatStageSupport.normalizeBoostPayload(requestedBoosts)
val appliedBoosts =
BattleStatStageSupport.resolveAppliedBoostDeltas(
currentBoosts = normalizedCurrentBoosts,
requestedBoosts = normalizedRequestedBoosts,
)
val positiveBoostChanged = BattleStatStageSupport.hasPositiveBoostChange(appliedBoosts)
val negativeBoostChanged = BattleStatStageSupport.hasNegativeBoostChange(appliedBoosts)
return buildMap {
put(BattleAttributeKeys.BOOSTS, normalizedRequestedBoosts)
put(BattleAttributeKeys.REQUESTED_BOOSTS, normalizedRequestedBoosts)
put(BattleAttributeKeys.CURRENT_BOOSTS, normalizedCurrentBoosts)
put(BattleAttributeKeys.APPLIED_BOOSTS, appliedBoosts)
put(BattleAttributeKeys.BOOST_CHANGED, appliedBoosts.isNotEmpty())
put(BattleAttributeKeys.POSITIVE_BOOST_CHANGED, positiveBoostChanged)
put(BattleAttributeKeys.NEGATIVE_BOOST_CHANGED, negativeBoostChanged)
put(
BattleAttributeKeys.BOOST_DIRECTION,
BattleStatStageSupport.resolveBoostDirection(appliedBoosts),
)
targetRelation?.let { relation ->
put(BattleAttributeKeys.TARGET_RELATION, relation)
}
}
}
/**
* 构造 `on_clear_boosts` 标准 attributes。
*/
fun createOnClearBoostsAttributes(
currentBoosts: Map<String, Int>,
targetRelation: String? = null,
): Map<String, Any?> {
val normalizedCurrentBoosts = BattleStatStageSupport.normalizeStoredBoosts(currentBoosts)
val boostChanged = normalizedCurrentBoosts.isNotEmpty()
return buildMap {
put(BattleAttributeKeys.BOOSTS, normalizedCurrentBoosts)
put(BattleAttributeKeys.CURRENT_BOOSTS, normalizedCurrentBoosts)
put(BattleAttributeKeys.CLEARED_BOOSTS, normalizedCurrentBoosts)
put(BattleAttributeKeys.BOOST_CHANGED, boostChanged)
put(BattleAttributeKeys.BOOST_DIRECTION, BattleBoostDirectionValues.NONE)
targetRelation?.let { relation ->
put(BattleAttributeKeys.TARGET_RELATION, relation)
}
}
}
}