修复AI方未完善的buff技能效果

master
humingxing 7 days ago
parent 33d324250a
commit 82d1644cbb
  1. 10
      assets/script/battle/ai/decision/AiActionPlanner.ts
  2. 89
      assets/script/battle/ai/decision/AiBoardProbe.ts
  3. 1
      docs/方案-Battlebuff新表实现.md

@ -5,7 +5,7 @@ import { AiBoardProbe } from './AiBoardProbe';
import { aiOp } from '../runtime/AiLog';
/**
* AI 决策:解锁 → 五行合成 → 上阵。
* AI 决策:解锁 → 产卡使用 → 五行合成 → 上阵。
*/
export class AiActionPlanner {
private readonly _probe = new AiBoardProbe();
@ -32,6 +32,12 @@ export class AiActionPlanner {
return this._logAction('解锁地块', { kind: AiActionKind.Place, merge: unlock }, emptyPut, dig);
}
const card = this._probe.findBattleCardAction(ctx.bagSession, ctx.map);
if (card) {
// Place:勿用 Upgrade,避免 onBagMergedAt 误推进待开启地块
return this._logAction('产卡使用', { kind: AiActionKind.Place, merge: card }, emptyPut, dig);
}
const upgrade = this._probe.findUpgradeAction(ctx.bagSession, ctx.map);
if (upgrade) {
return this._logAction('数字合成', { kind: AiActionKind.Upgrade, merge: upgrade }, emptyPut, dig);
@ -70,7 +76,7 @@ export class AiActionPlanner {
const dst = m.target.kind === 'bag' ? `bag[${m.target.slotIndex}]` : `map[${m.target.gridIndex}]`;
detail += ` ${src}->${dst}`;
}
if (label === '解锁地块' || label === '数字合成' || label === '上阵') {
if (label === '解锁地块' || label === '产卡使用' || label === '数字合成' || label === '上阵') {
console.warn('[AI操作]', `决策 ${label} | ${detail} | emptyPut=${emptyPut} dig=${dig}`);
} else {
aiOp(`决策 ${label} | ${detail} | emptyPut=${emptyPut} dig=${dig}`);

@ -1,4 +1,5 @@
import {
BattleBagCardKind,
MapCellKind,
Weapon2TileType,
isElementGlyphType,
@ -188,6 +189,94 @@ export class AiBoardProbe {
return bestMap ? { source: bestMap.source, target: bestMap.target } : null;
}
/**
* 倍率卡/属性卡:拖到己方可拖开启格或地图五行数字(优先场上、高等级)。
* @param session 会话
* @param map 地图
*/
findBattleCardAction(session: BattleBagSession, map: MapManager): { source: DragSource; target: DropTarget } | null {
WeaponComposeConfigProvider.instance.load();
const provider = WeaponComposeConfigProvider.instance;
const slots = session.getBagSlots();
let best: { source: DragSource; target: DropTarget; score: number } | null = null;
for (let s = 0; s < slots.length; s++) {
const card = slots[s];
if (!card) continue;
const kind = Math.floor(Number(card.battleCardKind) || 0);
if (kind !== BattleBagCardKind.Multiplier && kind !== BattleBagCardKind.Attr) continue;
if (!this._canDragBagSlot(session, s)) continue;
for (let t = 0; t < slots.length; t++) {
if (t === s) continue;
const dst = slots[t];
if (!dst || dst.battleCardKind) continue;
const land = session.landStateOf?.(t) ?? TextListCellState.Open;
if (land !== TextListCellState.Open) continue;
if (!this._isBattleCardDigitTarget(provider, dst.weapon2Id, dst.level ?? 1, kind)) continue;
const score = this._scoreBattleCardTarget(provider, dst.weapon2Id, dst.level ?? 1, false, t);
if (!best || score > best.score) {
best = {
source: { kind: 'bag', slotIndex: s },
target: { kind: 'bag', slotIndex: t },
score,
};
}
}
const grids = this._listActiveGrids(map);
for (let g = 0; g < grids.length; g++) {
const mg = grids[g];
const tile = session.merge.map.getTile(mg.Index);
if (!tile || tile.battleCardKind) continue;
if (!session.validator.isAllowedCampForPlace(mg.Index)) continue;
if (!this._isBattleCardDigitTarget(provider, tile.weapon2Id, tile.level ?? 1, kind)) continue;
const score = this._scoreBattleCardTarget(provider, tile.weapon2Id, tile.level ?? 1, true, mg.Index);
if (!best || score > best.score) {
best = {
source: { kind: 'bag', slotIndex: s },
target: { kind: 'map', gridIndex: mg.Index },
score,
};
}
}
}
return best ? { source: best.source, target: best.target } : null;
}
/**
* 产卡目标是否为可生效五行数字。
* @param provider 配表
* @param weapon2Id 目标字
* @param level 显示等级
* @param kind 卡种类
*/
private _isBattleCardDigitTarget(provider: WeaponComposeConfigProvider, weapon2Id: number, level: number, kind: number): boolean {
const w2Type = Math.floor(provider.getWeapon2Type(weapon2Id));
if (!isElementGlyphType(w2Type)) return false;
const lv = Math.max(1, Math.floor(Number(level) || 1));
if (kind === BattleBagCardKind.Multiplier) {
return lv < provider.getElementMaxLevel(w2Type);
}
return true;
}
/**
* 产卡落点评分:场上优先、等级高优先、下标稳定。
* @param provider 配表
* @param weapon2Id 目标字
* @param level 显示等级
* @param onMap 是否地图
* @param index 槽/格下标
*/
private _scoreBattleCardTarget(provider: WeaponComposeConfigProvider, weapon2Id: number, level: number, onMap: boolean, index: number): number {
const lv = Math.max(1, Math.floor(Number(level) || 1));
const w2Type = Math.floor(provider.getWeapon2Type(weapon2Id));
const maxLv = isElementGlyphType(w2Type) ? provider.getElementMaxLevel(w2Type) : lv;
return (onMap ? 100000 : 0) + lv * 1000 + (maxLv - lv) + (1000 - (index % 1000));
}
/**
* 空 Put 格是否可落五行字。
* @param session 会话

@ -36,6 +36,7 @@
| 能量石 | `comm/prefab/power` |
| 金币飞 | `battleGame/prefab/coinFly` |
| 倍率卡/属性卡实体 | `battleHero/prefab/buff/倍率卡`、`属性卡`(内部美术后换) |
| AI 产卡使用 | `AiBoardProbe.findBattleCardAction`:解锁后优先卡→己方数字(`dropLogical`) |
## 3. 清除范围

Loading…
Cancel
Save