Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
export PATH="/usr/local/bin:$HOME/.npm-global/bin:$HOME/.nvm/versions/node/$(node -v)/bin:$PATH"

# Then run lint-staged if tests pass
npx lint-staged
npx.cmd lint-staged
Binary file added proprietary/sounds/effects/atom_hit.mp3
Binary file not shown.
Binary file added proprietary/sounds/effects/atom_launch.mp3
Binary file not shown.
Binary file added proprietary/sounds/effects/click.mp3
Binary file not shown.
Binary file added proprietary/sounds/effects/hydrogen_hit.mp3
Binary file not shown.
Binary file not shown.
Binary file added proprietary/sounds/effects/mirv_launch.mp3
Binary file not shown.
19 changes: 15 additions & 4 deletions src/client/ClientGameRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ import {
} from "./Transport";
import { createCanvas } from "./Utils";
import { createRenderer, GameRenderer } from "./graphics/GameRenderer";
import SoundManager from "./sound/SoundManager";
import { SoundLayer } from "./sound/SoundLayer";
import { SoundManager } from "./sound/SoundManager";

export interface LobbyConfig {
serverConfig: ServerConfig;
Expand Down Expand Up @@ -175,7 +176,15 @@ async function createClientGame(
);

const canvas = createCanvas();
const gameRenderer = createRenderer(canvas, gameView, eventBus);
const soundManager = new SoundManager();
const soundLayer = new SoundLayer(gameView, soundManager);
const gameRenderer = createRenderer(
canvas,
gameView,
eventBus,
soundManager,
soundLayer,
);

console.log(
`creating private game got difficulty: ${lobbyConfig.gameStartInfo.config.difficulty}`,
Expand All @@ -189,6 +198,7 @@ async function createClientGame(
transport,
worker,
gameView,
soundManager,
);
}

Expand All @@ -211,6 +221,7 @@ export class ClientGameRunner {
private transport: Transport,
private worker: WorkerClient,
private gameView: GameView,
private soundManager: SoundManager,
) {
this.lastMessageTime = Date.now();
}
Expand Down Expand Up @@ -245,7 +256,7 @@ export class ClientGameRunner {
}

public start() {
SoundManager.playBackgroundMusic();
this.soundManager.playBackgroundMusic();
console.log("starting client game");

this.isActive = true;
Expand Down Expand Up @@ -374,7 +385,7 @@ export class ClientGameRunner {
}

public stop() {
SoundManager.stopBackgroundMusic();
this.soundManager.stopBackgroundMusic();
if (!this.isActive) return;

this.isActive = false;
Expand Down
4 changes: 3 additions & 1 deletion src/client/LocalServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,9 @@ export class LocalServer {
if (!this.lobbyConfig.gameRecord) {
if (clientMsg.turnNumber % 100 === 0) {
// In singleplayer, only store hash every 100 turns to reduce size of game record.
this.turns[clientMsg.turnNumber].hash = clientMsg.hash;
if (this.turns[clientMsg.turnNumber]) {
this.turns[clientMsg.turnNumber].hash = clientMsg.hash;
}
Comment on lines +112 to +114
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this change necessary?

Comment on lines +112 to +114
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this related?

}
return;
}
Expand Down
8 changes: 8 additions & 0 deletions src/client/graphics/GameRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { GameView } from "../../core/game/GameView";
import { UserSettings } from "../../core/game/UserSettings";
import { GameStartingModal } from "../GameStartingModal";
import { RefreshGraphicsEvent as RedrawGraphicsEvent } from "../InputHandler";
import { SoundLayer } from "../sound/SoundLayer";
import { SoundManager } from "../sound/SoundManager";
import { TransformHandler } from "./TransformHandler";
import { UIState } from "./UIState";
import { AlertFrame } from "./layers/AlertFrame";
Expand Down Expand Up @@ -44,6 +46,8 @@ export function createRenderer(
canvas: HTMLCanvasElement,
game: GameView,
eventBus: EventBus,
soundManager: SoundManager,
soundLayer: SoundLayer,
): GameRenderer {
const transformHandler = new TransformHandler(game, eventBus, canvas);
const userSettings = new UserSettings();
Expand Down Expand Up @@ -160,6 +164,7 @@ export function createRenderer(
}
settingsModal.userSettings = userSettings;
settingsModal.eventBus = eventBus;
settingsModal.soundManager = soundManager;

const unitDisplay = document.querySelector("unit-display") as UnitDisplay;
if (!(unitDisplay instanceof UnitDisplay)) {
Expand Down Expand Up @@ -273,6 +278,7 @@ export function createRenderer(
gutterAdModal,
alertFrame,
fpsDisplay,
soundLayer,
];

return new GameRenderer(
Expand All @@ -283,6 +289,7 @@ export function createRenderer(
uiState,
layers,
fpsDisplay,
soundManager,
);
}

Expand All @@ -297,6 +304,7 @@ export class GameRenderer {
public uiState: UIState,
private layers: Layer[],
private fpsDisplay: FPSDisplay,
public soundManager: SoundManager,
) {
const context = canvas.getContext("2d");
if (context === null) throw new Error("2d context not supported");
Expand Down
9 changes: 6 additions & 3 deletions src/client/graphics/layers/FxLayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
RailroadUpdate,
} from "../../../core/game/GameUpdates";
import { GameView, UnitView } from "../../../core/game/GameView";
import SoundManager, { SoundEffect } from "../../sound/SoundManager";

import { renderNumber } from "../../Utils";
import { AnimatedSpriteLoader } from "../AnimatedSpriteLoader";
import { conquestFxFactory } from "../fx/ConquestFx";
Expand All @@ -19,6 +19,7 @@ import { TextFx } from "../fx/TextFx";
import { UnitExplosionFx } from "../fx/UnitExplosionFx";
import { Layer } from "./Layer";
export class FxLayer implements Layer {
private seenNukes: Set<number> = new Set();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this used?

private canvas: HTMLCanvasElement;
private context: CanvasRenderingContext2D;

Expand Down Expand Up @@ -141,6 +142,10 @@ export class FxLayer implements Layer {
break;
}
case UnitType.AtomBomb:
this.onNukeEvent(unit, 70);
break;
case UnitType.MIRV:
break;
Comment on lines +140 to +143
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this related to sounds?

case UnitType.MIRVWarhead:
this.onNukeEvent(unit, 70);
break;
Expand Down Expand Up @@ -217,8 +222,6 @@ export class FxLayer implements Layer {
return;
}

SoundManager.playSoundEffect(SoundEffect.KaChing);

const conquestFx = conquestFxFactory(
this.animatedSpriteLoader,
conquest,
Expand Down
13 changes: 8 additions & 5 deletions src/client/graphics/layers/SettingsModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { UserSettings } from "../../../core/game/UserSettings";
import { AlternateViewEvent, RefreshGraphicsEvent } from "../../InputHandler";
import { PauseGameEvent } from "../../Transport";
import { translateText } from "../../Utils";
import SoundManager from "../../sound/SoundManager";
import { SoundManager } from "../../sound/SoundManager";
import { Layer } from "./Layer";

export class ShowSettingsModalEvent {
Expand All @@ -30,6 +30,7 @@ export class ShowSettingsModalEvent {
export class SettingsModal extends LitElement implements Layer {
public eventBus: EventBus;
public userSettings: UserSettings;
public soundManager: SoundManager;

@state()
private isVisible: boolean = false;
Expand All @@ -47,10 +48,12 @@ export class SettingsModal extends LitElement implements Layer {
wasPausedWhenOpened = false;

init() {
SoundManager.setBackgroundMusicVolume(
this.soundManager.setBackgroundMusicVolume(
this.userSettings.backgroundMusicVolume(),
);
SoundManager.setSoundEffectsVolume(this.userSettings.soundEffectsVolume());
this.soundManager.setSoundEffectsVolume(
this.userSettings.soundEffectsVolume(),
);
this.eventBus.on(ShowSettingsModalEvent, (event) => {
this.isVisible = event.isVisible;
this.shouldPause = event.shouldPause;
Expand Down Expand Up @@ -159,14 +162,14 @@ export class SettingsModal extends LitElement implements Layer {
private onVolumeChange(event: Event) {
const volume = parseFloat((event.target as HTMLInputElement).value) / 100;
this.userSettings.setBackgroundMusicVolume(volume);
SoundManager.setBackgroundMusicVolume(volume);
this.soundManager.setBackgroundMusicVolume(volume);
this.requestUpdate();
}

private onSoundEffectsVolumeChange(event: Event) {
const volume = parseFloat((event.target as HTMLInputElement).value) / 100;
this.userSettings.setSoundEffectsVolume(volume);
SoundManager.setSoundEffectsVolume(volume);
this.soundManager.setSoundEffectsVolume(volume);
this.requestUpdate();
}

Expand Down
99 changes: 99 additions & 0 deletions src/client/sound/SoundLayer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { UnitType } from "../../core/game/Game";
import { GameUpdateType } from "../../core/game/GameUpdates";
import { GameView, UnitView } from "../../core/game/GameView";
import { Layer } from "../graphics/layers/Layer";
import { SoundEffect, SoundManager } from "./SoundManager";

export class SoundLayer implements Layer {
private seenNukes: Set<number> = new Set();

constructor(
private game: GameView,
private soundManager: SoundManager,
) {}

shouldTransform(): boolean {
return false;
}

init(): void {}

tick(): void {
this.game
.updatesSinceLastTick()
?.[GameUpdateType.Unit]?.map((unit) => this.game.unit(unit.id))
?.forEach((unitView) => {
if (unitView === undefined) return;
this.onUnitEvent(unitView);
});
}

onUnitEvent(unit: UnitView) {
const myPlayer = this.game.myPlayer();
if (!myPlayer) return;

const isNuke =
unit.type() === UnitType.AtomBomb ||
unit.type() === UnitType.HydrogenBomb ||
unit.type() === UnitType.MIRV;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return early do:

if(!isNuke) {
return
}

if (isNuke) {
if (!this.seenNukes.has(unit.id())) {
const owner = unit.owner();
const targetTile = unit.targetTile();
const targetPlayer = targetTile
? this.game.playerBySmallID(this.game.ownerID(targetTile))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use this.game.owner(targetTile)

: undefined;

if (owner === myPlayer || targetPlayer === myPlayer) {
let soundEffect: SoundEffect | undefined;
if (unit.type() === UnitType.AtomBomb) {
soundEffect = SoundEffect.AtomLaunch;
} else if (unit.type() === UnitType.HydrogenBomb) {
soundEffect = SoundEffect.HydroLaunch;
} else if (unit.type() === UnitType.MIRV) {
soundEffect = SoundEffect.MirvLaunch;
}

if (soundEffect) {
this.soundManager.playSoundEffect(soundEffect);
}
Comment on lines +48 to +60
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be simplified:

switch(unit.type()) {
case UnitType.AtomBomb:
this.soundManager.playerSoundEffect(SoundEffect.AtomLaunch)

}
this.seenNukes.add(unit.id());
}
}

if (!unit.isActive() && unit.reachedTarget()) {
const isNukeHit =
unit.type() === UnitType.AtomBomb ||
unit.type() === UnitType.HydrogenBomb ||
unit.type() === UnitType.MIRVWarhead;
Comment on lines +67 to +70
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we already have the isNuke variable, reuse that.


if (isNukeHit) {
const owner = unit.owner();
const targetTile = unit.lastTile();
const targetPlayer = this.game.playerBySmallID(
this.game.ownerID(targetTile),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this.game.owner(targetTile)

);

if (owner === myPlayer || targetPlayer === myPlayer) {
let soundEffect: SoundEffect | undefined;
if (unit.type() === UnitType.AtomBomb) {
soundEffect = SoundEffect.AtomHit;
} else if (unit.type() === UnitType.HydrogenBomb) {
soundEffect = SoundEffect.HydroHit;
} else if (unit.type() === UnitType.MIRVWarhead) {
soundEffect = SoundEffect.MirvHit;
}

if (soundEffect) {
this.soundManager.playSoundEffect(soundEffect);
}
}
}
}
}

renderLayer(context: CanvasRenderingContext2D): void {}
redraw(): void {}
}
21 changes: 18 additions & 3 deletions src/client/sound/SoundManager.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
import { Howl } from "howler";
import atomHitSound from "../../../proprietary/sounds/effects/atom_hit.mp3";
import atomLaunchSound from "../../../proprietary/sounds/effects/atom_launch.mp3";
import hydroHitSound from "../../../proprietary/sounds/effects/hydrogen_hit.mp3";
import hydroLaunchSound from "../../../proprietary/sounds/effects/hydrogen_launch.mp3";
import mirvLaunchSound from "../../../proprietary/sounds/effects/mirv_launch.mp3";
import of4 from "../../../proprietary/sounds/music/of4.mp3";
import openfront from "../../../proprietary/sounds/music/openfront.mp3";
import war from "../../../proprietary/sounds/music/war.mp3";
import kaChingSound from "../../../resources/sounds/effects/ka-ching.mp3";

export enum SoundEffect {
KaChing = "ka-ching",
AtomLaunch = "atom_launch",
AtomHit = "atom_hit",
HydroLaunch = "hydro_launch",
HydroHit = "hydro_hit",
MirvHit = "mirv_hit",
MirvLaunch = "mirv_launch",
}
Comment on lines 12 to 20
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should try to avoid enums, instead do:

export const SoundEffect = {
KaChing: "ka-ching",
AtomLaunch: "atom_launch",
AtomHit: "atom_hit",
HydroLaunch: "hydro_launch",
HydroHit: "hydro_hit",
MirvHit: "mirv_hit",
MirvLaunch: "mirv_launch",
} as const;

export type SoundEffect = typeof SoundEffect[keyof typeof SoundEffect];


class SoundManager {
export class SoundManager {
private backgroundMusic: Howl[] = [];
private currentTrack: number = 0;
private soundEffects: Map<SoundEffect, Howl> = new Map();
Expand Down Expand Up @@ -37,6 +48,12 @@ class SoundManager {
}),
];
this.loadSoundEffect(SoundEffect.KaChing, kaChingSound);
this.loadSoundEffect(SoundEffect.AtomLaunch, atomLaunchSound);
this.loadSoundEffect(SoundEffect.AtomHit, atomHitSound);
this.loadSoundEffect(SoundEffect.HydroLaunch, hydroLaunchSound);
this.loadSoundEffect(SoundEffect.HydroHit, hydroHitSound);
this.loadSoundEffect(SoundEffect.MirvHit, atomHitSound);
this.loadSoundEffect(SoundEffect.MirvLaunch, mirvLaunchSound);
}

public playBackgroundMusic(): void {
Expand Down Expand Up @@ -105,5 +122,3 @@ class SoundManager {
}
}
}

export default new SoundManager();
Loading