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:
sganggs committed 2026-10-05 16:13:25 +08:00
1 parent 6b489b1776
commit 13224f9483
17 files changed
+2488 -2328

No files matched your search

+59
View File
@@ -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;
}
}