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.
115 lines
3.7 KiB
115 lines
3.7 KiB
|
3 weeks ago
|
import { ChapterNewPlayTypeEnum, ICharmProperty } from '../../../game/ChapterPlayTypes';
|
||
|
|
import { cloneCharmConfig } from '../MechanismConfigClone';
|
||
|
|
import type { IBattleMechanism, MechanismContext } from '../IBattleMechanism';
|
||
|
|
import {
|
||
|
|
isCombatPhase,
|
||
|
|
pickRandomCharmTargets,
|
||
|
|
pickRandomDigGrid,
|
||
|
|
playFoxSpiritCharmVisual,
|
||
|
|
} from '../MechanismServices';
|
||
|
|
|
||
|
|
/** 狐狸精魅惑机制(Playmode 21) */
|
||
|
|
export class CharmMechanism implements IBattleMechanism {
|
||
|
|
readonly typeId = ChapterNewPlayTypeEnum.Charm;
|
||
|
|
|
||
|
|
private _ctx: MechanismContext | null = null;
|
||
|
|
private _config: ICharmProperty | null = null;
|
||
|
|
private _eventIndex = 0;
|
||
|
|
private _checkTimer = 0;
|
||
|
|
private _visualPending = 0;
|
||
|
|
|
||
|
|
init(ctx: MechanismContext, config: unknown): void {
|
||
|
|
this._ctx = ctx;
|
||
|
|
this._config = cloneCharmConfig(config as ICharmProperty);
|
||
|
|
this._eventIndex = 0;
|
||
|
|
this._checkTimer = 0;
|
||
|
|
this._visualPending = 0;
|
||
|
|
const cfg = this._config;
|
||
|
|
if (!cfg?.timeArr?.length) {
|
||
|
|
console.error('[CharmMechanism] 配表 timeArr 为空,机制不会触发');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
tick(dt: number): void {
|
||
|
|
if (!this._ctx || !this._config || !isCombatPhase(this._ctx)) return;
|
||
|
|
if (this._visualPending > 0) return;
|
||
|
|
|
||
|
|
this._checkTimer += dt;
|
||
|
|
if (this._checkTimer < 1) return;
|
||
|
|
this._checkTimer = 0;
|
||
|
|
this._tryTriggerDueEvents();
|
||
|
|
}
|
||
|
|
|
||
|
|
destroy(): void {
|
||
|
|
this._visualPending = 0;
|
||
|
|
this._ctx = null;
|
||
|
|
this._config = null;
|
||
|
|
this._eventIndex = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
private _tryTriggerDueEvents(): void {
|
||
|
|
const ctx = this._ctx;
|
||
|
|
const cfg = this._config;
|
||
|
|
if (!ctx || !cfg) return;
|
||
|
|
|
||
|
|
while (this._eventIndex < cfg.timeArr.length && ctx.battleTime >= cfg.timeArr[this._eventIndex]) {
|
||
|
|
if (!this._tryTriggerOnce()) break;
|
||
|
|
this._eventIndex++;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private _tryTriggerOnce(): boolean {
|
||
|
|
const ctx = this._ctx;
|
||
|
|
const cfg = this._config;
|
||
|
|
if (!ctx || !cfg) return false;
|
||
|
|
|
||
|
|
const wave = this._eventIndex;
|
||
|
|
const targetCount = cfg.numArr[wave] ?? 1;
|
||
|
|
const rawDuration = cfg.durationArr[wave];
|
||
|
|
const durationSec = (typeof rawDuration === 'number' && Number.isFinite(rawDuration) && rawDuration > 0)
|
||
|
|
? rawDuration
|
||
|
|
: 2;
|
||
|
|
const exclude = ctx.runtime.charmController.getCharmedComposeKeys();
|
||
|
|
const targets = pickRandomCharmTargets(ctx, targetCount, exclude);
|
||
|
|
if (targets.length === 0) {
|
||
|
|
console.log(
|
||
|
|
'[CharmMechanism] 无可用魅惑目标(需地图上有已激活攻击的武器/英雄),event=',
|
||
|
|
wave,
|
||
|
|
'battleTime=',
|
||
|
|
ctx.battleTime,
|
||
|
|
'deployed=',
|
||
|
|
ctx.runtime.getPlayer(0)?.deployedUnits.length ?? 0,
|
||
|
|
);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
let pending = 0;
|
||
|
|
for (const target of targets) {
|
||
|
|
const appearGrid = pickRandomDigGrid(ctx);
|
||
|
|
if (!appearGrid) {
|
||
|
|
console.log('[CharmMechanism] 无可开挖出现落点,target=', target.composeKey);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
const ok = playFoxSpiritCharmVisual(
|
||
|
|
ctx,
|
||
|
|
appearGrid,
|
||
|
|
target,
|
||
|
|
durationSec,
|
||
|
|
ctx.runtime.charmController,
|
||
|
|
() => this._onVisualComplete(),
|
||
|
|
);
|
||
|
|
if (ok) pending++;
|
||
|
|
}
|
||
|
|
if (pending <= 0) return false;
|
||
|
|
this._visualPending = pending;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
private _onVisualComplete(): void {
|
||
|
|
if (this._visualPending <= 0) return;
|
||
|
|
this._visualPending--;
|
||
|
|
}
|
||
|
|
}
|