修复AI使用道具卡的一些bug

master
humingxing 6 hours ago
parent 70d37eea4d
commit 4fb30e60bb
  1. 45
      assets/mx/module/merge/core/MergeSession.ts
  2. 18
      assets/script/battle/ai/runtime/AiHeadlessBagHost.ts
  3. 12
      assets/script/battle/ai/runtime/AiMapTextHost.ts
  4. 14
      assets/script/battle/combat/TowerQueryService.ts
  5. 46
      assets/script/battle/view/CocosBagBoardView.ts
  6. 43
      assets/script/battle/view/TextGrid.ts
  7. 13
      assets/script/ui/BattleGame/UIBattleGame.ts

@ -151,9 +151,13 @@ export class MergeSession {
const w2 = Math.floor(Number(weapon2Id) || 0); const w2 = Math.floor(Number(weapon2Id) || 0);
const lv = Math.max(1, Math.floor(Number(level) || 0)); const lv = Math.max(1, Math.floor(Number(level) || 0));
if (w2 <= 0) return PlaceRejectReason.InvalidMerge; if (w2 <= 0) return PlaceRejectReason.InvalidMerge;
this.map.placeTile(gridIndex, { ...tile, weapon2Id: w2, level: lv });
this._recompose();
const heroId = this._resolveElementHeroId(w2, lv) ?? 0; const heroId = this._resolveElementHeroId(w2, lv) ?? 0;
if (!(heroId > 0)) {
console.warn('[MergeSession] applyBattleCardToMapTile 无 Hero', w2, lv);
return PlaceRejectReason.InvalidMerge;
}
this.map.placeTile(gridIndex, { ...tile, weapon2Id: w2, level: lv, weapon1Id: heroId });
this._recompose();
this.emit(MergeEventFactory.mapUpgraded(gridIndex, heroId, lv)); this.emit(MergeEventFactory.mapUpgraded(gridIndex, heroId, lv));
return null; return null;
} }
@ -171,8 +175,12 @@ export class MergeSession {
const w2 = Math.floor(Number(weapon2Id) || 0); const w2 = Math.floor(Number(weapon2Id) || 0);
const lv = Math.max(1, Math.floor(Number(level) || 0)); const lv = Math.max(1, Math.floor(Number(level) || 0));
if (w2 <= 0) return PlaceRejectReason.InvalidMerge; if (w2 <= 0) return PlaceRejectReason.InvalidMerge;
this.bag.setSlot(slotIndex, { ...dst, weapon2Id: w2, level: lv });
const heroId = this._resolveElementHeroId(w2, lv) ?? 0; const heroId = this._resolveElementHeroId(w2, lv) ?? 0;
if (!(heroId > 0)) {
console.warn('[MergeSession] applyBattleCardToBagSlot 无 Hero', w2, lv);
return PlaceRejectReason.InvalidMerge;
}
this.bag.setSlot(slotIndex, { ...dst, weapon2Id: w2, level: lv, weapon1Id: heroId });
this.emit(MergeEventFactory.bagMerged(slotIndex, heroId, lv)); this.emit(MergeEventFactory.bagMerged(slotIndex, heroId, lv));
return null; return null;
} }
@ -397,9 +405,13 @@ export class MergeSession {
const max = this._config.getElementMaxLevel(srcType); const max = this._config.getElementMaxLevel(srcType);
if (srcLevel >= max) return PlaceRejectReason.MaxLevel; if (srcLevel >= max) return PlaceRejectReason.MaxLevel;
const newLevel = srcLevel + 1; const newLevel = srcLevel + 1;
clearSource();
this.bag.setSlot(toSlot, { ...target, level: newLevel });
const heroId = this._config.getElementHeroId(srcType, newLevel) ?? 0; const heroId = this._config.getElementHeroId(srcType, newLevel) ?? 0;
if (!(heroId > 0)) {
console.warn('[MergeSession] 背包五行合成无 Hero', srcType, newLevel);
return PlaceRejectReason.InvalidMerge;
}
clearSource();
this.bag.setSlot(toSlot, { ...target, level: newLevel, weapon1Id: heroId });
this.emit(MergeEventFactory.bagMerged(toSlot, heroId, newLevel)); this.emit(MergeEventFactory.bagMerged(toSlot, heroId, newLevel));
return null; return null;
} }
@ -628,14 +640,22 @@ export class MergeSession {
return null; return null;
} }
/** 组合内所有字块设为同一等级,并同步绑定快照等级 */ /** 组合内所有字块设为同一等级,并同步 Hero.id / 绑定快照 */
private _applyLevelToCompositionTiles(compose: ComposedUnit, level: number): void { private _applyLevelToCompositionTiles(compose: ComposedUnit, level: number): void {
const w1 = Math.floor(Number(compose.weapon1Id) || 0);
for (const idx of compose.gridIndices) { for (const idx of compose.gridIndices) {
const tile = this.map.getTile(idx); const tile = this.map.getTile(idx);
if (!tile) continue; if (!tile) continue;
if ((tile.level ?? 1) === level && tile.heroBind?.level === level) continue; const sameLv = (tile.level ?? 1) === level && tile.heroBind?.level === level;
const sameW1 = (tile.weapon1Id ?? 0) === w1;
if (sameLv && sameW1) continue;
const rec: MapTileRecord = { ...tile, level }; const rec: MapTileRecord = { ...tile, level };
if (tile.heroBind) rec.heroBind = { ...this._cloneHeroBind(tile.heroBind), level }; if (w1 > 0) rec.weapon1Id = w1;
if (tile.heroBind) {
const bind = { ...this._cloneHeroBind(tile.heroBind), level };
if (w1 > 0) bind.weapon1Id = w1;
rec.heroBind = bind;
}
this.map.placeTile(idx, rec); this.map.placeTile(idx, rec);
} }
} }
@ -1008,10 +1028,15 @@ export class MergeSession {
const max = this._config.getElementMaxLevel(srcType); const max = this._config.getElementMaxLevel(srcType);
if (srcLevel >= max) return PlaceRejectReason.MaxLevel; if (srcLevel >= max) return PlaceRejectReason.MaxLevel;
const newLevel = srcLevel + 1; const newLevel = srcLevel + 1;
const heroId = this._config.getElementHeroId(srcType, newLevel) ?? 0;
if (!(heroId > 0)) {
console.warn('[MergeSession] 五行合成无 Hero', srcType, newLevel);
return PlaceRejectReason.InvalidMerge;
}
clearSource(); clearSource();
this.map.placeTile(toGrid, { ...target, level: newLevel }); this.map.placeTile(toGrid, { ...target, level: newLevel, weapon1Id: heroId });
this._recompose(); this._recompose();
this.emit(MergeEventFactory.mapUpgraded(toGrid, target.weapon1Id ?? 0, newLevel)); this.emit(MergeEventFactory.mapUpgraded(toGrid, heroId, newLevel));
return null; return null;
} }

