import type { EntityId } from 'db://assets/mx/module/ecs'; import { TableNames } from '../../game/ConfigTableData'; import type { BattleBagSession } from '../bag/BattleBagSession'; import { WeaponComposeConfigProvider } from '../bag/WeaponComposeConfigProvider'; import { findEntityIdByGridIndex } from '../runtime/DeployEntityQuery'; import type { ProjectBattleHandle } from '../runtime/BattleRuntime'; import type { BattleBuffSkillDropTarget } from '../view/CocosBagBoardView'; import { getTowerExpHost, needTowerExpForLevel } from './TowerExpHost'; import { getTowerLoadoutService } from './TowerLoadoutService'; /** * 封神榜(functiontype=2)/ 授仙箓(functiontype=7): * 多格组合字武将、普通 type1 单字(含已上场单字塔)可施放;type2 未合成英雄散字不可。 * 攻速符/千里眼等拖到字块类主动 buff 共用 MergeSession.canApplyBattleBuffSkillDrop* 落点校验。 * 对已部署多格合成武将升级时补剩余经验;授仙箓降级时清空累计经验。 */ /** 是否地图多格合成武将(已部署时走补经验) */ export function isBattleBuffLevelUpExpFillMapTarget(bagSession: BattleBagSession, gridIndex: number): boolean { return bagSession.merge.isMultiCellCompositionAt(gridIndex); } /** 地图格 → 已部署塔实体;未部署则 null */ export function resolveBattleBuffLevelUpMapEntity( battle: ProjectBattleHandle, bagSession: BattleBagSession, gridIndex: number, ): EntityId | null { const map = battle.Map; const player = battle.getPlayer(bagSession.ownerPlayerId); if (!map || !player) return null; const entityId = findEntityIdByGridIndex(gridIndex, battle.session, map, player); if (entityId == null || !battle.session.world.isAlive(entityId)) return null; return entityId; } /** 是否应对该落点走「补剩余升级经验」 */ export function shouldBattleBuffLevelUpViaExpFill( battle: ProjectBattleHandle | null, bagSession: BattleBagSession, target: BattleBuffSkillDropTarget, ): boolean { if (target.kind !== 'map' || !battle) return false; if (!isBattleBuffLevelUpExpFillMapTarget(bagSession, target.gridIndex)) return false; return resolveBattleBuffLevelUpMapEntity(battle, bagSession, target.gridIndex) != null; } /** 授仙箓降级:是否须清空已部署多格合成武将经验 */ export function shouldBattleBuffLevelDownClearExp( battle: ProjectBattleHandle, bagSession: BattleBagSession, target: BattleBuffSkillDropTarget, ): boolean { return shouldBattleBuffLevelUpViaExpFill(battle, bagSession, target); } /** 授仙箓降级:清空已部署多格合成武将累计经验 */ export function applyBattleBuffLevelDownClearExp( battle: ProjectBattleHandle, bagSession: BattleBagSession, gridIndex: number, ): void { const entityId = resolveBattleBuffLevelUpMapEntity(battle, bagSession, gridIndex); if (entityId == null) return; getTowerExpHost().clearExp(entityId); } /** 已部署多格合成武将:是否可补剩余升级经验 */ export function canApplyBattleBuffLevelUpViaExpFill( battle: ProjectBattleHandle, bagSession: BattleBagSession, gridIndex: number, levelDelta: number, ): boolean { if (levelDelta <= 0) return false; if (bagSession.merge.canApplyBattleBuffUnitLevelUp(gridIndex, levelDelta) != null) return false; const entityId = resolveBattleBuffLevelUpMapEntity(battle, bagSession, gridIndex); if (entityId == null) return false; const loadout = getTowerLoadoutService().getLoadout(entityId); if (!loadout) return false; const hero = gg.data.table.getTableData(TableNames.Hero, loadout.weapon1Id); if (!hero) return false; const max = WeaponComposeConfigProvider.instance.getMaxWeaponLevel(loadout.weapon1Id); if (loadout.level >= max) return false; return needTowerExpForLevel(hero, loadout.level) > 0; } /** 已部署多格合成武将:补剩余升级经验(可触发正常经验升级) */ export function applyBattleBuffLevelUpViaExpFill( battle: ProjectBattleHandle, bagSession: BattleBagSession, gridIndex: number, ): boolean { const entityId = resolveBattleBuffLevelUpMapEntity(battle, bagSession, gridIndex); if (entityId == null) return false; return getTowerExpHost().grantRemainingExpForNextLevel(battle, entityId); } /** * 授仙箓:掷骰并写盘;已部署合成武将若掷到升级则补剩余经验。 * @param rollWan 0~9999 */ export function applyBattleBuffRandomLevelWithExpFill( battle: ProjectBattleHandle, bagSession: BattleBagSession, target: BattleBuffSkillDropTarget, levelUpProbsWan: readonly number[], rollWan: number, ): number | null { const merge = bagSession.merge; if (target.kind === 'map') { const rolled = merge.rollBattleBuffRandomLevelMap(target.gridIndex, levelUpProbsWan, rollWan); if (typeof rolled !== 'number') return null; if (rolled > 0 && shouldBattleBuffLevelUpViaExpFill(battle, bagSession, target)) { if (canApplyBattleBuffLevelUpViaExpFill(battle, bagSession, target.gridIndex, rolled)) { return applyBattleBuffLevelUpViaExpFill(battle, bagSession, target.gridIndex) ? rolled : null; } } const result = merge.applyBattleBuffRandomLevelMapDelta(target.gridIndex, rolled); if (typeof result === 'number' && result < 0 && shouldBattleBuffLevelDownClearExp(battle, bagSession, target)) { applyBattleBuffLevelDownClearExp(battle, bagSession, target.gridIndex); } return typeof result === 'number' ? result : null; } const rolled = merge.rollBattleBuffRandomLevelBag(target.slotIndex, levelUpProbsWan, rollWan); if (typeof rolled !== 'number') return null; const result = merge.applyBattleBuffRandomLevelBagDelta(target.slotIndex, rolled); return typeof result === 'number' ? result : null; }