SoundBoard

Play sounds when specific chat messages are received

  1. // ==UserScript==
  2. // @name SoundBoard
  3. // @version 1.4.0
  4. // @description Play sounds when specific chat messages are received
  5. // @author FeiFei
  6. // @match https://bonk.io/gameframe-release.html
  7. // @run-at document-end
  8. // @grant none
  9. // @namespace https://greasyfork.org/users/1366475
  10. // ==/UserScript==
  11.  
  12. "use strict";
  13.  
  14. let soundBoard = {};
  15.  
  16. soundBoard.windowConfigs = {
  17. windowName: "SoundBoard",
  18. windowId: "soundBoard_window",
  19. modVersion: "1.4.0",
  20. bonkLIBVersion: "1.1.3",
  21. bonkVersion: "49",
  22. windowContent: null,
  23. settingsContent: null,
  24. };
  25.  
  26. // Initialize global mute state
  27. soundBoard.globalMute = false;
  28. soundBoard.modIndex = null;
  29. soundBoard.windowContentElement = null;
  30. soundBoard.settingsContentElement = null;
  31.  
  32. // Define the sounds and their corresponding messages and audio URLs
  33. soundBoard.sounds = [
  34. {
  35. name: "a",
  36. triggerMessage: "a",
  37. audioUrl: "https://www.myinstants.com/media/sounds/gawr-gura-a.mp3",
  38. enabled: true, // default enabled
  39. },
  40. // *Add more sounds here if needed
  41. ];
  42.  
  43. soundBoard.setWindowContent = function () {
  44. let windowHTML = document.createElement("div");
  45. // !Maybe dont need this
  46. windowHTML.id = soundBoard.windowConfigs.windowId; // Unique ID for scoping
  47. windowHTML.classList.add("bonkhud-background-color");
  48. // Create the global mute toggle button
  49. let muteButton = document.createElement("button");
  50. muteButton.id = "muteButton";
  51. muteButton.textContent = this.globalMute ? "🔇" : "🔊";
  52. muteButton.title = this.globalMute ? "Unmute" : "Mute";
  53. muteButton.classList.add("bonkhud-text-color"); // Apply text color
  54. muteButton.addEventListener("click", () => {
  55. this.globalMute = !this.globalMute;
  56. muteButton.textContent = this.globalMute ? "🔇" : "🔊";
  57. muteButton.title = this.globalMute ? "Unmute" : "Mute";
  58. // Save the global mute setting
  59. this.saveSettings();
  60. });
  61. windowHTML.appendChild(muteButton);
  62.  
  63. // Create the list of sounds
  64. let soundList = document.createElement("div");
  65. soundList.id = "soundList";
  66.  
  67. this.sounds.forEach((sound, index) => {
  68. let soundDiv = document.createElement("div");
  69. soundDiv.className = "sound-item bonkhud-border-color"; // Apply border color
  70.  
  71. let soundName = document.createElement("span");
  72. soundName.className = "sound-name bonkhud-text-color"; // Apply text color
  73. soundName.textContent = sound.name;
  74. soundName.title = sound.triggerMessage;
  75.  
  76. // Create the checkbox input
  77. let checkbox = document.createElement("input");
  78. checkbox.type = "checkbox";
  79. checkbox.id = `checkbox_${index}`;
  80. checkbox.checked = sound.enabled;
  81.  
  82. // Create the label for the checkbox
  83. let label = document.createElement("label");
  84. label.htmlFor = `checkbox_${index}`;
  85. label.className = "soundBoardToggle bonkhud-button-color"; // Apply button color
  86.  
  87. // Event listener to update the sound enabled state
  88. checkbox.addEventListener("change", () => {
  89. sound.enabled = checkbox.checked;
  90. // Save the settings
  91. this.saveSettings();
  92. });
  93.  
  94. // Create a container for the toggle switch
  95. let toggleContainer = document.createElement("div");
  96. toggleContainer.style.display = "flex";
  97. toggleContainer.style.alignItems = "center";
  98.  
  99. toggleContainer.appendChild(checkbox);
  100. toggleContainer.appendChild(label);
  101.  
  102. soundDiv.appendChild(soundName);
  103. soundDiv.appendChild(toggleContainer);
  104.  
  105. soundList.appendChild(soundDiv);
  106. });
  107.  
  108. windowHTML.appendChild(soundList);
  109.  
  110. // Add to windowContent
  111. this.windowConfigs.windowContent = windowHTML;
  112.  
  113. // Store a reference to the window content element
  114. this.windowContentElement = windowHTML;
  115. };
  116.  
  117. soundBoard.setSettingsContent = function () {
  118. let settingsHTML = document.createElement("div");
  119. settingsHTML.className = "settings-container bonkhud-background-color"; // Apply background color
  120. // Create the list of sounds with delete buttons
  121. let soundList = document.createElement("div");
  122. soundList.id = "settingsSoundList";
  123.  
  124. this.sounds.forEach((sound, index) => {
  125. let soundDiv = document.createElement("div");
  126. soundDiv.className = "settings-sound-item bonkhud-border-color"; // Apply border color
  127.  
  128. let soundInfo = document.createElement("span");
  129. soundInfo.className = "settings-sound-info bonkhud-text-color"; // Apply text color
  130. soundInfo.textContent = `${sound.name} | Trigger: "${sound.triggerMessage}" | URL: ${sound.audioUrl}`;
  131.  
  132. let deleteButton = document.createElement("button");
  133. deleteButton.className = "delete-button bonkhud-button-color"; // Apply button color
  134. deleteButton.textContent = "Delete";
  135. deleteButton.addEventListener("mouseover", () => {
  136. deleteButton.classList.add("bonkhud-button-color-hover");
  137. });
  138. deleteButton.addEventListener("mouseout", () => {
  139. deleteButton.classList.remove("bonkhud-button-color-hover");
  140. });
  141. deleteButton.addEventListener("click", () => {
  142. // Remove the sound from the list
  143. this.sounds.splice(index, 1);
  144. // Save settings
  145. this.saveSettings();
  146. // Update the settings content
  147. this.updateSettingsContent();
  148. // Update the window content
  149. this.updateWindowContent();
  150. });
  151.  
  152. soundDiv.appendChild(soundInfo);
  153. soundDiv.appendChild(deleteButton);
  154.  
  155. soundList.appendChild(soundDiv);
  156. });
  157.  
  158. settingsHTML.appendChild(soundList);
  159.  
  160. // Create GUI for importing new sounds
  161. let importDiv = document.createElement("div");
  162. importDiv.className = "import-div";
  163. importDiv.style.marginTop = "10px";
  164.  
  165. let nameInput = document.createElement("input");
  166. nameInput.type = "text";
  167. nameInput.placeholder = "Sound Name";
  168. nameInput.classList.add("bonkhud-text-color", "bonkhud-background-color"); // Apply text and background color
  169.  
  170. let triggerInput = document.createElement("input");
  171. triggerInput.type = "text";
  172. triggerInput.placeholder = "Trigger Message";
  173. triggerInput.classList.add("bonkhud-text-color", "bonkhud-background-color");
  174.  
  175. let urlInput = document.createElement("input");
  176. urlInput.type = "text";
  177. urlInput.placeholder = "Audio URL";
  178. urlInput.classList.add("bonkhud-text-color", "bonkhud-background-color");
  179.  
  180. let addButton = document.createElement("button");
  181. addButton.className = "add-button bonkhud-button-color"; // Apply button color
  182. addButton.textContent = "Add Sound";
  183. addButton.addEventListener("click", () => {
  184. let name = nameInput.value.trim();
  185. let triggerMessage = triggerInput.value.trim();
  186. let audioUrl = urlInput.value.trim();
  187.  
  188. if (name && triggerMessage && audioUrl) {
  189. this.sounds.push({
  190. name: name,
  191. triggerMessage: triggerMessage,
  192. audioUrl: audioUrl,
  193. enabled: true
  194. });
  195. // Save settings
  196. this.saveSettings();
  197. // Update the settings content
  198. this.updateSettingsContent();
  199. // Update the window content
  200. this.updateWindowContent();
  201. // Clear inputs
  202. nameInput.value = '';
  203. triggerInput.value = '';
  204. urlInput.value = '';
  205. } else {
  206. alert("Please fill in all fields.");
  207. }
  208. });
  209.  
  210. importDiv.appendChild(nameInput);
  211. importDiv.appendChild(triggerInput);
  212. importDiv.appendChild(urlInput);
  213. importDiv.appendChild(addButton);
  214.  
  215. settingsHTML.appendChild(importDiv);
  216.  
  217. // Add to settingsContent
  218. this.windowConfigs.settingsContent = settingsHTML;
  219.  
  220. // Store a reference to the settings content element
  221. this.settingsContentElement = settingsHTML;
  222. };
  223.  
  224. // Create the mod window using BonkHUD
  225. soundBoard.createWindow = function () {
  226. // Create the window using BonkHUD
  227. const modIndex = bonkHUD.createMod(this.windowConfigs.windowName, this.windowConfigs);
  228. this.modIndex = modIndex; // Store the mod index just in case
  229. // Load UI settings if available
  230. bonkHUD.loadUISetting(modIndex);
  231. };
  232.  
  233. // Function to add custom styles
  234. soundBoard.addStyles = function() {
  235. const css = `
  236. /* Scoped Styles for SoundBoard Mod */
  237. #soundBoard_window {
  238. font-family: Poppins;
  239. padding: 10px;
  240. }
  241. #soundBoard_window #muteButton {
  242. background-color: transparent;
  243. border: none;
  244. font-size: 24px;
  245. cursor: pointer;
  246. margin-bottom: 10px;
  247. }
  248. #soundBoard_window .sound-item {
  249. display: flex;
  250. justify-content: space-between;
  251. align-items: center;
  252. padding: 5px 0;
  253. border-bottom: 1px solid;
  254. }
  255. #soundBoard_window .sound-item:last-child {
  256. border-bottom: none;
  257. }
  258. #soundBoard_window .sound-name {
  259. flex-grow: 1;
  260. font-size: 16px;
  261. }
  262. #soundBoard_window .soundBoardToggle {
  263. position: relative;
  264. width: 40px;
  265. height: 20px;
  266. border-radius: 20px;
  267. cursor: pointer;
  268. transition: background-color 0.2s;
  269. }
  270. #soundBoard_window .soundBoardToggle::before {
  271. content: '';
  272. position: absolute;
  273. width: 18px;
  274. height: 18px;
  275. left: 1px;
  276. top: 1px;
  277. background-color: #fff;
  278. border-radius: 18px;
  279. transition: transform 0.2s;
  280. }
  281. #soundBoard_window input[type="checkbox"]:checked + .soundBoardToggle::before {
  282. transform: translateX(20px);
  283. }
  284. #soundBoard_window input[type="checkbox"] {
  285. display: none;
  286. }
  287. /* Style the Settings Content */
  288. #soundBoardModContainer .settings-container {
  289. margin-top: 15px;
  290. }
  291. #soundBoardModContainer .settings-sound-item {
  292. display: flex;
  293. justify-content: space-between;
  294. align-items: center;
  295. padding: 5px 0;
  296. border-bottom: 1px solid;
  297. }
  298. #soundBoardModContainer .settings-sound-item:last-child {
  299. border-bottom: none;
  300. }
  301. #soundBoardModContainer .settings-sound-info {
  302. flex-grow: 1;
  303. font-size: 14px;
  304. }
  305. /* Style the Input Fields and Add Button */
  306. #soundBoardModContainer .import-div {
  307. margin-top: 15px;
  308. }
  309. #soundBoardModContainer .import-div input[type="text"] {
  310. width: calc(33% - 10px);
  311. padding: 5px;
  312. margin-right: 5px;
  313. border-radius: 4px;
  314. }
  315. #soundBoardModContainer .import-div input[type="text"]:last-of-type {
  316. margin-right: 0;
  317. }
  318. `;
  319. let style = document.createElement('style');
  320. style.innerHTML = css;
  321. document.head.appendChild(style);
  322. };
  323.  
  324. soundBoard.updateWindowContent = function () {
  325. let soundList = this.windowContentElement.querySelector('#soundList');
  326. if (soundList) {
  327. // Clear existing content
  328. soundList.innerHTML = '';
  329.  
  330. // Re-create the list of sounds
  331. this.sounds.forEach((sound, index) => {
  332. let soundDiv = document.createElement("div");
  333. soundDiv.className = "sound-item bonkhud-border-color"; // Apply border color
  334.  
  335. let soundName = document.createElement("span");
  336. soundName.className = "sound-name bonkhud-text-color"; // Apply text color
  337. soundName.textContent = sound.name;
  338. soundName.title = sound.triggerMessage;
  339.  
  340. // Create the checkbox input
  341. let checkbox = document.createElement("input");
  342. checkbox.type = "checkbox";
  343. checkbox.id = `checkbox_${index}`;
  344. checkbox.checked = sound.enabled;
  345.  
  346. // Create the label for the checkbox
  347. let label = document.createElement("label");
  348. label.htmlFor = `checkbox_${index}`;
  349. label.className = "soundBoardToggle bonkhud-button-color"; // Apply button color
  350.  
  351. // Event listener to update the sound enabled state
  352. checkbox.addEventListener("change", () => {
  353. sound.enabled = checkbox.checked;
  354. // Save the settings
  355. this.saveSettings();
  356. });
  357.  
  358. // Create a container for the toggle switch
  359. let toggleContainer = document.createElement("div");
  360. toggleContainer.style.display = "flex";
  361. toggleContainer.style.alignItems = "center";
  362.  
  363. toggleContainer.appendChild(checkbox);
  364. toggleContainer.appendChild(label);
  365.  
  366. soundDiv.appendChild(soundName);
  367. soundDiv.appendChild(toggleContainer);
  368.  
  369. soundList.appendChild(soundDiv);
  370. });
  371. bonkHUD.updateStyleSettings();
  372. }
  373. };
  374.  
  375. soundBoard.updateSettingsContent = function () {
  376. let soundList = this.settingsContentElement.querySelector('#settingsSoundList');
  377. if (soundList) {
  378. // Clear existing content
  379. soundList.innerHTML = '';
  380.  
  381. // Re-create the list of sounds with delete buttons
  382. this.sounds.forEach((sound, index) => {
  383. let soundDiv = document.createElement("div");
  384. soundDiv.className = "settings-sound-item bonkhud-border-color"; // Apply border color
  385.  
  386. let soundInfo = document.createElement("span");
  387. soundInfo.className = "settings-sound-info bonkhud-text-color"; // Apply text color
  388. soundInfo.textContent = `${sound.name} | Trigger: "${sound.triggerMessage}" | URL: ${sound.audioUrl}`;
  389.  
  390. let deleteButton = document.createElement("button");
  391. deleteButton.className = "delete-button bonkhud-button-color"; // Apply button color
  392. deleteButton.textContent = "Delete";
  393. deleteButton.addEventListener("mouseover", () => {
  394. deleteButton.classList.add("bonkhud-button-color-hover");
  395. });
  396. deleteButton.addEventListener("mouseout", () => {
  397. deleteButton.classList.remove("bonkhud-button-color-hover");
  398. });
  399. deleteButton.addEventListener("click", () => {
  400. // Remove the sound from the list
  401. this.sounds.splice(index, 1);
  402. // Save settings
  403. this.saveSettings();
  404. // Update the settings content
  405. this.updateSettingsContent();
  406. // Update the window content
  407. this.updateWindowContent();
  408. });
  409.  
  410. soundDiv.appendChild(soundInfo);
  411. soundDiv.appendChild(deleteButton);
  412.  
  413. soundList.appendChild(soundDiv);
  414. });
  415. bonkHUD.updateStyleSettings();
  416. }
  417. };
  418.  
  419. // Function to save settings to localStorage
  420. soundBoard.saveSettings = function () {
  421. let settings = {
  422. globalMute: this.globalMute,
  423. sounds: this.sounds,
  424. };
  425. localStorage.setItem('bonkHUD_Mod_Setting_SoundBoard', JSON.stringify(settings));
  426. };
  427.  
  428. // Function to load settings from localStorage
  429. soundBoard.loadSettings = function () {
  430. let savedSettings = JSON.parse(localStorage.getItem('bonkHUD_Mod_Setting_SoundBoard') || '{}');
  431. if (typeof savedSettings.globalMute !== "undefined") {
  432. this.globalMute = savedSettings.globalMute;
  433. }
  434. if (Array.isArray(savedSettings.sounds)) {
  435. this.sounds = savedSettings.sounds;
  436. }
  437. };
  438.  
  439. // Initialize the mod (run when document is ready)
  440. soundBoard.initMod = function () {
  441. // Ensure BonkHUD is available
  442. if (!window.bonkHUD) {
  443. console.error("BonkHUD is not loaded. Please make sure BonkHUD is installed.");
  444. return;
  445. }
  446. this.loadSettings();
  447. this.setWindowContent();
  448. this.setSettingsContent();
  449. this.createWindow();
  450. this.addStyles();
  451.  
  452. // Add event listener for chat messages
  453. bonkAPI.addEventListener("chatIn", (e) => {
  454. if (this.globalMute) return;
  455. this.sounds.forEach((sound) => {
  456. if (sound.enabled && e.message === sound.triggerMessage) {
  457. this.playSound(sound.audioUrl);
  458. }
  459. });
  460. });
  461.  
  462. console.log(this.windowConfigs.windowName + " initialized");
  463. };
  464.  
  465. // Function to play audio
  466. soundBoard.playSound = function (url) {
  467. let audio = new Audio(url);
  468. audio.play();
  469. };
  470.  
  471. // Function to handle document readiness and initialize the mod
  472. soundBoard.onDocumentReady = function () {
  473. if (document.readyState === "complete" || document.readyState === "interactive") {
  474. this.initMod();
  475. } else {
  476. document.addEventListener("DOMContentLoaded", () => {
  477. this.initMod();
  478. });
  479. }
  480. };
  481.  
  482. // Call the function to check document readiness and initialize the mod
  483. soundBoard.onDocumentReady();