@ -7,6 +7,7 @@ import type { MapManager } from '../../map/legacy/MapManager';
import type { AiMatchProfile } from '../match/AiMatchProfile'; import type { AiMatchProfile } from '../match/AiMatchProfile';
import { AI_PLACE_CAMP, AI_PLAYER_ID, AI_VIEW_LOCAL_CAMP } from './AiCampArea'; import { AI_PLACE_CAMP, AI_PLAYER_ID, AI_VIEW_LOCAL_CAMP } from './AiCampArea';
import { WeaponComposeConfigProvider } from '../../bag/WeaponComposeConfigProvider'; import { WeaponComposeConfigProvider } from '../../bag/WeaponComposeConfigProvider';
import { isBagToolTextType, isShovelTextType } from 'db://assets/mx/module/merge';
import { textDisplayName } from '../../config/BattleHeroTable'; import { textDisplayName } from '../../config/BattleHeroTable';
import { TextListCellState, TextListLandHost } from '../../view/TextListLandHost'; import { TextListCellState, TextListLandHost } from '../../view/TextListLandHost';
import { TableNames } from '../../../game/ConfigTableData'; import { TableNames } from '../../../game/ConfigTableData';
@ -121,11 +122,24 @@ export class AiHeadlessBagHost {
const slots = bag.getBagSlots(); const slots = bag.getBagSlots();
let best = -1; let best = -1;
let bestLv = 1e9; let bestLv = 1e9;
let bestIsTool = false;
for (let i = 0; i < slots.length; i++) { for (let i = 0; i < slots.length; i++) {
const slot = slots[i]; const slot = slots[i];
if (!slot || !(slot.weapon2Id > 0)) continue; if (!slot || !(slot.weapon2Id > 0)) continue;
if (this._land.stateOf(i) !== TextListCellState.Open) continue; if (this._land.stateOf(i) !== TextListCellState.Open) continue;
const lv = Math.floor(Number(slot.level) || 0); const w2Type = Math.floor(WeaponComposeConfigProvider.instance.getWeapon2Type(slot.weapon2Id));
const isTool = isBagToolTextType(w2Type) || isShovelTextType(w2Type) || Math.floor(Number(slot.battleCardKind) || 0) > 0;
const lv = Math.max(0, Math.floor(Number(slot.level) || 0));
// 功能符 level=0:优先丢掉,避免卡死开启格
if (isTool) {
if (!bestIsTool || i < best || best < 0) {
bestIsTool = true;
bestLv = lv;
best = i;
}
continue;
}
if (bestIsTool) continue;
if (!(lv > 0)) continue; if (!(lv > 0)) continue;
if (lv < bestLv || (lv === bestLv && i < best)) { if (lv < bestLv || (lv === bestLv && i < best)) {
bestLv = lv; bestLv = lv;
@ -134,7 +148,7 @@ export class AiHeadlessBagHost {
} }
if (best < 0) return false; if (best < 0) return false;
if (!bag.discardBagSlot(best)) return false; if (!bag.discardBagSlot(best)) return false;
aiOp(`卡死丢弃 bag[${best}] Lv${bestLv} 腾召唤位`); aiOp(`卡死丢弃 bag[${best}] Lv${bestLv}${bestIsTool ? ' 工具' : ''} 腾召唤位`);
return true; return true;
} }

@ -1,5 +1,5 @@
import { Director, director, Tween, tween, v3, Vec3, type Node } from 'cc'; import { Director, director, Tween, tween, v3, Vec3, type Node } from 'cc';
import { canDragMapTile, Weapon2TileType, isElementGlyphType, type ComposedUnit, type DragSource, type DropTarget, type MapTileRecord } from 'db://assets/mx/module/merge'; import { canDragMapTile, Weapon2TileType, isBagToolTextType, isElementGlyphType, type ComposedUnit, type DragSource, type DropTarget, type MapTileRecord } from 'db://assets/mx/module/merge';
import { aiLog, aiWarn } from './AiLog'; import { aiLog, aiWarn } from './AiLog';
import type { BattleBagSession } from '../../bag/BattleBagSession'; import type { BattleBagSession } from '../../bag/BattleBagSession';
import type { MapManager } from '../../map/legacy/MapManager'; import type { MapManager } from '../../map/legacy/MapManager';
@ -157,6 +157,16 @@ export class AiMapTextHost {
return false; return false;
} }
if (source.kind === 'bag' && target.kind === 'bag') return false; if (source.kind === 'bag' && target.kind === 'bag') return false;
// 功能符/产卡:瞬移生效,避免飞向已占格(含对方)时误藏目标格 HeroActor
if (source.kind === 'bag') {
const slot = bag.merge.bag.getSlot(source.slotIndex);
const cardKind = Math.floor(Number(slot?.battleCardKind) || 0);
if (cardKind > 0) return false;
if (slot && slot.weapon2Id > 0) {
const w2Type = Math.floor(WeaponComposeConfigProvider.instance.getWeapon2Type(slot.weapon2Id));
if (isBagToolTextType(w2Type)) return false;
}
}
const bagOrigin = this._resolveBagOriginWorld(); const bagOrigin = this._resolveBagOriginWorld();
if (!bagOrigin) { if (!bagOrigin) {

@ -388,15 +388,19 @@ export class TowerQueryService {
composition: ComposedUnit | null, composition: ComposedUnit | null,
tileType: Weapon2TileType, tileType: Weapon2TileType,
): number { ): number {
if (record.weapon1Id != null && record.weapon1Id > 0) return record.weapon1Id;
if (composition) return composition.weapon1Id;
if (record.weapon2Id <= 0) return 0;
const provider = WeaponComposeConfigProvider.instance; const provider = WeaponComposeConfigProvider.instance;
// 五行数字:按 type + 显示等级解析 Hero // 五行:以 type+显示等级为准,避免升/降级后 tile.weapon1Id 陈旧盖住 composition
if (isElementGlyphType(Number(tileType))) { if (isElementGlyphType(Number(tileType))) {
const level = Math.max(1, Math.floor(Number(record.level) || 1)); const level = Math.max(1, Math.floor(Number(record.level) || 1));
return provider.getElementHeroId(Number(tileType), level) ?? 0; const fromLevel = provider.getElementHeroId(Number(tileType), level) ?? 0;
if (fromLevel > 0) return fromLevel;
if (composition && composition.weapon1Id > 0) return composition.weapon1Id;
if (record.weapon1Id != null && record.weapon1Id > 0) return record.weapon1Id;
return 0;
} }
if (record.weapon1Id != null && record.weapon1Id > 0) return record.weapon1Id;
if (composition) return composition.weapon1Id;
if (record.weapon2Id <= 0) return 0;
// 蟠桃等非五行工具字:单 id 解析 // 蟠桃等非五行工具字:单 id 解析
return provider.getWeapon1ByGroupSequence([record.weapon2Id]) ?? 0; return provider.getWeapon1ByGroupSequence([record.weapon2Id]) ?? 0;
} }

@ -940,9 +940,10 @@ export class CocosBagBoardView {
if (this._bagSession?.merge.map.hasTile(mapGrid)) { if (this._bagSession?.merge.map.hasTile(mapGrid)) {
const tile = this._bagSession.merge.map.getTile(mapGrid); const tile = this._bagSession.merge.map.getTile(mapGrid);
const level = tile?.level ?? 1; const level = tile?.level ?? 1;
const w1 = Number(tile?.weapon1Id) || 0;
const grid = this._mapGrids.get(mapGrid); const grid = this._mapGrids.get(mapGrid);
if (grid?.isValid) { if (grid?.isValid) {
grid.applyMapLevel(level); grid.applyMapLevel(level, w1);
grid.enableDrag(this._canDrag()); grid.enableDrag(this._canDrag());
this._bindDrag(grid); this._bindDrag(grid);
} }
@ -964,7 +965,7 @@ export class CocosBagBoardView {
const record = this._bagSession.getBagSlots()[bagSlot]; const record = this._bagSession.getBagSlots()[bagSlot];
if (grid?.isValid && record) { if (grid?.isValid && record) {
this._grids.setBagGrid(bagSlot, grid); this._grids.setBagGrid(bagSlot, grid);
grid.applyMapLevel(record.level ?? 1); grid.applyMapLevel(record.level ?? 1, Number(record.weapon1Id) || 0);
} }
this._sanitizeBagSlotAfterMerge(bagSlot); this._sanitizeBagSlotAfterMerge(bagSlot);
this._playBagUpgradeEffect(bagSlot); this._playBagUpgradeEffect(bagSlot);
@ -4593,7 +4594,7 @@ export class CocosBagBoardView {
this._deferredBagUpgradeSlot = event.slotIndex; this._deferredBagUpgradeSlot = event.slotIndex;
break; break;
} }
if (this._applyBagUpgradeInPlace(event.slotIndex, event.level)) { if (this._applyBagUpgradeInPlace(event.slotIndex, event.level, event.weapon1Id)) {
this._sanitizeBagSlotAfterMerge(event.slotIndex); this._sanitizeBagSlotAfterMerge(event.slotIndex);
if (!this._suppressDefaultUpgradeFx) { if (!this._suppressDefaultUpgradeFx) {
this._playBagUpgradeEffect(event.slotIndex); this._playBagUpgradeEffect(event.slotIndex);
@ -4614,7 +4615,7 @@ export class CocosBagBoardView {
} }
const prevMapLv = Math.floor(Number(this._grids.getMapGrid(event.gridIndex)?.level) || 0); const prevMapLv = Math.floor(Number(this._grids.getMapGrid(event.gridIndex)?.level) || 0);
const mapLevelDown = event.level < prevMapLv; const mapLevelDown = event.level < prevMapLv;
if (this._applyMapUpgradeInPlace(event.gridIndex, event.level)) { if (this._applyMapUpgradeInPlace(event.gridIndex, event.level, event.weapon1Id)) {
this._refreshHeroLevelAtGrid(event.gridIndex, event.level); this._refreshHeroLevelAtGrid(event.gridIndex, event.level);
if (this._deploySync && this._map.gridsInitialized) { if (this._deploySync && this._map.gridsInitialized) {
this._deploySync.reconcileFromMerge('mapUpgraded'); this._deploySync.reconcileFromMerge('mapUpgraded');
@ -5471,9 +5472,12 @@ const w2Type = WeaponComposeConfigProvider.instance.getWeapon2Type(weapon2Id) as
/** /**
* 地图字块仅等级变化:原地刷新 TextGrid,避免全量 rebuild 叠字。 * 地图字块仅等级变化:原地刷新 TextGrid,避免全量 rebuild 叠字。
* @param gridIndex 地图格
* @param newLevel 新等级
* @param weapon1Id 新 Hero.id(0 表示仅改等级)
* @returns 是否已在原节点上更新成功 * @returns 是否已在原节点上更新成功
*/ */
private _applyMapUpgradeInPlace(gridIndex: number, newLevel: number): boolean { private _applyMapUpgradeInPlace(gridIndex: number, newLevel: number, weapon1Id = 0): boolean {
if (!this._bagSession || !this._map) return false; if (!this._bagSession || !this._map) return false;
if (!this._bagSession.merge.map.hasTile(gridIndex)) return false; if (!this._bagSession.merge.map.hasTile(gridIndex)) return false;
@ -5483,13 +5487,14 @@ const w2Type = WeaponComposeConfigProvider.instance.getWeapon2Type(weapon2Id) as
const indices = composition?.gridIndices.length const indices = composition?.gridIndices.length
? composition.gridIndices.slice() ? composition.gridIndices.slice()
: [gridIndex]; : [gridIndex];
const w1 = Math.floor(Number(weapon1Id) || 0) || (composition?.weapon1Id ?? 0);
let applied = 0; let applied = 0;
for (let i = 0; i < indices.length; i++) { for (let i = 0; i < indices.length; i++) {
const idx = indices[i]; const idx = indices[i];
const grid = this._resolveMapTextGridForUpgrade(idx); const grid = this._resolveMapTextGridForUpgrade(idx);
if (!grid?.isValid) continue; if (!grid?.isValid) continue;
grid.applyMapLevel(newLevel); grid.applyMapLevel(newLevel, w1);
this._grids.setMapGrid(idx, grid); this._grids.setMapGrid(idx, grid);
applied++; applied++;
} }
@ -5497,8 +5502,13 @@ const w2Type = WeaponComposeConfigProvider.instance.getWeapon2Type(weapon2Id) as
return applied > 0; return applied > 0;
} }
/** 背包字块仅等级变化:原地刷新 TextGrid */ /**
private _applyBagUpgradeInPlace(slotIndex: number, newLevel: number): boolean { * 背包字块仅等级变化:原地刷新 TextGrid。
* @param slotIndex 槽
* @param newLevel 新等级
* @param weapon1Id 新 Hero.id
*/
private _applyBagUpgradeInPlace(slotIndex: number, newLevel: number, weapon1Id = 0): boolean {
if (!this._bagSession || !this._bagList) return false; if (!this._bagSession || !this._bagList) return false;
if (!this._bagSession.getBagSlots()[slotIndex]) return false; if (!this._bagSession.getBagSlots()[slotIndex]) return false;
const slotNode = this._bagSlotNodeAt(slotIndex); const slotNode = this._bagSlotNodeAt(slotIndex);
@ -5506,7 +5516,9 @@ const w2Type = WeaponComposeConfigProvider.instance.getWeapon2Type(weapon2Id) as
const grid = this._resolveBagTextGridForUpgrade(slotIndex, slotNode); const grid = this._resolveBagTextGridForUpgrade(slotIndex, slotNode);
if (!grid?.isValid) return false; if (!grid?.isValid) return false;
grid.applyMapLevel(newLevel); const slot = this._bagSession.getBagSlots()[slotIndex];
const w1 = Math.floor(Number(weapon1Id) || 0) || (Number(slot?.weapon1Id) || 0);
grid.applyMapLevel(newLevel, w1);
this._grids.setBagGrid(slotIndex, grid); this._grids.setBagGrid(slotIndex, grid);
return true; return true;
} }
@ -6912,12 +6924,13 @@ const w2Type = WeaponComposeConfigProvider.instance.getWeapon2Type(weapon2Id) as
return loc?.kind === 'map' && this._isEnemyPlaceCampCell(loc.gridIndex); return loc?.kind === 'map' && this._isEnemyPlaceCampCell(loc.gridIndex);
} }
/** 字块完整快照(敌方格补 ECS runtime) */ /** 字块完整快照(敌方格补 ECS runtime);无实体时 null */
private _resolveTextGridData(grid: TextGrid): TextGridData { private _resolveTextGridData(grid: TextGrid): TextGridData | null {
const deploySync = this._isEnemyTextGrid(grid) const deploySync = this._isEnemyTextGrid(grid)
? AiBattleBridge.inst.aiDeploySync ? AiBattleBridge.inst.aiDeploySync
: this._deploySync; : this._deploySync;
const data = grid.getData(deploySync); const data = grid.getData(deploySync);
if (!data) return null;
if (!this._isEnemyTextGrid(grid)) return data; if (!this._isEnemyTextGrid(grid)) return data;
const loc = grid.location; const loc = grid.location;
if (loc?.kind !== 'map') return data; if (loc?.kind !== 'map') return data;
@ -6981,7 +6994,7 @@ const w2Type = WeaponComposeConfigProvider.instance.getWeapon2Type(weapon2Id) as
/** 字块占格合成体(含敌方) */ /** 字块占格合成体(含敌方) */
private _resolveGridComposition(grid: TextGrid, gridIndex: number): ComposedUnit | null { private _resolveGridComposition(grid: TextGrid, gridIndex: number): ComposedUnit | null {
const fromEntity = this._resolveTextGridData(grid).composition; const fromEntity = this._resolveTextGridData(grid)?.composition;
if (fromEntity) return fromEntity; if (fromEntity) return fromEntity;
if (this._isEnemyPlaceCampCell(gridIndex)) { if (this._isEnemyPlaceCampCell(gridIndex)) {
const enemyPlayer = this._battle?.getPlayer(this._resolveEnemyPlayerId()); const enemyPlayer = this._battle?.getPlayer(this._resolveEnemyPlayerId());
@ -7004,6 +7017,11 @@ const w2Type = WeaponComposeConfigProvider.instance.getWeapon2Type(weapon2Id) as
this._textInteractDedupKey = dedupKey; this._textInteractDedupKey = dedupKey;
const data = this._resolveTextGridData(grid); const data = this._resolveTextGridData(grid);
if (!data) {
console.warn('[BagBoard] 字块交互无快照', target.kind, target.index, grid.weapon2Id);
this._clearTextSelect();
return;
}
const isPeachTree = grid.isPeachTreeTile(); const isPeachTree = grid.isPeachTreeTile();
const isBagItem = this._isBagItemEntity(data); const isBagItem = this._isBagItemEntity(data);
// 五行数字与旧 Single=1 编号重叠,数字格子一律 Hero,勿再开 Desc1 // 五行数字与旧 Single=1 编号重叠,数字格子一律 Hero,勿再开 Desc1
@ -7136,6 +7154,7 @@ const w2Type = WeaponComposeConfigProvider.instance.getWeapon2Type(weapon2Id) as
): Pick<BattleWeaponDescHeroPanelData, 'entity' | 'runtime' | 'weaponId'> | null { ): Pick<BattleWeaponDescHeroPanelData, 'entity' | 'runtime' | 'weaponId'> | null {
if (!grid?.node?.isValid) return null; if (!grid?.node?.isValid) return null;
let data = this._resolveTextGridData(grid); let data = this._resolveTextGridData(grid);
if (!data) return null;
if (target.kind === 'map') { if (target.kind === 'map') {
const comp = this._resolveGridComposition(grid, target.index); const comp = this._resolveGridComposition(grid, target.index);
if (comp) { if (comp) {
@ -7215,6 +7234,7 @@ const w2Type = WeaponComposeConfigProvider.instance.getWeapon2Type(weapon2Id) as
private _gridCanShowWeaponDesc(grid: TextGrid): boolean { private _gridCanShowWeaponDesc(grid: TextGrid): boolean {
const data = this._resolveTextGridData(grid); const data = this._resolveTextGridData(grid);
if (!data) return false;
if (grid.isPeachTreeTile()) return !!data.tile; if (grid.isPeachTreeTile()) return !!data.tile;
if (this._isBagItemEntity(data)) return !!data.tile; if (this._isBagItemEntity(data)) return !!data.tile;
return !!(data.tower && data.weapon1Id > 0); return !!(data.tower && data.weapon1Id > 0);
@ -7249,6 +7269,7 @@ const w2Type = WeaponComposeConfigProvider.instance.getWeapon2Type(weapon2Id) as
/** 字块攻击范围(像素):已部署优先读 runtime */ /** 字块攻击范围(像素):已部署优先读 runtime */
private _resolveGridRangePx(grid: TextGrid): number { private _resolveGridRangePx(grid: TextGrid): number {
const data = this._resolveTextGridData(grid); const data = this._resolveTextGridData(grid);
if (!data) return 0;
const px = data.runtime?.stats.range ?? data.tower?.stats.range ?? 0; const px = data.runtime?.stats.range ?? data.tower?.stats.range ?? 0;
return px > 0 ? px : 0; return px > 0 ? px : 0;
} }
@ -7437,6 +7458,7 @@ const w2Type = WeaponComposeConfigProvider.instance.getWeapon2Type(weapon2Id) as
private _canShowType1Range(grid: TextGrid | null): boolean { private _canShowType1Range(grid: TextGrid | null): boolean {
if (!grid?.node?.isValid) return false; if (!grid?.node?.isValid) return false;
const data = this._resolveTextGridData(grid); const data = this._resolveTextGridData(grid);
if (!data) return false;
if (this._isCampGridText(data)) return false; if (this._isCampGridText(data)) return false;
if (!data.tower && !data.runtime) return false; if (!data.tower && !data.runtime) return false;
const rangePx = this._resolveGridRangePx(grid); const rangePx = this._resolveGridRangePx(grid);

@ -793,11 +793,18 @@ export class TextGrid extends Component {
this.location = loc; this.location = loc;
} }
/** 完整快照:实体走战斗层查询,视图层只补 UI 字段 */ /**
getData(deploySync?: DeploySync | null): TextGridData { * 完整快照:实体走战斗层查询,视图层只补 UI 字段。
* @returns 无实体/location 时 null(点选勿崩)
*/
getData(deploySync?: DeploySync | null): TextGridData | null {
const entity = this._aiMapLite && this._entity const entity = this._aiMapLite && this._entity
? this._entity ? this._entity
: this._queryEntity(); : this._queryEntity();
if (!entity?.location) {
console.warn('[TextGrid] getData 无实体或 location', this.weapon2Id, this.node?.name);
return null;
}
const runtime = entity.location.kind === 'map' && !this._aiMapLite const runtime = entity.location.kind === 'map' && !this._aiMapLite
? TowerQueryService.instance.getRuntimeByGridIndex(entity.location.gridIndex, undefined, deploySync ?? null) ? TowerQueryService.instance.getRuntimeByGridIndex(entity.location.gridIndex, undefined, deploySync ?? null)
: null; : null;
@ -815,9 +822,10 @@ export class TextGrid extends Component {
} }
onClickText(e: EventTouch): void { onClickText(e: EventTouch): void {
const data = this.getData(); if (!this.location && !this._entity?.location) {
const range = data.runtime?.stats.range ?? data.tower?.stats.range; console.warn('[TextGrid] onClick 无 location,忽略', this.weapon2Id);
return;
}
if (this.location?.kind === 'map' || this.location?.kind === 'bag') { if (this.location?.kind === 'map' || this.location?.kind === 'bag') {
if (this._mapClickHandler) { if (this._mapClickHandler) {
e.propagationStopped = true; e.propagationStopped = true;
@ -1078,21 +1086,23 @@ export class TextGrid extends Component {
this.node.removeDragEvent?.(); this.node.removeDragEvent?.();
} }
private _queryEntity(): TileEntitySnapshot { private _queryEntity(): TileEntitySnapshot | null {
const location = this.location ?? this._entity?.location; const location = this.location ?? this._entity?.location;
if (!location) return this._entity!; if (!location) return this._entity;
const composition = this._findComposition() ?? this._entity?.composition ?? null; const composition = this._findComposition() ?? this._entity?.composition ?? null;
const level = composition?.level ?? this.level; const level = composition?.level ?? this.level;
const fromCompose = composition && composition.weapon1Id > 0 ? composition.weapon1Id : 0;
const weapon1Id = fromCompose > 0 ? fromCompose : (this.weapon1Id > 0 ? this.weapon1Id : undefined);
return TowerQueryService.instance.buildTileEntity( return TowerQueryService.instance.buildTileEntity(
location, location,
{ {
weapon2Id: this.weapon2Id, weapon2Id: this.weapon2Id,
weapon1Id: this.weapon1Id > 0 ? this.weapon1Id : undefined, weapon1Id,
level, level,
source: this._entity?.source ?? undefined, source: this._entity?.source ?? undefined,
}, },
{ composition, player: gg.game.localPlayer }, { composition, player: gg.game.localPlayer },
) ?? this._entity!; ) ?? this._entity;
} }
private _findComposition(): ComposedUnit | null { private _findComposition(): ComposedUnit | null {
@ -2405,16 +2415,23 @@ export class TextGrid extends Component {
return this.level; return this.level;
} }
/** 地图字块等级变更后刷新数字皮(免全量 setData) */ /**
applyMapLevel(level: number): void { * 地图字块等级变更后刷新数字皮(免全量 setData)。
* @param level 新显示等级
* @param weapon1Id 新 Hero.id;>0 时同步,避免升/降级后陈旧
*/
applyMapLevel(level: number, weapon1Id = 0): void {
if (!this.isValid) return; if (!this.isValid) return;
const lv = Math.max(1, Math.floor(level) || 1); const lv = Math.max(1, Math.floor(level) || 1);
this.level = lv; this.level = lv;
const w1 = Math.floor(Number(weapon1Id) || 0);
if (w1 > 0) this.weapon1Id = w1;
if (this._entity) { if (this._entity) {
const nextW1 = w1 > 0 ? w1 : (Number(this._entity.weapon1Id) || this.weapon1Id);
const comp = this._entity.composition const comp = this._entity.composition
? { ...this._entity.composition, level: lv } ? { ...this._entity.composition, level: lv, weapon1Id: nextW1 > 0 ? nextW1 : this._entity.composition.weapon1Id }
: null; : null;
this._entity = { ...this._entity, level: lv, composition: comp }; this._entity = { ...this._entity, level: lv, weapon1Id: nextW1, composition: comp };
} }
this._updateLevelLabel(); this._updateLevelLabel();
this._syncSkillActiveState(); this._syncSkillActiveState();

@ -991,16 +991,23 @@ export class UIBattleGame extends Auto_BattleGame {
* @param gridIndex 地图格 * @param gridIndex 地图格
*/ */
private readonly _onPeerMapToolApplied = (peerOwnerPlayerId: number, gridIndex: number): void => { private readonly _onPeerMapToolApplied = (peerOwnerPlayerId: number, gridIndex: number): void => {
if (!(gridIndex >= 0)) {
console.warn('[UIBattleGame] 衰弱符对端格无效', peerOwnerPlayerId, gridIndex);
return;
}
if (peerOwnerPlayerId === AiHeadlessBagHost.AI_PLAYER_ID) { if (peerOwnerPlayerId === AiHeadlessBagHost.AI_PLAYER_ID) {
const bridge = AiBattleBridge.inst; const bridge = AiBattleBridge.inst;
bridge.aiDeploySync?.reconcileFromMerge('bagToolWeaken'); bridge.aiDeploySync?.reconcileFromMerge('bagToolWeaken');
bridge.notifyAiBoardChanged(); bridge.notifyAiBoardChanged();
return; return;
} }
// 本机盘面由 peer.merge 的 MapUpgraded 驱动 CocosBagBoardView // AI 衰弱本机:MapUpgraded 已改视图等级;补 DeploySync,避免 Hero/装载仍绑旧等级
if (!(gridIndex >= 0)) { const battle = this._battle;
console.warn('[UIBattleGame] 衰弱符对端格无效', peerOwnerPlayerId, gridIndex); if (!battle?.deploySync) {
console.warn('[UIBattleGame] 衰弱本机缺 DeploySync', peerOwnerPlayerId, gridIndex);
return;
} }
battle.deploySync.reconcileFromMerge('bagToolWeakenLocal');
}; };
/** /**

Loading…
Cancel
Save