Doom-style weapon audio batch + remove footsteps

- Regenerated all 13 weapon fire one-shots and 4 weapon loops via the audio
  specialist (ElevenLabs) with a 1993 Doom style brief: chunky, bass-heavy,
  crunchy 90s FPS sounds
- New clips wired into SfxBank: ui_active, ui_active_empty (active items),
  ui_curse (legendary pickups, replaces the normal item jingle), plr_revive
  (Second Skin revive)
- Footstep system removed entirely (never worked right): Sfx.footstep, 8
  plr_step* samples and bank entries, player.js call site, smoke test block
- Cache v=42
This commit is contained in:
MeatSlicer Developer committed 2026-07-30 17:41:31 +10:00
1 parent 4dad22d087
commit 64ac53434b
36 files changed
+37 -80

No files matched your search

+2 -2
View File
@@ -176,9 +176,9 @@ function giveItem(iid) {
spawnText(p.x, p.y - 14, 'UPGRADED!', '#ffd060');
} else {
addToast(item.name, item.desc);
spawnText(p.x, p.y - 14, item.name.toUpperCase(), '#c9a227');
spawnText(p.x, p.y - 14, item.name.toUpperCase(), ITEM_RARITY[item.rarity].color);
}
Sfx.item();
if (item.rarity === 'legendary') Sfx.curse(); else Sfx.item();
refreshOrbitals(p);
}
+2 -6
View File
@@ -5,7 +5,7 @@ function initPlayer() {
x: W / 2, y: H / 2, r: 20,
hp: 6, shieldHp: 0,
aim: 0, bodyFacing: 0, fireT: 0, charge: 0, invT: 0, frenzyT: 0,
step: 0, stepTick: 0, moveBlend: 0, recoil: 0, muzzleT: 0,
step: 0, moveBlend: 0, recoil: 0, muzzleT: 0,
animT: 0, attackT: 0, actionT: 0, hitT: 0, deathT: 0,
weapon: { id: 'bonepopper', ammo: Infinity },
holstered: null, // a special weapon set aside while the pistol is out
@@ -76,15 +76,11 @@ function updatePlayer(dt) {
p.x += (mx / len) * spd * dt;
p.y += (my / len) * spd * dt;
p.step += dt * 9 * Math.min(st.speedMul, 1.8);
const stepTick = Math.floor(p.step / Math.PI);
if (stepTick !== p.stepTick && p.hp > 0) Sfx.footstep(p.moveBlend, onGore(p.x, p.y));
p.stepTick = stepTick;
}
else {
// Finish on a planted contact frame instead of freezing halfway through a stride.
const planted = Math.round(p.step / Math.PI) * Math.PI;
p.step = lerp(p.step, planted, clamp(dt * 10, 0, 1));
p.stepTick = Math.round(p.step / Math.PI);
}
p.moveBlend = lerp(p.moveBlend, mx || my ? 1 : 0, clamp(dt * 12, 0, 1));
p.recoil = Math.max(0, p.recoil - dt * 7);
@@ -339,7 +335,7 @@ function hurtPlayer(dmg, ang, attacker) {
addShake(10);
spawnText(p.x, p.y - 20, 'SECOND SKIN', '#e2472f');
addToast('SECOND SKIN', 'you refuse to die — once per floor');
Sfx.shieldUp();
Sfx.revive();
return;
}
p.hp = 0;
+6 -34
View File
@@ -3,12 +3,12 @@ const Sfx = {
ctx: null, master: null, comp: null, glue: null, limiter: null, muted: false,
mixBus: null, musicBus: null, musicMute: null, duckGain: null, saturators: {},
buses: {}, active: [], procedural: [], lastPlayed: new Map(), currentWeaponLoop: null,
footstepN: 0, fleshN: 0, wallN: 0, goreN: 0,
fleshN: 0, wallN: 0, goreN: 0,
lastPunch: -999, lastPunchLevel: 0,
maxVoices: 24,
cooldowns: {
hit: 0.035, crit: 0.07, ricochet: 0.05, wallHit: 0.045, sawHit: 0.09, gem: 0.025,
enemyDie: 0.04, goreBurst: 0.055, footstep: 0.10, lifesteal: 0.12,
enemyDie: 0.04, goreBurst: 0.055, lifesteal: 0.12,
loop_wpnloop_bile: 0.12, loop_wpnloop_cauterizer: 0.12,
loop_wpnloop_redhand: 0.11, loop_wpnloop_spinaltap_charge: 0.12,
},
@@ -302,36 +302,6 @@ const Sfx = {
this.blip(260, .14, 'sine', .2, 180, 'voices');
},
playerDeath() { this.stopAllLoops(); if (this.sample('plr_death', 'voices', null, 1, 'playerDeath')) return; this.thump(80, .65, .7, 25, 'voices'); this.noise(.7, .45, 350, 'voices'); },
footstep(strength, wet) {
if (!this.canPlay('footstep')) return;
this.footstepN = (this.footstepN % 4) + 1;
const dryName = 'plr_step' + this.footstepN;
const wanted = wet ? 'plr_step_wet' + this.footstepN : dryName;
const force = strength === undefined ? 1 : clamp(strength, .55, 1);
const side = this.footstepN % 2 ? .96 : 1.04;
const gain = .66 * force * side;
let sampled = false;
if (typeof SfxBank !== 'undefined' && SfxBank.buffers.has(wanted)) {
this.enforceVoiceLimit();
sampled = SfxBank.play(wanted, this.output('impacts', null), {
gain: gain * rand(.96, 1.04), rate: rand(.965, 1.035),
});
} else if (typeof SfxBank !== 'undefined') {
SfxBank.want(wanted);
// Keep the gait audible while a wet variant is still decoding.
if (wet && SfxBank.buffers.has(dryName)) {
this.enforceVoiceLimit();
sampled = SfxBank.play(dryName, this.output('impacts', null), { gain: gain * .9, rate: rand(.97, 1.03) });
}
}
this.punch(.18 * force * side);
if (!sampled) {
if (wet) {
this.noise(.08, .17 * force, 360, 'impacts');
this.noise(.025, .05 * force, 1500, 'impacts', null, true);
} else this.noise(.055, .13 * force, 420, 'impacts');
}
},
ricochet(pos) { if (this.sample('imp_ricochet', 'impacts', pos, .5, 'ricochet')) return; this.blip(rand(1400, 1900), .045, 'triangle', .12, -500, 'impacts', pos); },
wallHit(pos) {
@@ -376,8 +346,10 @@ const Sfx = {
ammo() { this.ui('ammo', () => { this.click(.14, 1600, 'ui'); this.blip(520, .08, 'square', .12, -80, 'ui'); }); },
weapon() { this.ui('weapon', () => { this.thump(120, .14, .4, 50, 'ui'); this.blip(300, .1, 'square', .25, 200, 'ui'); this.blip(450, .12, 'square', .2, 250, 'ui'); }); },
item() { this.ui('item', () => { this.thump(100, .2, .4, 45, 'ui'); this.blip(350, .15, 'triangle', .3, 150, 'ui'); this.blip(525, .2, 'triangle', .25, 200, 'ui'); }); },
active() { this.thump(140, .22, .5, 60, 'ui'); this.blip(700, .12, 'sawtooth', .28, 500, 'ui'); this.noise(.1, .14, 2400, 'ui', null, true); },
activeEmpty() { this.blip(220, .12, 'square', .18, -90, 'ui'); },
active() { this.ui('active', () => { this.thump(140, .22, .5, 60, 'ui'); this.blip(700, .12, 'sawtooth', .28, 500, 'ui'); this.noise(.1, .14, 2400, 'ui', null, true); }); },
activeEmpty() { this.ui('active_empty', () => this.blip(220, .12, 'square', .18, -90, 'ui')); },
curse() { this.ui('curse', () => { this.thump(60, .5, .5, 30, 'ui'); this.blip(180, .4, 'sawtooth', .22, -60, 'ui'); }); },
revive() { if (this.sample('plr_revive', 'voices', null, .85, 'revive')) return; this.blip(500, .3, 'sine', .25, 300, 'ui'); this.thump(100, .3, .4, 50, 'ui'); },
levelup() { this.ui('levelup', () => { this.blip(400, .12, 'square', .25, 200, 'ui'); setTimeout(() => this.blip(600, .12, 'square', .25, 200, 'ui'), 100); setTimeout(() => this.blip(800, .2, 'square', .25, 200, 'ui'), 200); }); },
perk() { this.ui('perk', () => this.blip(500, .1, 'square', .25, 300, 'ui')); },
menu() { this.ui('menu', () => this.blip(620, .055, 'square', .11, 120, 'ui')); },
+5 -9
View File
@@ -79,6 +79,10 @@ const SfxBank = {
ui_perk: 'ui_perk.mp3',
ui_stairs: 'ui_stairs.mp3',
ui_menu: 'ui_menu.mp3',
ui_active: 'ui_active.mp3',
ui_active_empty: 'ui_active_empty.mp3',
ui_curse: 'ui_curse.mp3',
plr_revive: 'plr_revive.mp3',
imp_crit: 'imp_crit.mp3',
imp_ricochet: 'imp_ricochet.mp3',
@@ -88,14 +92,6 @@ const SfxBank = {
plr_death: 'plr_death.mp3',
plr_shield_break: 'plr_shield_break.mp3',
plr_shield_up: 'plr_shield_up.mp3',
plr_step1: 'plr_step1.mp3',
plr_step2: 'plr_step2.mp3',
plr_step3: 'plr_step3.mp3',
plr_step4: 'plr_step4.mp3',
plr_step_wet1: 'plr_step_wet1.mp3',
plr_step_wet2: 'plr_step_wet2.mp3',
plr_step_wet3: 'plr_step_wet3.mp3',
plr_step_wet4: 'plr_step_wet4.mp3',
imp_flesh1: 'imp_flesh1.mp3',
imp_flesh2: 'imp_flesh2.mp3',
imp_flesh3: 'imp_flesh3.mp3',
@@ -115,7 +111,7 @@ const SfxBank = {
if (this.buffers.has(name) || this.pending.has(name) || this.failed.has(name)) return;
const file = this.FILES[name];
if (!file || !this.ctx || typeof fetch !== 'function') return;
const job = fetch('/assets/sfx/' + encodeURIComponent(file) + '?v=41')
const job = fetch('/assets/sfx/' + encodeURIComponent(file) + '?v=42')
.then(r => { if (!r.ok) throw new Error('HTTP ' + r.status); return r.arrayBuffer(); })
.then(bytes => this.ctx.decodeAudioData(bytes))
.then(buffer => this.buffers.set(name, this.trim(buffer)))
+1 -1
View File
@@ -84,7 +84,7 @@ const Sprites = {
const img = new Image();
img.onload = () => { this.imgs[name] = img; if (--pending === 0) G.imagesLoaded = true; };
img.onerror = () => { if (--pending === 0) G.imagesLoaded = true; };
img.src = 'assets/' + name + '.png?v=41';
img.src = 'assets/' + name + '.png?v=42';
}
},