feedback5 R3: Battle.js → server/sim/battle/*.js, a pure move — the 131 methods, verbatim with their comments, go to 14 per-concern method containers (players, lifecycle, hooks, spawns, deploy, blocking, status, combat, queries, summons, tiles, displacement, economy, events; fin / clone in util.js) that Battle.js installs on Battle.prototype in a fixed order with class-method descriptors; Battle.js keeps the header, the constructor and the class, and re-exports pushTiles. docs-consistency reads the method modules (battleText) and pins layerGainRoom in battle/economy.js
This commit is contained in:
1 parent
6b489b1776
commit
13224f9483
17 files changed
+2488
-2328
No files matched your search
@@ -0,0 +1,59 @@
|
||||
// server/sim/battle/combat.js — Battle methods: damage, heal and HP loss (the guarded entry points of the damage.js
|
||||
// pipeline), projectiles and forced attacks (ai.js performAttack).
|
||||
// Installed on Battle.prototype by server/sim/Battle.js (a method container: never instantiated; `this` is the battle).
|
||||
|
||||
import { dealDamage as pipeDamage, heal as pipeHeal, applyHpLoss, makeDamageInfo, reduceElement, leaderHitCancelled } from '../damage.js';
|
||||
import { effectiveProfile, performAttack, acquireTargets } from '../ai.js';
|
||||
|
||||
export class BattleCombat {
|
||||
dealDamage(source, target, dmg) {
|
||||
try { return pipeDamage(this, source, target, dmg); } catch (e) { this._internalError('dealDamage', e); return 0; }
|
||||
}
|
||||
|
||||
heal(source, target, amount, opts = {}) {
|
||||
try { return pipeHeal(this, source, target, amount, opts); } catch (e) { this._internalError('heal', e); return 0; }
|
||||
}
|
||||
|
||||
/**
|
||||
* HP loss that ignores DEF/RES, dodge and shields (流失). May kill. opts: { source, silent, tags, from } — `from` = the
|
||||
* DamageInfo this loss derives from (damage passed on to a leader, split, shared…): its tags are inherited and it is
|
||||
* kept as `dmg.origin`, so `damaged` handlers that skip their own tagged damage also skip what it turned into; a loss
|
||||
* derived from 无来源 damage (`from.sourceless`, element bursts) is 无来源 too (hooks see no source, `source` is credited).
|
||||
* `sourceless: true` makes the loss itself 无来源 ("受到等量的无来源生命流失": hooks see no source; `source` keeps the
|
||||
* credit — the stats and the per-player shared-pool tally).
|
||||
* On a leader in a boss / hidden battle a loss of ≥ BOSS_HIT_LIMIT is cancelled like a hit (damage.js leaderHitCancelled).
|
||||
*/
|
||||
loseHp(target, amount, { source = null, silent = false, tags = null, from = null, sourceless = false } = {}) {
|
||||
if (!target || !target.alive || !(amount > 0)) return 0;
|
||||
// 限伤 (shared/constants.js BOSS_HIT_LIMIT): a loss passed on to a leader (parts' 传递, 无人机) is one hit too
|
||||
if (leaderHitCancelled(this, target, amount)) return 0;
|
||||
const t = ['hpLoss'];
|
||||
for (const list of [from && from.tags, tags]) if (Array.isArray(list)) for (const x of list) if (!t.includes(x)) t.push(x);
|
||||
return applyHpLoss(this, source, target, amount, { type: 'true', tags: t, noSp: true, silent, origin: from ?? null, sourceless: !!sourceless || !!(from && from.sourceless) });
|
||||
}
|
||||
|
||||
reduceElement(target, amount, element = null) { return reduceElement(target, amount, element); }
|
||||
|
||||
makeDamage(d) { return makeDamageInfo(d); }
|
||||
|
||||
addProjectile(p) { return this.projectiles.add(p); }
|
||||
|
||||
// exposed for ai/content convenience
|
||||
effectiveProfile(u) { return effectiveProfile(u); }
|
||||
|
||||
/**
|
||||
* Perform an immediate attack with a unit's current profile (content: "立即攻击", extra attacks, counters). It is an
|
||||
* attack in every respect (hooks, attack SP, a running ammo skill's bullet) — except with `noAmmo: true`: an extra
|
||||
* attack that spends no ammo (no `ammoUsed`, the skill never ends on it; 圣约送葬人 "不额外消耗弹药").
|
||||
* Returns true when an attack was made.
|
||||
*/
|
||||
forceAttack(u, targets = null, { noAmmo = false } = {}) {
|
||||
if (!u || !u.alive || !u.profile) return false;
|
||||
const prof = effectiveProfile(u);
|
||||
const t = targets ?? acquireTargets(this, u, prof);
|
||||
if (!t || !t.length) return false;
|
||||
const n0 = u.stats.attacks;
|
||||
performAttack(this, u, prof, t, noAmmo ? { noAmmo: true } : null);
|
||||
return u.stats.attacks > n0;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user