You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
231 lines
9.1 KiB
231 lines
9.1 KiB
import { BattleBuffFunctionType, BattleBuffSlotType } from '../../manager/battleBuff/BattleBuffTypes';
|
|
import {
|
|
BattleGameSkillDragKind,
|
|
isBattleBuffDragRecycleToPeach,
|
|
resolveBattleGameSkillClickKind,
|
|
resolveBattleGameSkillDragKind,
|
|
} from '../../manager/battleBuff/BattleBuffActiveSkillUtil';
|
|
import { parseBattleBuffRow } from '../../manager/BattleBuffParse';
|
|
import { DailyShopDataManager } from '../../manager/DailyShopDataManager';
|
|
import { DailyShopKind, type DailyShopParsed } from '../../manager/DailyShopTypes';
|
|
import { TableNames } from '../../game/ConfigTableData';
|
|
import type { ProjectBattleHandle } from '../../battle/runtime/BattleRuntime';
|
|
|
|
/** 主动 skill 槽数量 */
|
|
const SKILL_SLOT_COUNT = 2;
|
|
|
|
/** 七十二变不可随机到的主动 buff id*/
|
|
const RANDOM_ACTIVE_BANNED_BUFF_IDS: readonly number[] = [];
|
|
|
|
/** 战斗 rng 最小接口(七十二变 roll) */
|
|
type BattleRollRng = { int(min: number, max: number): number };
|
|
|
|
/** 随机池条目:buff id + 权重 */
|
|
type RollPoolEntry = { id: number; weight: number };
|
|
|
|
/** 单槽七十二变状态 */
|
|
type RandomActiveSlotState = {
|
|
/** 携带的七十二变 buff id */
|
|
baseBuffId: number;
|
|
/** 当前随机展示 buff id;0=显示本体(CD 中) */
|
|
rolledBuffId: number;
|
|
};
|
|
|
|
/**
|
|
* 七十二变(functiontype=19)局内宿主。
|
|
* CD 结束随机主动 buff;用完恢复本体并重新进入 CD。
|
|
*/
|
|
export class BattleGameRandomActiveSkillHost {
|
|
private static _inst: BattleGameRandomActiveSkillHost | null = null;
|
|
|
|
private _slots: (RandomActiveSlotState | null)[] = [];
|
|
|
|
/** 单例 */
|
|
static get(): BattleGameRandomActiveSkillHost {
|
|
if (!BattleGameRandomActiveSkillHost._inst) {
|
|
BattleGameRandomActiveSkillHost._inst = new BattleGameRandomActiveSkillHost();
|
|
}
|
|
return BattleGameRandomActiveSkillHost._inst;
|
|
}
|
|
|
|
/** 战斗结束重置 */
|
|
reset(): void {
|
|
this._slots.length = 0;
|
|
}
|
|
|
|
/** 是否七十二变 buff 行 */
|
|
isRandomActiveRow(row: ITableBattlebuff | null | undefined): boolean {
|
|
if (!row) return false;
|
|
return Number(row.type) === BattleBuffSlotType.Active
|
|
&& Number(row.functiontype) === BattleBuffFunctionType.RandomActive;
|
|
}
|
|
|
|
/** 槽位是否为七十二变携带 */
|
|
isRandomActiveSlot(slotIndex: number): boolean {
|
|
return this._slots[slotIndex] != null;
|
|
}
|
|
|
|
/** 当前是否展示随机出的主动 buff(可施放) */
|
|
isShowingRolledBuff(slotIndex: number): boolean {
|
|
const state = this._slots[slotIndex];
|
|
return state != null && state.rolledBuffId > 0;
|
|
}
|
|
|
|
/** 绑定槽位携带 buff(refresh 时) */
|
|
syncSlot(slotIndex: number, baseBuffId: number, row: ITableBattlebuff | null | undefined): void {
|
|
if (slotIndex < 0 || slotIndex >= SKILL_SLOT_COUNT) return;
|
|
if (!this.isRandomActiveRow(row)) {
|
|
this._slots[slotIndex] = null;
|
|
return;
|
|
}
|
|
const id = Math.floor(Number(baseBuffId) || 0);
|
|
if (id <= 0) {
|
|
this._slots[slotIndex] = null;
|
|
return;
|
|
}
|
|
const prev = this._slots[slotIndex];
|
|
const rolledBuffId = prev != null && prev.baseBuffId === id ? prev.rolledBuffId : 0;
|
|
this._slots[slotIndex] = { baseBuffId: id, rolledBuffId };
|
|
}
|
|
|
|
/** 解析槽位当前应走的 skill 拖拽类型(roll 后按变化 buff) */
|
|
resolveCastDragKind(slotIndex: number, baseParsed: DailyShopParsed | null): BattleGameSkillDragKind | null {
|
|
const cast = this.resolveDisplayParsed(slotIndex, baseParsed);
|
|
if (!cast) return null;
|
|
return resolveBattleGameSkillDragKind(cast.row as ITableBattlebuff);
|
|
}
|
|
|
|
/**
|
|
* 解析槽位当前应展示的 buff 解析结果。
|
|
* @param slotIndex skill 槽
|
|
* @param baseParsed 携带 buff 解析
|
|
*/
|
|
resolveDisplayParsed(slotIndex: number, baseParsed: DailyShopParsed | null): DailyShopParsed | null {
|
|
if (!baseParsed) return null;
|
|
const state = this._slots[slotIndex];
|
|
if (!state) return baseParsed;
|
|
if (state.rolledBuffId > 0) {
|
|
const rolled = DailyShopDataManager.getParsed(state.rolledBuffId)
|
|
?? BattleGameRandomActiveSkillHost._parseRollBuffParsed(state.rolledBuffId);
|
|
if (!rolled) {
|
|
console.log('[BattleGameRandomActive] 随机 buff 缺失', state.rolledBuffId);
|
|
return baseParsed;
|
|
}
|
|
return rolled;
|
|
}
|
|
return baseParsed;
|
|
}
|
|
|
|
/**
|
|
* CD 结束:随机一个可局内施放的主动 buff。
|
|
* @returns 是否成功 roll
|
|
*/
|
|
tryRollOnCooldownReady(slotIndex: number, battle: ProjectBattleHandle | null): boolean {
|
|
const state = this._slots[slotIndex];
|
|
if (!state || state.rolledBuffId > 0) return false;
|
|
|
|
const excludeIds = BattleGameRandomActiveSkillHost._collectCarriedActiveBuffIds();
|
|
const picked = BattleGameRandomActiveSkillHost.pickRollBuffIdFromPool(
|
|
excludeIds,
|
|
battle?.session?.rng ?? null,
|
|
);
|
|
if (picked <= 0) {
|
|
console.log('[BattleGameRandomActive] roll 失败', slotIndex, excludeIds);
|
|
return false;
|
|
}
|
|
state.rolledBuffId = picked;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 从可随机池按 weight 权重选取 buff id;GM 固定 id 优先且须在池内。
|
|
* @param excludeIds 排除 id
|
|
* @param rng 战斗 rng;GM 固定时可省略
|
|
*/
|
|
static pickRollBuffIdFromPool(excludeIds: readonly number[], rng: BattleRollRng | null): number {
|
|
const pool = BattleGameRandomActiveSkillHost._buildRollPool(excludeIds);
|
|
const fixId = Math.floor(Number(gg.game.gmRandomActiveFixBuffId) || 0);
|
|
if (fixId > 0) {
|
|
for (let i = 0; i < pool.length; i++) {
|
|
if (pool[i].id === fixId) return fixId;
|
|
}
|
|
console.log('[BattleGameRandomActive] GM 固定 roll 不在可用池', fixId, pool);
|
|
return 0;
|
|
}
|
|
if (pool.length <= 0) return 0;
|
|
if (!rng) {
|
|
console.log('[BattleGameRandomActive] 无 battle rng');
|
|
return 0;
|
|
}
|
|
let total = 0;
|
|
for (let i = 0; i < pool.length; i++) total += pool[i].weight;
|
|
if (total <= 0) return 0;
|
|
let roll = rng.int(0, total - 1);
|
|
for (let i = 0; i < pool.length; i++) {
|
|
roll -= pool[i].weight;
|
|
if (roll < 0) return pool[i].id;
|
|
}
|
|
return pool[pool.length - 1].id;
|
|
}
|
|
|
|
/** 随机 buff 施放成功:恢复本体展示(由 View 开 CD) */
|
|
onRolledBuffConsumed(slotIndex: number): void {
|
|
const state = this._slots[slotIndex];
|
|
if (!state) return;
|
|
state.rolledBuffId = 0;
|
|
}
|
|
|
|
/** 收集全部主动槽携带 buff id(不可随机到自身或其它槽) */
|
|
private static _collectCarriedActiveBuffIds(): number[] {
|
|
const slotIds = DailyShopDataManager.getActiveSlotIds();
|
|
const out: number[] = [];
|
|
for (let i = 0; i < SKILL_SLOT_COUNT; i++) {
|
|
const id = Math.floor(Number(slotIds[i]) || 0);
|
|
if (id > 0) out.push(id);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
/** 可随机主动 buff 池(type=1、局内可施放、weight>0;排除已携带 id) */
|
|
private static _buildRollPool(excludeIds: readonly number[]): RollPoolEntry[] {
|
|
const list = gg.data.table.getTableList<ITableBattlebuff>(TableNames.Battlebuff) ?? [];
|
|
const exclude = excludeIds.slice();
|
|
const out: RollPoolEntry[] = [];
|
|
for (let i = 0; i < list.length; i++) {
|
|
const row = list[i];
|
|
const id = Math.floor(Number(row.id) || 0);
|
|
if (id <= 0) continue;
|
|
if (exclude.indexOf(id) >= 0) continue;
|
|
if (RANDOM_ACTIVE_BANNED_BUFF_IDS.indexOf(id) >= 0) continue;
|
|
if (!BattleGameRandomActiveSkillHost._isRollCandidate(row)) continue;
|
|
const weight = Math.max(0, Math.floor(Number(row.weight) || 0));
|
|
if (weight <= 0) continue;
|
|
out.push({ id, weight });
|
|
}
|
|
return out;
|
|
}
|
|
|
|
/** 从配表解析 roll 目标 buff(不依赖是否已携带) */
|
|
private static _parseRollBuffParsed(buffId: number): DailyShopParsed | null {
|
|
const id = Math.floor(Number(buffId) || 0);
|
|
if (id <= 0) return null;
|
|
const row = gg.data.table.getTableData<ITableBattlebuff>(TableNames.Battlebuff, id);
|
|
if (!row) return null;
|
|
return parseBattleBuffRow(row);
|
|
}
|
|
|
|
/** 是否可进入随机池 */
|
|
private static _isRollCandidate(row: ITableBattlebuff): boolean {
|
|
const parsed = parseBattleBuffRow(row);
|
|
if (!parsed || parsed.kind !== DailyShopKind.Active) return false;
|
|
if (Number(row.functiontype) === BattleBuffFunctionType.RandomActive) return false;
|
|
if (resolveBattleGameSkillDragKind(row) != null) return true;
|
|
if (resolveBattleGameSkillClickKind(row) != null) return true;
|
|
return isBattleBuffDragRecycleToPeach(row);
|
|
}
|
|
}
|
|
|
|
/** 获取七十二变宿主 */
|
|
export function getBattleGameRandomActiveSkillHost(): BattleGameRandomActiveSkillHost {
|
|
return BattleGameRandomActiveSkillHost.get();
|
|
}
|
|
|