BattleStatAliasResolver.kt
package io.github.lishangbu.avalon.game.battle.engine.core.runtime.support
import io.github.lishangbu.avalon.game.battle.engine.core.constant.BattleStatIds
/**
* battle 能力项别名解析器。
*
* 设计意图:
* - 统一处理 `attack/atk`、`speed/spe` 这类长短写别名;
* - 让伤害、逃跑、条件判断、boost 落盘等路径共享同一套 stat id 解析规则;
* - 为后续继续收口到单一规范命名提供唯一入口,避免各文件继续手写 if/when 分支。
*
* 当前约定:
* - 运行时基础能力值 `stats` 仍允许读取长写和短写;
* - stage / boost 在真正写回时会优先归一到短写,便于与既有 fixture 及规则数据保持一致;
* - 对于未知 stat id,不做额外猜测,按原值透传。
*/
object BattleStatAliasResolver {
/**
* 给出一个 stat id 的“读取优先顺序”。
*
* 说明:
* - 会优先返回调用方传入的原始写法,避免同一份 map 中同时存在长写和短写时出现意外覆盖;
* - 如果该 stat 存在标准别名,则把另一种写法追加到后面作为兜底。
*/
fun aliasesOf(statId: String): List<String> {
val counterpart = counterpartOf(statId) ?: return listOf(statId)
return listOf(statId, counterpart)
}
/**
* 返回一个 stat id 所属别名族。
*
* 适用于“删除旧键后写回规范键”这类需要整族处理的场景。
*/
fun equivalentIds(statId: String): Set<String> = aliasesOf(statId).toSet()
/**
* 从任意 stat map 中读取能力值。
*
* 设计目标不是“把 map 彻底改写”,而是提供一个稳定读取入口,
* 让各调用方不用重复写 `speed ?: spe`、`attack ?: atk` 这类兼容分支。
*/
fun readValue(
values: Map<String, Int>,
statId: String,
): Int? = aliasesOf(statId).firstNotNullOfOrNull(values::get)
/**
* 把任意 boost/stat id 归一成 stage map 的标准短写键。
*
* 例如:
* - `attack` -> `atk`
* - `special-defense` -> `spd`
* - 未知键保持原样
*/
fun canonicalBoostId(statId: String): String =
when (statId) {
BattleStatIds.ATTACK,
BattleStatIds.ATTACK_SHORT,
-> BattleStatIds.ATTACK_SHORT
BattleStatIds.DEFENSE,
BattleStatIds.DEFENSE_SHORT,
-> BattleStatIds.DEFENSE_SHORT
BattleStatIds.SPECIAL_ATTACK,
BattleStatIds.SPECIAL_ATTACK_SHORT,
-> BattleStatIds.SPECIAL_ATTACK_SHORT
BattleStatIds.SPECIAL_DEFENSE,
BattleStatIds.SPECIAL_DEFENSE_SHORT,
-> BattleStatIds.SPECIAL_DEFENSE_SHORT
BattleStatIds.SPEED,
BattleStatIds.SPEED_SHORT,
-> BattleStatIds.SPEED_SHORT
BattleStatIds.ACCURACY,
BattleStatIds.ACCURACY_SHORT,
-> BattleStatIds.ACCURACY_SHORT
BattleStatIds.EVASION,
BattleStatIds.EVASION_SHORT,
-> BattleStatIds.EVASION_SHORT
else -> statId
}
private fun counterpartOf(statId: String): String? =
when (statId) {
BattleStatIds.ATTACK -> BattleStatIds.ATTACK_SHORT
BattleStatIds.ATTACK_SHORT -> BattleStatIds.ATTACK
BattleStatIds.DEFENSE -> BattleStatIds.DEFENSE_SHORT
BattleStatIds.DEFENSE_SHORT -> BattleStatIds.DEFENSE
BattleStatIds.SPECIAL_ATTACK -> BattleStatIds.SPECIAL_ATTACK_SHORT
BattleStatIds.SPECIAL_ATTACK_SHORT -> BattleStatIds.SPECIAL_ATTACK
BattleStatIds.SPECIAL_DEFENSE -> BattleStatIds.SPECIAL_DEFENSE_SHORT
BattleStatIds.SPECIAL_DEFENSE_SHORT -> BattleStatIds.SPECIAL_DEFENSE
BattleStatIds.SPEED -> BattleStatIds.SPEED_SHORT
BattleStatIds.SPEED_SHORT -> BattleStatIds.SPEED
BattleStatIds.ACCURACY -> BattleStatIds.ACCURACY_SHORT
BattleStatIds.ACCURACY_SHORT -> BattleStatIds.ACCURACY
BattleStatIds.EVASION -> BattleStatIds.EVASION_SHORT
BattleStatIds.EVASION_SHORT -> BattleStatIds.EVASION
else -> null
}
}