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.
175 lines
6.4 KiB
175 lines
6.4 KiB
import type { Skill } from '../skill/Skill';
|
|
import type { SkillPresentationContext } from '../skill/SkillPresentationTypes';
|
|
import type { ISkillPresenter } from './SkillPresenter';
|
|
import {
|
|
FallbackAtkPresenter,
|
|
InstantAtkPresenter,
|
|
LineMultiHitAtkPresenter,
|
|
LineRectAtkPresenter,
|
|
ProjectileAtkPresenter,
|
|
ScatterPierceAtkPresenter,
|
|
SequentialSingleAtkPresenter,
|
|
SummonAtkPresenter,
|
|
VolleyArrowAtkPresenter,
|
|
} from './AtkTypePresenters';
|
|
|
|
/**
|
|
* 技能表现路由:Skill.skill 额外效果头优先,其次 skillId,否则 atk_type。
|
|
* 三槽(普攻/英雄主动/武器主动)共用。
|
|
*/
|
|
export class SkillPresenterRouter {
|
|
private static _inst: SkillPresenterRouter | null = null;
|
|
|
|
/** 单例 */
|
|
static get instance(): SkillPresenterRouter {
|
|
if (!this._inst) {
|
|
this._inst = new SkillPresenterRouter();
|
|
this._inst._registerBuiltin();
|
|
}
|
|
return this._inst;
|
|
}
|
|
|
|
private readonly _bySkillId: { id: number; presenter: ISkillPresenter }[] = [];
|
|
private readonly _byAtkType: { type: number; presenter: ISkillPresenter }[] = [];
|
|
private readonly _byExtra: { type: number; presenter: ISkillPresenter }[] = [];
|
|
private _fallback: ISkillPresenter = new FallbackAtkPresenter();
|
|
|
|
/** 按 skillId 注册特殊表现 */
|
|
registerSkillId(skillId: number, presenter: ISkillPresenter): void {
|
|
const id = Math.floor(Number(skillId) || 0);
|
|
if (id <= 0) {
|
|
console.log('[SkillPresenterRouter] skillId 无效', skillId);
|
|
return;
|
|
}
|
|
const idx = this._findSkillIndex(id);
|
|
if (idx >= 0) this._bySkillId[idx].presenter = presenter;
|
|
else this._bySkillId.push({ id, presenter });
|
|
}
|
|
|
|
/**
|
|
* 按 Skill.skill 头类型注册额外效果表现。
|
|
* @param extraType skill 字段第一段
|
|
* @param presenter 表现
|
|
*/
|
|
registerExtraSkill(extraType: number, presenter: ISkillPresenter): void {
|
|
const type = Math.floor(Number(extraType) || 0);
|
|
if (type <= 0) {
|
|
console.log('[SkillPresenterRouter] extraSkill 类型无效', extraType);
|
|
return;
|
|
}
|
|
for (let i = 0; i < this._byExtra.length; i++) {
|
|
if (this._byExtra[i].type === type) {
|
|
this._byExtra[i].presenter = presenter;
|
|
return;
|
|
}
|
|
}
|
|
this._byExtra.push({ type, presenter });
|
|
}
|
|
|
|
/** 按 atk_type 注册通用表现 */
|
|
registerAtkType(atkType: number, presenter: ISkillPresenter): void {
|
|
const type = Math.floor(Number(atkType) || 0);
|
|
const idx = this._findTypeIndex(type);
|
|
if (idx >= 0) this._byAtkType[idx].presenter = presenter;
|
|
else this._byAtkType.push({ type, presenter });
|
|
}
|
|
|
|
/** 分发表现 */
|
|
dispatch(ctx: SkillPresentationContext, host: Skill): void {
|
|
if (!ctx.isAlive) return;
|
|
const extraRaw = String(
|
|
ctx.params.extraSkill
|
|
?? (String(ctx.params.skillKind ?? '') === 'normal' ? '' : ctx.params.skillRaw)
|
|
?? '',
|
|
).trim();
|
|
if (extraRaw) {
|
|
const extraHead = Math.floor(Number(extraRaw.split(',')[0]) || 0);
|
|
const extraPres = this._findExtraPresenter(extraHead);
|
|
if (extraPres) {
|
|
extraPres.present(ctx, host);
|
|
return;
|
|
}
|
|
}
|
|
this.dispatchBase(ctx, host);
|
|
}
|
|
|
|
/**
|
|
* 跳过 Skill.skill 额外效果段,按 skillId → atk_type → 兜底派发。
|
|
* 供附加型额外效果(如 type=10 环形龙影)先播本体表现再追加。
|
|
*/
|
|
dispatchBase(ctx: SkillPresentationContext, host: Skill): void {
|
|
if (!ctx.isAlive) return;
|
|
const skillId = Math.floor(Number(ctx.params.skillId ?? ctx.baseAtkId) || 0);
|
|
const byId = this._findSkillPresenter(skillId);
|
|
if (byId) {
|
|
byId.present(ctx, host);
|
|
return;
|
|
}
|
|
const atkHead = Math.floor(Number(ctx.params.atkTypeHead ?? ctx.params.atkType) || 0);
|
|
const byType = this._findTypePresenter(atkHead);
|
|
if (byType) {
|
|
byType.present(ctx, host);
|
|
return;
|
|
}
|
|
this._fallback.present(ctx, host);
|
|
}
|
|
|
|
private _registerBuiltin(): void {
|
|
const instant = new InstantAtkPresenter();
|
|
const lineRect = new LineRectAtkPresenter();
|
|
const lineMulti = new LineMultiHitAtkPresenter();
|
|
const summon = new SummonAtkPresenter();
|
|
this.registerAtkType(1, instant);
|
|
this.registerAtkType(2, lineRect);
|
|
this.registerAtkType(3, instant);
|
|
this.registerAtkType(5, lineMulti);
|
|
this.registerAtkType(14, lineMulti);
|
|
this.registerAtkType(16, lineMulti);
|
|
this.registerAtkType(15, instant);
|
|
this.registerAtkType(6, instant);
|
|
this.registerAtkType(7, instant);
|
|
this.registerAtkType(10, new SequentialSingleAtkPresenter());
|
|
this.registerAtkType(8, summon);
|
|
this.registerAtkType(11, summon);
|
|
const projectile = new ProjectileAtkPresenter();
|
|
this.registerAtkType(4, projectile);
|
|
this.registerAtkType(12, new ScatterPierceAtkPresenter());
|
|
this.registerAtkType(17, new ScatterPierceAtkPresenter());
|
|
this.registerAtkType(13, new VolleyArrowAtkPresenter());
|
|
}
|
|
|
|
private _findSkillIndex(id: number): number {
|
|
for (let i = 0; i < this._bySkillId.length; i++) {
|
|
if (this._bySkillId[i].id === id) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
private _findTypeIndex(type: number): number {
|
|
for (let i = 0; i < this._byAtkType.length; i++) {
|
|
if (this._byAtkType[i].type === type) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
private _findSkillPresenter(id: number): ISkillPresenter | null {
|
|
const idx = this._findSkillIndex(id);
|
|
return idx >= 0 ? this._bySkillId[idx].presenter : null;
|
|
}
|
|
|
|
private _findTypePresenter(type: number): ISkillPresenter | null {
|
|
const idx = this._findTypeIndex(type);
|
|
return idx >= 0 ? this._byAtkType[idx].presenter : null;
|
|
}
|
|
|
|
/**
|
|
* 按 extra skill 头查找表现。
|
|
* @param type skill 第一段
|
|
*/
|
|
private _findExtraPresenter(type: number): ISkillPresenter | null {
|
|
for (let i = 0; i < this._byExtra.length; i++) {
|
|
if (this._byExtra[i].type === type) return this._byExtra[i].presenter;
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|