Fix source-owned Lemuen detection and wanted skill triggers (#428)

This commit is contained in:
sganggs committed 2026-10-09 17:29:46 +08:00
1 parent 08c93460db
commit 85b694f206
8 files changed
+495 -379

No files matched your search

@@ -21,24 +21,43 @@ const LEMUEN_SHELL_FLIGHT = 0.3;
function ensureWanted(battle) {
const S = bstate(battle);
if (S.wanted) return S.wanted;
const W = S.wanted = { lemuens: new Set(), time: new WeakMap() };
const W = S.wanted = { lemuens: new Set(), sources: new Map(), refreshRanges: new Set() };
const activeLem = () => [...W.lemuens].filter(live);
battle.every(0.25, () => {
const lems = activeLem();
if (!lems.length) return;
const need = Math.min(...lems.map((u) => u.mem.wantedInterval));
const lat = battle.allyUnits.filter((a) => live(a) && a.kind === 'op' && hasBond(a, 'lateranoShip'));
const reconcile = () => {
for (const e of battle.enemies) {
if (!e.alive || e.hidden || !isElite(e) || e.findBuff('lemuen:wanted')) continue;
// "停留超过8秒": a continuous stay — leaving every 拉特兰 range restarts the count
if (!lat.some((a) => a.rangeKeySet && bodyInKeys(e, a.rangeKeySet))) { W.time.delete(e); continue; }
const t = (W.time.get(e) ?? 0) + 0.25;
W.time.set(e, t);
if (t >= need - 1e-9) {
const marked = [...W.sources.values()].some((s) => s.marks.has(e));
if (marked && e.alive && !e.findBuff('lemuen:wanted')) {
battle.addBuff(e, { key: 'lemuen:wanted', visible: true });
battle.fx('wanted', { x: e.x, y: e.y, id: e.id });
} else if (!marked && e.findBuff('lemuen:wanted')) battle.removeBuff(e, 'lemuen:wanted');
}
for (const refresh of W.refreshRanges) refresh();
};
// PRTS: the source leaving clears its timers and marks; another on-field Lemuen keeps her own progress.
battle.on('death', ({ unit }) => {
if (!W.lemuens.has(unit)) return;
W.sources.delete(unit);
reconcile();
});
battle.every(0.25, () => {
const lems = activeLem();
for (const u of W.sources.keys()) if (!lems.includes(u)) W.sources.delete(u);
const lat = battle.allyUnits.filter((a) => live(a) && a.kind === 'op' && hasBond(a, 'lateranoShip'));
for (const u of lems) {
let state = W.sources.get(u);
if (!state) W.sources.set(u, state = { time: new WeakMap(), marks: new Set() });
for (const e of state.marks) if (!e.alive) state.marks.delete(e);
for (const e of battle.enemies) {
if (!e.alive || state.marks.has(e) || !isElite(e)) continue;
// PRTS: starting the timer needs selectability; once attached, only its continuous stay is tested.
if (e.hidden || !lat.some((a) => a.rangeKeySet && bodyInKeys(e, a.rangeKeySet))) { state.time.delete(e); continue; }
if (!state.time.has(e) && !canTargetEnemy(u, e, ANY)) continue;
const t = (state.time.get(e) ?? 0) + 0.25;
state.time.set(e, t);
if (t >= u.mem.wantedInterval - 1e-9) state.marks.add(e);
}
}
reconcile();
});
battle.on('hit', (ctx) => {
const s = ctx.source, t = ctx.target;
@@ -205,17 +224,26 @@ function lemuen(bb, chess, def) {
{ install(battle, unit) { // 跨境追缉许可
unit.mem.wantedInterval = num(t0.interval, 8);
unit.mem.wantedScale = num(t0.damage_scale, 1);
ensureWanted(battle).lemuens.add(unit);
let sig = null;
battle.on('tick', () => { // wanted targets' tiles join her range (engine extra range keys, kept across rebuilds)
if (!live(unit)) return;
const wanted = ensureWanted(battle);
wanted.lemuens.add(unit);
const wantedKeys = () => {
const keys = [];
for (const e of battle.enemies) if (e.alive && !e.hidden && e.findBuff('lemuen:wanted')) keys.push(...bodyKeys(e));
return keys;
};
// #428: extra attack range also opens her skill under the existing content-trigger contract.
unit.skill?.addTriggerRange(() => [{ keys: wantedKeys(), profile: unit.profile }]);
let sig = null;
const refresh = () => { // update immediately when the last source leaves, before another attack can run
const keys = live(unit) ? wantedKeys() : [];
const s = keys.join(',');
if (s === sig) return;
sig = s;
battle.setExtraRange(unit, keys);
}, { owner: unit });
};
wanted.refreshRanges.add(refresh);
battle.on('tick', refresh, { owner: unit });
battle.on('deploy', ({ unit: u }) => { if (u === unit) { sig = null; refresh(); } }, { owner: unit });
} },
{ install(battle, unit) { // 逃犯引渡手续
const iv = num(t1.interval, 20), atk = num(t1.atk), add = Math.floor(num(t1.add_count)), exAdd = Math.floor(num(t1.ex_add_count));