Add SoundEffectController to restore v31 sound effects

Ports the sound-emission logic from v31's deleted FxLayer into a new
controller registered with the game renderer. Per-tick it scans the
worker's update stream and emits PlaySoundEffectEvent for unit launches,
nuke detonations, structure/warship builds (local player only), and
conquests where the local player is the conqueror.
This commit is contained in:
evanpelle
2026-06-03 20:43:12 -07:00
parent 9c2ac05506
commit 88697955b7
2 changed files with 89 additions and 0 deletions
@@ -0,0 +1,87 @@
import { EventBus } from "../../core/EventBus";
import { UnitType } from "../../core/game/Game";
import { GameUpdateType } from "../../core/game/GameUpdates";
import { GameView, UnitView } from "../../core/game/GameView";
import { Controller } from "../Controller";
import { PlaySoundEffectEvent, SoundEffect } from "../sound/Sounds";
export class SoundEffectController implements Controller {
constructor(
private readonly game: GameView,
private readonly eventBus: EventBus,
) {}
tick(): void {
const updates = this.game.updatesSinceLastTick();
if (!updates) return;
for (const u of updates[GameUpdateType.Unit] ?? []) {
const unit = this.game.unit(u.id);
if (unit === undefined) continue;
this.handleUnit(unit);
}
const myPlayer = this.game.myPlayer();
if (myPlayer === null) return;
for (const c of updates[GameUpdateType.ConquestEvent] ?? []) {
if (c.conquerorId === myPlayer.id()) {
this.emit("ka-ching");
}
}
}
private handleUnit(unit: UnitView): void {
if (unit.isActive() && unit.createdAt() === this.game.ticks()) {
this.onCreated(unit);
}
switch (unit.type()) {
case UnitType.AtomBomb:
case UnitType.MIRVWarhead:
this.onNukeDetonation(unit, "atom-hit");
break;
case UnitType.HydrogenBomb:
this.onNukeDetonation(unit, "hydrogen-hit");
break;
}
}
private onCreated(unit: UnitView): void {
const myPlayer = this.game.myPlayer();
switch (unit.type()) {
case UnitType.AtomBomb:
this.emit("atom-launch");
break;
case UnitType.HydrogenBomb:
this.emit("hydrogen-launch");
break;
case UnitType.MIRV:
this.emit("mirv-launch");
break;
case UnitType.Warship:
if (unit.owner() === myPlayer) this.emit("build-warship");
break;
case UnitType.City:
if (unit.owner() === myPlayer) this.emit("build-city");
break;
case UnitType.Port:
if (unit.owner() === myPlayer) this.emit("build-port");
break;
case UnitType.DefensePost:
if (unit.owner() === myPlayer) this.emit("build-defense-post");
break;
case UnitType.SAMLauncher:
if (unit.owner() === myPlayer) this.emit("sam-built");
break;
}
}
private onNukeDetonation(unit: UnitView, sound: SoundEffect): void {
if (unit.isActive()) return;
if (!unit.reachedTarget()) return;
this.emit(sound);
}
private emit(sound: SoundEffect): void {
this.eventBus.emit(new PlaySoundEffectEvent(sound));
}
}
+2
View File
@@ -8,6 +8,7 @@ import { UIState } from "../UIState";
import { AttackingTroopsController } from "../controllers/AttackingTroopsController";
import { BuildPreviewController } from "../controllers/BuildPreviewController";
import { HoverHighlightController } from "../controllers/HoverHighlightController";
import { SoundEffectController } from "../controllers/SoundEffectController";
import { StructureHighlightController } from "../controllers/StructureHighlightController";
import { ViewModeController } from "../controllers/ViewModeController";
import { WarshipSelectionController } from "../controllers/WarshipSelectionController";
@@ -294,6 +295,7 @@ export function createRenderer(
new StructureHighlightController(eventBus, view),
new ViewModeController(eventBus, view),
new AttackingTroopsController(game, eventBus, userSettings, view),
new SoundEffectController(game, eventBus),
eventsDisplay,
actionableEvents,
attacksDisplay,