0.2.6-dev: port PR #552 by IceCodeNew — an optional 「弹药数量」 setting (default off: the official HUD has no such number, the maintainer's decision of 2026-10-13) shows an ammo skill's rounds left / magazine under its bar, from the exact b.snap ammo counts; sanitised with the other settings, applied by the field view live, all four language packs, the diagnostics line; the simplified board has no ammo bar; DESIGN §31.9; golden: unchanged
This commit is contained in:
1 parent
231da0efbc
commit
461a7747e1
16 files changed
+244
-17
No files matched your search
@@ -3,6 +3,7 @@
|
||||
// [[id, left, max]] and `neg` [[id, fill]] beside the unit tuples and samples them from the older snapshot; render/units.js
|
||||
// draws the ammo skill's segmented yellow bar in place of the SP bar, 伺夜's 狼影 as a row of diamonds and the 我执 pool
|
||||
// as the red bar over the drained HP bar; an ammo skill has no standing aura (headless fake PIXI, test/render/fakepixi.js).
|
||||
// 设置「弹药数量」 (PR #552 by @IceCodeNew, off by default) adds the magazine's count under the ammo bar.
|
||||
// The server side is test/sim/hud-readouts.test.js and test/content/op_hsgma2.test.js.
|
||||
// Run: node --test test/render/hud-readouts.test.js
|
||||
|
||||
@@ -166,6 +167,92 @@ describe('UnitView: the ammo skill\'s segmented bar', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// 设置「弹药数量」 (PR #552 by @IceCodeNew, DESIGN §31.9): the official HUD has no number under the ammo bar, so the count is an
|
||||
// option, off by default (the maintainer's decision of 2026-10-13); the settings side is test/ui/ammo-count.test.js
|
||||
describe('UnitView: the optional ammo count under the bar (设置「弹药数量」)', () => {
|
||||
const counting = (on = true) => view({}, { settings: { damageNumbers: true, quality: 'high', ammoCount: on } });
|
||||
const coinY = (v) => v.coinHud.root.position.y;
|
||||
|
||||
test('off (the default): nothing is drawn under the magazine, and the rows below stay where they were', () => {
|
||||
const v = view();
|
||||
const w = counting(false);
|
||||
try {
|
||||
for (const u of [v, w]) { u.sync(sample({ flags: UF.SKILL, ammo: [13, 14], coins: [3, 10] })); frames(u); }
|
||||
assert.equal(v.ammoText, null, 'never built without the setting');
|
||||
assert.equal(w.ammoText, null, 'nor with it off');
|
||||
assert.equal(v.hud.children.some((c) => c instanceof fake.P.Text && /\d+\/14/.test(c.text)), false);
|
||||
const plain = view();
|
||||
plain.sync(sample({ coins: [3, 10] }));
|
||||
frames(plain);
|
||||
assert.equal(coinY(v), coinY(w));
|
||||
assert.ok(coinY(v) > coinY(plain), 'the magazine row (thicker than the SP bar) is all that sits above the purse');
|
||||
plain.destroy();
|
||||
} finally { v.destroy(); w.destroy(); }
|
||||
});
|
||||
|
||||
test('on: the exact count through spending, refills and capacity changes, also where the cells are too narrow for cuts', () => {
|
||||
const v = counting();
|
||||
try {
|
||||
for (const [left, max] of [[13, 14], [12, 14], [137, 240], [136, 240], [260, 260], [0, 260]]) {
|
||||
v.sync(sample({ flags: UF.SKILL, ammo: [left, max] }));
|
||||
frames(v);
|
||||
assert.equal(v.ammoText?.text, `${left}/${max}`);
|
||||
assert.equal(v.ammoText.visible, true);
|
||||
if (max >= 240) assert.equal(v.ammoCuts.filter((c) => c.visible).length, 0, 'a dense magazine draws no cuts, the count still reads');
|
||||
}
|
||||
const bw = barWidth(v);
|
||||
assert.ok(Math.abs(v.ammoText.position.x - (v.spFill.position.x + bw / 2)) < 1e-9, 'centred under the bar');
|
||||
assert.ok(v.ammoText.position.y > v.spFill.position.y, 'below the magazine');
|
||||
assert.equal(v.ammoText.anchor.x, 0.5);
|
||||
assert.equal(v.ammoText.style.fill, COLORS.ammo, 'in the bar\'s yellow');
|
||||
} finally { v.destroy(); }
|
||||
});
|
||||
|
||||
test('on: hidden when the skill ends, without the snapshot row, in the prep view, after death and for enemies; the rows below make room', () => {
|
||||
const v = counting();
|
||||
try {
|
||||
v.sync(sample({ flags: UF.SKILL, ammo: [5, 14], coins: [3, 10] }));
|
||||
frames(v);
|
||||
const withCount = coinY(v);
|
||||
v.sync(sample({ sp: 6, spMax: 24, coins: [3, 10] })); // the magazine is spent: the SP bar again
|
||||
frames(v);
|
||||
assert.equal(v.ammoText.visible, false, 'no stale number after the skill');
|
||||
assert.ok(withCount > coinY(v), 'the purse row moved down by the count\'s height while it showed');
|
||||
v.sync(sample({ flags: UF.SKILL, ammo: [5, 14] }));
|
||||
v.prep = true;
|
||||
frames(v);
|
||||
assert.equal(v.ammoText.visible, false, 'the prep view draws no bars');
|
||||
v.prep = false;
|
||||
frames(v);
|
||||
assert.equal(v.ammoText.visible, true);
|
||||
v.die();
|
||||
frames(v);
|
||||
assert.equal(v.ammoText.visible, false, 'a dead unit has no bars');
|
||||
} finally { v.destroy(); }
|
||||
const e = view({ id: 2, side: 'enemy', kind: 'enemy', defId: 'enemy_x' }, { settings: { damageNumbers: true, quality: 'high', ammoCount: true } });
|
||||
try {
|
||||
e.sync(sample({ hp: 500, flags: UF.SKILL, ammo: [3, 4] }));
|
||||
frames(e);
|
||||
assert.equal(e.ammoText, null, 'enemies have no magazine, so no count');
|
||||
} finally { e.destroy(); }
|
||||
});
|
||||
|
||||
test('turning the setting off takes the count away at once (the field view shares its settings object with the units)', () => {
|
||||
const v = counting();
|
||||
try {
|
||||
v.sync(sample({ flags: UF.SKILL, ammo: [9, 14] }));
|
||||
frames(v);
|
||||
assert.equal(v.ammoText.visible, true);
|
||||
v.ctx.settings.ammoCount = false;
|
||||
frames(v);
|
||||
assert.equal(v.ammoText.visible, false);
|
||||
v.ctx.settings.ammoCount = true;
|
||||
frames(v);
|
||||
assert.equal(v.ammoText.visible, true);
|
||||
} finally { v.destroy(); }
|
||||
});
|
||||
});
|
||||
|
||||
describe('UnitView: 伺夜\'s 狼影 pips', () => {
|
||||
const pack = (extra = {}) => view({ kind: 'token', defId: 'token_10028_vigil_wolf', ...extra });
|
||||
|
||||
|
||||
Reference in new issue
Block a user