Normalize ammo economy: per-weapon refill, stream drain, behavior fixes
- Every special weapon gets an explicit 'refill' (units per ammo pickup,
tuned so one pickup funds ~10 kills) replacing the ammoRefillFraction
log2 heuristic and ammoWeight overrides
- Bile Blunderbuss + The Cauterizer join Red Right Hand as time-denominated
stream weapons ('drain' per second) instead of per-shot cost
- Sawblades ricochet through enemies (bounce fix), traps catch 3 victims,
lobbed projectiles arc overhead and always trigger at the target point
(Flesh Masher / Trap Queen / Swarm Jar payloads now actually deploy)
- Boss rooms stock one ammo on entry and drop one guaranteed on death
- Cauterizer burn trimmed (2.2s x2 -> 1.5s x0.8), bile acid pools trimmed
(3.5s x1.5 -> 2.5s x0.8), Marrow Draught now covers stream drain
- New tools/ammo_sim.js calibrates every weapon into the 8-13 kills/refill
band (all 15 pass); smoke test guards the ammo structure
- v0.3.0, cache bump v=44
This commit is contained in:
1 parent
7d33e36c1e
commit
d9eae34df4
18 files changed
+380
-101
No files matched your search
+22
-8
@@ -733,14 +733,10 @@ console.log('== generic ammo drops ==');
|
||||
step(2, 16);
|
||||
check('ammo reaches holstered weapon while sidearm is selected', p.holstered.ammo > holsteredAmmo);
|
||||
|
||||
const repeaterRefill = Math.ceil(ctx.WEAPONS.repeater.ammo * ctx.ammoRefillFraction(ctx.WEAPONS.repeater));
|
||||
const spinalRefill = Math.ceil(ctx.WEAPONS.spinaltap.ammo * ctx.ammoRefillFraction(ctx.WEAPONS.spinaltap));
|
||||
check('rapid low-damage weapons receive more rounds than heavy weapons', repeaterRefill > spinalRefill * 10);
|
||||
const sameDamageFast = ctx.ammoRefillFraction({ dmg: 8, interval: 0.1, ammo: 50 });
|
||||
const sameDamageSlow = ctx.ammoRefillFraction({ dmg: 8, interval: 1.0, ammo: 50 });
|
||||
check('fire rate explicitly increases ammo refill share', sameDamageFast > sameDamageSlow);
|
||||
check('persistent utility weapon overrides dampen refill size',
|
||||
ctx.WEAPONS.trapqueen.ammoWeight < 1 && ctx.WEAPONS.swarmjar.ammoWeight < 1);
|
||||
check('rapid low-damage weapons receive more rounds than heavy weapons',
|
||||
ctx.WEAPONS.repeater.refill > ctx.WEAPONS.spinaltap.refill * 10);
|
||||
check('stream weapons are time-denominated (drain, not per-shot)',
|
||||
ctx.WEAPONS.bile.drain > 0 && ctx.WEAPONS.cauterizer.drain > 0 && ctx.WEAPONS.redhand.drain > 0);
|
||||
|
||||
const repeaterCap = ctx.WEAPONS.repeater.ammo * 1.5;
|
||||
p.weapon = { id: 'repeater', ammo: repeaterCap - 1 };
|
||||
@@ -756,6 +752,24 @@ console.log('== generic ammo drops ==');
|
||||
ctx.G.pickups.length = 0;
|
||||
}
|
||||
|
||||
console.log('== ammo economy structure ==');
|
||||
{
|
||||
// Kills-per-refill is calibrated empirically by tools/ammo_sim.js (target
|
||||
// band ~8-13). Here we guard the structural rules that keep it meaningful.
|
||||
const bad = [];
|
||||
for (const w of Object.values(ctx.WEAPONS)) {
|
||||
if (w.ammo === Infinity) continue;
|
||||
if (!Number.isInteger(w.refill) || w.refill < 1) bad.push(w.id + ':refill-missing');
|
||||
else if (w.refill > w.ammo) bad.push(w.id + ':refill-exceeds-magazine');
|
||||
// a full magazine must stay a usable burst: not a 1s sneeze, not endless
|
||||
const seconds = w.drain ? w.ammo / w.drain
|
||||
: w.ammo * (w.behavior === 'beam' ? (w.chargeTime + w.interval) : w.interval);
|
||||
if (seconds < 3 || seconds > 20) bad.push(w.id + ':magazine-' + seconds.toFixed(1) + 's');
|
||||
}
|
||||
check('every special weapon has a sane authored refill + magazine', bad.length === 0);
|
||||
if (bad.length) console.log(' BAD-AMMO: ' + bad.join(', '));
|
||||
}
|
||||
|
||||
console.log('== drop economy: weapons are rare, elites feed you ==');
|
||||
{
|
||||
const p = ctx.G.player;
|
||||
|
||||
Reference in new issue
Block a user