BattleSessionSwitchBoostStateSupport.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.support.BattleStoredBoostSupport

/**
 * session 换人过程中的 boosts 清理与 Baton Pass 继承支持组件。
 *
 * 设计意图:
 * - 把“离场清空 boosts”和“入场继承暂存 boosts”从多个 switch executor 中抽离;
 * - 保证普通换人、强制换人、濒死替补三条路径共享同一套能力变化收口规则;
 * - 让 Baton Pass 这类例外规则只在这一层表达,不污染通用 switch 编排主体。
 */
internal object BattleSessionSwitchBoostStateSupport {
    /**
     * 在单位离场时清空其当前 boosts,但保留待继承快照。
     */
    fun clearOutgoingBoosts(
        snapshot: BattleRuntimeSnapshot,
        outgoingUnitId: String,
    ): BattleRuntimeSnapshot {
        val outgoingUnit = snapshot.units[outgoingUnitId] ?: return snapshot
        val normalizedCarry = BattleStoredBoostSupport.normalize(outgoingUnit.sessionState.pendingSwitchBoostCarry)
        val nextOutgoingUnit =
            outgoingUnit.copy(
                boosts = emptyMap(),
                sessionState = outgoingUnit.sessionState.copy(pendingSwitchBoostCarry = normalizedCarry),
            )
        return snapshot.copy(units = snapshot.units + (outgoingUnitId to nextOutgoingUnit))
    }

    /**
     * 在新单位入场前消费上一位离场者的待继承 boosts。
     */
    fun applyIncomingBoostCarry(
        snapshot: BattleRuntimeSnapshot,
        outgoingUnitId: String?,
        incomingUnitId: String,
    ): BattleRuntimeSnapshot {
        val incomingClearedSnapshot = clearIncomingCarry(snapshot, incomingUnitId)
        if (outgoingUnitId == null) {
            return incomingClearedSnapshot
        }
        val outgoingUnit = incomingClearedSnapshot.units[outgoingUnitId] ?: return incomingClearedSnapshot
        val incomingUnit = incomingClearedSnapshot.units[incomingUnitId] ?: return incomingClearedSnapshot
        val pendingCarry = BattleStoredBoostSupport.normalize(outgoingUnit.sessionState.pendingSwitchBoostCarry)
        val nextOutgoingUnit = outgoingUnit.copy(sessionState = outgoingUnit.sessionState.copy(pendingSwitchBoostCarry = emptyMap()))
        if (pendingCarry.isEmpty()) {
            return incomingClearedSnapshot.copy(
                units = incomingClearedSnapshot.units + (outgoingUnitId to nextOutgoingUnit),
            )
        }
        val nextIncomingUnit =
            incomingUnit.copy(
                boosts = pendingCarry,
                sessionState = incomingUnit.sessionState.copy(pendingSwitchBoostCarry = emptyMap()),
            )
        return incomingClearedSnapshot.copy(
            units =
                incomingClearedSnapshot.units +
                    (outgoingUnitId to nextOutgoingUnit) +
                    (incomingUnitId to nextIncomingUnit),
        )
    }

    private fun clearIncomingCarry(
        snapshot: BattleRuntimeSnapshot,
        incomingUnitId: String,
    ): BattleRuntimeSnapshot {
        val incomingUnit = snapshot.units[incomingUnitId] ?: return snapshot
        if (incomingUnit.sessionState.pendingSwitchBoostCarry.isEmpty()) {
            return snapshot
        }
        return snapshot.copy(
            units =
                snapshot.units +
                    (
                        incomingUnitId to
                            incomingUnit.copy(
                                sessionState = incomingUnit.sessionState.copy(pendingSwitchBoostCarry = emptyMap()),
                            )
                    ),
        )
    }
}