mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 06:10:42 +00:00
MUSIC (#2090)
## Description: add music to the game Describe the PR. add music <img width="549" height="770" alt="image" src="https://github.com/user-attachments/assets/d8457d85-6f63-4024-8b69-572f8c9bb225" /> ## Please complete the following: - [X] I have added screenshots for all UI updates - [X] I process any text displayed to the user through translateText() and I've added it to the en.json file - [X] I have added relevant tests to the test directory - [X] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: Lucas
This commit is contained in:
Generated
+15
-2
@@ -25,6 +25,7 @@
|
||||
"express": "^4.21.1",
|
||||
"express-rate-limit": "^7.5.0",
|
||||
"fastpriorityqueue": "^0.7.5",
|
||||
"howler": "^2.2.4",
|
||||
"intl-messageformat": "^10.7.16",
|
||||
"ip-anonymize": "^0.1.0",
|
||||
"jose": "^6.0.10",
|
||||
@@ -52,6 +53,7 @@
|
||||
"@types/express": "^4.17.23",
|
||||
"@types/google-protobuf": "^3.15.12",
|
||||
"@types/hammerjs": "^2.0.46",
|
||||
"@types/howler": "^2.2.12",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/jquery": "^3.5.31",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
@@ -7131,6 +7133,13 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/howler": {
|
||||
"version": "2.2.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/howler/-/howler-2.2.12.tgz",
|
||||
"integrity": "sha512-hy769UICzOSdK0Kn1FBk4gN+lswcj1EKRkmiDtMkUGvFfYJzgaDXmVXkSShS2m89ERAatGIPnTUlp2HhfkVo5g==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/html-minifier-terser": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz",
|
||||
@@ -9509,7 +9518,6 @@
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz",
|
||||
"integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
@@ -12292,6 +12300,12 @@
|
||||
"he": "bin/he"
|
||||
}
|
||||
},
|
||||
"node_modules/howler": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/howler/-/howler-2.2.4.tgz",
|
||||
"integrity": "sha512-iARIBPgcQrwtEr+tALF+rapJ8qSc+Set2GJQl7xT1MQzWaVkFebdJhR3alVlSiUf5U7nAANKuj3aWpwerocD5w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/hpack.js": {
|
||||
"version": "2.1.6",
|
||||
"resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz",
|
||||
@@ -16221,7 +16235,6 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
|
||||
"integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
"@types/express": "^4.17.23",
|
||||
"@types/google-protobuf": "^3.15.12",
|
||||
"@types/hammerjs": "^2.0.46",
|
||||
"@types/howler": "^2.2.12",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/jquery": "^3.5.31",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
@@ -119,6 +120,7 @@
|
||||
"express": "^4.21.1",
|
||||
"express-rate-limit": "^7.5.0",
|
||||
"fastpriorityqueue": "^0.7.5",
|
||||
"howler": "^2.2.4",
|
||||
"intl-messageformat": "^10.7.16",
|
||||
"ip-anonymize": "^0.1.0",
|
||||
"jose": "^6.0.10",
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 122.88 91.69" style="enable-background:new 0 0 122.88 91.69" xml:space="preserve"><style type="text/css"><![CDATA[
|
||||
.st0{fill-rule:evenodd;clip-rule:evenodd;}
|
||||
]]></style><g><path class="st0" d="M49.58,0h11.34v3.79c28.37,6.5,31.61,20.12,15.16,41.59c1.75-21.3-0.4-25.87-15.16-26.86v53.86 c0.03,0.29,0.04,0.57,0.04,0.86c0,7-7.35,13.94-16.4,15.51c-9.06,1.57-16.4-2.84-16.4-9.84c0-9.55,13.12-17.84,21.43-14.92L49.58,0 L49.58,0L49.58,0z M72.31,91.69h-0.16c0-1.29-0.48-2.41-1.44-3.38c-0.96-0.96-2.09-1.44-3.38-1.44v-0.16 c1.29,0,2.41-0.48,3.38-1.44c0.96-0.97,1.44-2.09,1.44-3.37h0.16c0,1.29,0.48,2.41,1.44,3.37c0.96,0.96,2.09,1.44,3.38,1.44v0.16 c-1.29,0-2.41,0.48-3.38,1.44C72.79,89.27,72.31,90.4,72.31,91.69L72.31,91.69L72.31,91.69z M92.53,74.61l-0.4-0.03 c0.24-3.22-0.75-6.13-2.97-8.72s-4.94-4.01-8.17-4.25l0.03-0.4c3.22,0.25,6.13-0.75,8.72-2.97c2.59-2.23,4.01-4.95,4.25-8.16 l0.4,0.03c-0.24,3.22,0.75,6.13,2.97,8.72s4.94,4.01,8.17,4.25l-0.03,0.4c-3.22-0.25-6.13,0.75-8.72,2.97 C94.19,68.67,92.78,71.39,92.53,74.61L92.53,74.61L92.53,74.61z M109.33,42.87l-0.5,0.06c-0.52-4.13-2.51-7.55-5.99-10.26 c-3.47-2.71-7.28-3.8-11.42-3.29l-0.06-0.5c4.13-0.51,7.55-2.51,10.26-5.99s3.8-7.29,3.29-11.41l0.5-0.06 c0.52,4.13,2.51,7.55,5.99,10.26c3.48,2.71,7.28,3.8,11.42,3.29l0.06,0.5c-4.13,0.52-7.55,2.51-10.26,5.99 C109.91,34.93,108.82,38.74,109.33,42.87L109.33,42.87L109.33,42.87z M18.45,54.03c-2.3,0-4.17-1.87-4.17-4.17s1.87-4.17,4.17-4.17 h16.63c2.3,0,4.17,1.87,4.17,4.17s-1.87,4.17-4.17,4.17H18.45L18.45,54.03L18.45,54.03z M10.57,33.79c-2.3,0-4.17-1.87-4.17-4.17 c0-2.3,1.87-4.17,4.17-4.17h24.52c2.3,0,4.17,1.87,4.17,4.17c0,2.3-1.87,4.17-4.17,4.17H3.67L10.57,33.79L10.57,33.79z M4.17,13.55 C1.87,13.55,0,11.68,0,9.37c0-2.3,1.87-4.17,4.17-4.17h30.92c2.3,0,4.17,1.87,4.17,4.17c0,2.3-1.87,4.17-4.17,4.17L4.17,13.55 L4.17,13.55L4.17,13.55z" fill="#ffffff"/></g></svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
@@ -360,7 +360,8 @@
|
||||
"terrain_enabled": "Terrain view enabled",
|
||||
"terrain_disabled": "Terrain view disabled",
|
||||
"exit_game_label": "Exit Game",
|
||||
"exit_game_info": "Return to main menu"
|
||||
"exit_game_info": "Return to main menu",
|
||||
"background_music_volume": "Background Music Volume"
|
||||
},
|
||||
"chat": {
|
||||
"title": "Quick Chat",
|
||||
|
||||
@@ -47,6 +47,7 @@ import {
|
||||
} from "./Transport";
|
||||
import { createCanvas } from "./Utils";
|
||||
import { createRenderer, GameRenderer } from "./graphics/GameRenderer";
|
||||
import SoundManager from "./sound/SoundManager";
|
||||
|
||||
export interface LobbyConfig {
|
||||
serverConfig: ServerConfig;
|
||||
@@ -245,6 +246,7 @@ export class ClientGameRunner {
|
||||
}
|
||||
|
||||
public start() {
|
||||
SoundManager.playBackgroundMusic();
|
||||
console.log("starting client game");
|
||||
|
||||
this.isActive = true;
|
||||
@@ -372,6 +374,7 @@ export class ClientGameRunner {
|
||||
}
|
||||
|
||||
public stop() {
|
||||
SoundManager.stopBackgroundMusic();
|
||||
if (!this.isActive) return;
|
||||
|
||||
this.isActive = false;
|
||||
|
||||
@@ -9,11 +9,13 @@ import mouseIcon from "../../../../resources/images/MouseIconWhite.svg";
|
||||
import ninjaIcon from "../../../../resources/images/NinjaIconWhite.svg";
|
||||
import settingsIcon from "../../../../resources/images/SettingIconWhite.svg";
|
||||
import treeIcon from "../../../../resources/images/TreeIconWhite.svg";
|
||||
import musicIcon from "../../../../resources/images/music.svg";
|
||||
import { EventBus } from "../../../core/EventBus";
|
||||
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 { Layer } from "./Layer";
|
||||
|
||||
export class ShowSettingsModalEvent {
|
||||
@@ -45,6 +47,9 @@ export class SettingsModal extends LitElement implements Layer {
|
||||
wasPausedWhenOpened = false;
|
||||
|
||||
init() {
|
||||
SoundManager.setBackgroundMusicVolume(
|
||||
this.userSettings.backgroundMusicVolume(),
|
||||
);
|
||||
this.eventBus.on(ShowSettingsModalEvent, (event) => {
|
||||
this.isVisible = event.isVisible;
|
||||
this.shouldPause = event.shouldPause;
|
||||
@@ -150,6 +155,13 @@ export class SettingsModal extends LitElement implements Layer {
|
||||
window.location.href = "/";
|
||||
}
|
||||
|
||||
private onVolumeChange(event: Event) {
|
||||
const volume = parseFloat((event.target as HTMLInputElement).value) / 100;
|
||||
this.userSettings.setBackgroundMusicVolume(volume);
|
||||
SoundManager.setBackgroundMusicVolume(volume);
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.isVisible) {
|
||||
return null;
|
||||
@@ -187,6 +199,28 @@ export class SettingsModal extends LitElement implements Layer {
|
||||
</div>
|
||||
|
||||
<div class="p-4 space-y-3">
|
||||
<div
|
||||
class="flex gap-3 items-center w-full text-left p-3 hover:bg-slate-700 rounded text-white transition-colors"
|
||||
>
|
||||
<img src=${musicIcon} alt="musicIcon" width="20" height="20" />
|
||||
<div class="flex-1">
|
||||
<div class="font-medium">
|
||||
${translateText("user_setting.background_music_volume")}
|
||||
</div>
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="100"
|
||||
.value=${this.userSettings.backgroundMusicVolume() * 100}
|
||||
@input=${this.onVolumeChange}
|
||||
class="w-full border border-slate-500 rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${Math.round(this.userSettings.backgroundMusicVolume() * 100)}%
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="flex gap-3 items-center w-full text-left p-3 hover:bg-slate-700 rounded text-white transition-colors"
|
||||
@click="${this.onTerrainButtonClick}"
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import { Howl, Howler } from "howler";
|
||||
import of4 from "../../../proprietary/sounds/music/of4.mp3";
|
||||
import openfront from "../../../proprietary/sounds/music/openfront.mp3";
|
||||
import war from "../../../proprietary/sounds/music/war.mp3";
|
||||
class SoundManager {
|
||||
private backgroundMusic: Howl[] = [];
|
||||
private currentTrack: number = 0;
|
||||
|
||||
constructor() {
|
||||
this.backgroundMusic = [
|
||||
new Howl({ src: [of4], loop: false, onend: this.playNext.bind(this) }),
|
||||
new Howl({
|
||||
src: [openfront],
|
||||
loop: false,
|
||||
onend: this.playNext.bind(this),
|
||||
}),
|
||||
new Howl({ src: [war], loop: false, onend: this.playNext.bind(this) }),
|
||||
];
|
||||
this.setBackgroundMusicVolume(0);
|
||||
}
|
||||
|
||||
public playBackgroundMusic(): void {
|
||||
if (
|
||||
this.backgroundMusic.length > 0 &&
|
||||
!this.backgroundMusic[this.currentTrack].playing()
|
||||
) {
|
||||
this.backgroundMusic[this.currentTrack].play();
|
||||
}
|
||||
}
|
||||
|
||||
public stopBackgroundMusic(): void {
|
||||
if (this.backgroundMusic.length > 0) {
|
||||
this.backgroundMusic[this.currentTrack].stop();
|
||||
}
|
||||
}
|
||||
|
||||
public setBackgroundMusicVolume(volume: number): void {
|
||||
const newVolume = Math.max(0, Math.min(1, volume));
|
||||
Howler.volume(newVolume);
|
||||
}
|
||||
|
||||
private playNext(): void {
|
||||
this.currentTrack = (this.currentTrack + 1) % this.backgroundMusic.length;
|
||||
this.playBackgroundMusic();
|
||||
}
|
||||
}
|
||||
|
||||
export default new SoundManager();
|
||||
@@ -19,6 +19,20 @@ export class UserSettings {
|
||||
localStorage.setItem(key, value ? "true" : "false");
|
||||
}
|
||||
|
||||
getFloat(key: string, defaultValue: number): number {
|
||||
const value = localStorage.getItem(key);
|
||||
if (!value) return defaultValue;
|
||||
|
||||
const floatValue = parseFloat(value);
|
||||
if (isNaN(floatValue)) return defaultValue;
|
||||
|
||||
return floatValue;
|
||||
}
|
||||
|
||||
setFloat(key: string, value: number) {
|
||||
localStorage.setItem(key, value.toString());
|
||||
}
|
||||
|
||||
emojis() {
|
||||
return this.get("settings.emojis", true);
|
||||
}
|
||||
@@ -154,4 +168,12 @@ export class UserSettings {
|
||||
localStorage.setItem(PATTERN_KEY, patternName);
|
||||
}
|
||||
}
|
||||
|
||||
backgroundMusicVolume(): number {
|
||||
return this.getFloat("settings.backgroundMusicVolume", 0);
|
||||
}
|
||||
|
||||
setBackgroundMusicVolume(volume: number): void {
|
||||
this.setFloat("settings.backgroundMusicVolume", volume);
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+5
@@ -40,3 +40,8 @@ declare module "*.xml" {
|
||||
const value: string;
|
||||
export default value;
|
||||
}
|
||||
|
||||
declare module "*.mp3" {
|
||||
const value: string;
|
||||
export default value;
|
||||
}
|
||||
|
||||
@@ -93,6 +93,13 @@ export default async (env, argv) => {
|
||||
filename: "fonts/[name].[contenthash][ext]", // Added content hash and fixed path
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.(mp3|wav|ogg)$/i,
|
||||
type: "asset/resource",
|
||||
generator: {
|
||||
filename: "sounds/[name].[contenthash][ext]",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
|
||||
Reference in New Issue
Block a user