master
parent
32d9e005d1
commit
eaf613c5e8
@ -0,0 +1,137 @@ |
||||
import type { EntityId } from 'db://assets/mx/module/ecs'; |
||||
import type { Skill } from '../skill/Skill'; |
||||
import type { SkillPresentationContext } from '../skill/SkillPresentationTypes'; |
||||
import type { SkillVisualChannel } from './SkillVisualChannel'; |
||||
import type { ISkillPresenter } from './SkillPresenter'; |
||||
|
||||
/** 待发射飞剑 */ |
||||
interface FlySwordPending { |
||||
/** 施法者 */ |
||||
caster: EntityId; |
||||
/** Ability id */ |
||||
abilityId: string; |
||||
/** 目标 */ |
||||
target: EntityId; |
||||
/** 伤害倍率 */ |
||||
scale: number; |
||||
/** atk_buff1 */ |
||||
buff1: string; |
||||
/** atk_buff2 */ |
||||
buff2: string; |
||||
/** 距发射(秒) */ |
||||
wait: number; |
||||
/** 表现通道 */ |
||||
channel: SkillVisualChannel; |
||||
} |
||||
|
||||
let _host: FlySwordHost | null = null; |
||||
|
||||
/** 飞剑交错发射宿主 */ |
||||
export function getFlySwordHost(): FlySwordHost { |
||||
if (!_host) _host = new FlySwordHost(); |
||||
return _host; |
||||
} |
||||
|
||||
/** |
||||
* atk_type=10 飞剑线:按间隔依次发射,落地伤由 BowAtkHost 结算。 |
||||
*/ |
||||
export class FlySwordHost { |
||||
private readonly _pending: FlySwordPending[] = []; |
||||
|
||||
/** |
||||
* 排队发射。 |
||||
* @param channel 表现通道 |
||||
* @param ctx 表现上下文 |
||||
* @param scale 伤害倍率 |
||||
* @param intervalSec 邻剑间隔 |
||||
* @param maxCount 最多发射数 |
||||
*/ |
||||
begin(channel: SkillVisualChannel, ctx: SkillPresentationContext, scale: number, intervalSec: number, maxCount: number): void { |
||||
const buff1 = String(ctx.params.buff1 ?? ''); |
||||
const buff2 = String(ctx.params.buff2 ?? ''); |
||||
const targets = ctx.targets; |
||||
let launched = 0; |
||||
for (let i = 0; i < targets.length && launched < maxCount; i++) { |
||||
const tid = targets[i]; |
||||
if (!(tid > 0)) continue; |
||||
this._pending.push({ |
||||
caster: ctx.caster, |
||||
abilityId: ctx.abilityId, |
||||
target: tid, |
||||
scale, |
||||
buff1, |
||||
buff2, |
||||
wait: launched * Math.max(0, intervalSec), |
||||
channel, |
||||
}); |
||||
launched += 1; |
||||
} |
||||
if (launched <= 0) { |
||||
console.log('[FlySword] 无有效目标', ctx.params.skillId); |
||||
return; |
||||
} |
||||
this.tick(0); |
||||
} |
||||
|
||||
/** |
||||
* 推进排队发射。 |
||||
* @param dt 逻辑秒 |
||||
*/ |
||||
tick(dt: number): void { |
||||
if (this._pending.length <= 0) return; |
||||
for (let i = this._pending.length - 1; i >= 0; i--) { |
||||
const p = this._pending[i]; |
||||
p.wait -= dt; |
||||
if (p.wait > 0) continue; |
||||
this._pending.splice(i, 1); |
||||
if (!p.channel.launchFlySword(p.caster, p.abilityId, p.target, p.scale, p.buff1, p.buff2)) { |
||||
console.log('[FlySword] 发射失败', p.target); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 卸下施法者排队。 |
||||
* @param caster 塔实体 |
||||
*/ |
||||
cancelCaster(caster: EntityId): void { |
||||
for (let i = this._pending.length - 1; i >= 0; i--) { |
||||
if (this._pending[i].caster === caster) this._pending.splice(i, 1); |
||||
} |
||||
} |
||||
|
||||
/** 清空全部排队 */ |
||||
abortAll(): void { |
||||
this._pending.length = 0; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 飞剑武器主动:瞬发,实例化飞剑.prefab 飞向目标,落地结算。 |
||||
*/ |
||||
export class FlySwordAtkPresenter implements ISkillPresenter { |
||||
present(ctx: SkillPresentationContext, host: Skill): void { |
||||
if (!ctx.isAlive) { |
||||
ctx.finish(); |
||||
return; |
||||
} |
||||
const raw = String(ctx.params.atkPara ?? '').split(','); |
||||
const count = Math.floor(Number(String(raw[0] ?? '').trim()) || 0); |
||||
const intervalSec = Number(String(raw[1] ?? '').trim()); |
||||
const wan = Number(String(raw[2] ?? '').trim()); |
||||
if (!(count > 0) || !Number.isFinite(intervalSec) || intervalSec < 0 || !Number.isFinite(wan) || !(wan > 0)) { |
||||
console.log('[FlySwordAtkPresenter] atk_para 无效', ctx.params.skillId, ctx.params.atkPara); |
||||
ctx.finish(); |
||||
return; |
||||
} |
||||
const skillKind = String(ctx.params.skillKind ?? ''); |
||||
const followWeapon = skillKind === 'weapon' || host.visualChannel.useWeapon; |
||||
if (followWeapon) host.visualChannel.ensureWeapon(); |
||||
const seq = host.beginPresentationCast(ctx); |
||||
if (!(seq > 0)) return; |
||||
host.disarmAnimComplete(); |
||||
getFlySwordHost().begin(host.visualChannel, ctx, wan / 10000, intervalSec, count); |
||||
ctx.releasePresentationLock(); |
||||
host.finishPresentationCast(seq, false); |
||||
} |
||||
} |
||||
@ -0,0 +1,9 @@ |
||||
{ |
||||
"ver": "4.0.24", |
||||
"importer": "typescript", |
||||
"imported": true, |
||||
"uuid": "aa83d9ec-834f-4235-8777-652362698e71", |
||||
"files": [], |
||||
"subMetas": {}, |
||||
"userData": {} |
||||
} |
||||
Loading…
Reference in new issue