aboutsummaryrefslogtreecommitdiff
path: root/webAO
diff options
context:
space:
mode:
authorCaleb <caleb.mabry.15@cnu.edu>2022-09-09 18:30:07 -0400
committerCaleb <caleb.mabry.15@cnu.edu>2022-09-09 18:30:07 -0400
commite50167a8077b0ada769cdf785971972c3ad865f7 (patch)
tree711000af34cf52b508ec05ec79b2f7d6d731cd78 /webAO
parent1e3f34e03c9dd8fda7e2b24e4533e23fcb7e1de7 (diff)
Pulled out everything I wanted
Diffstat (limited to 'webAO')
-rw-r--r--webAO/client.ts369
-rw-r--r--webAO/client/addTrack.ts15
-rw-r--r--webAO/client/createArea.ts30
-rw-r--r--webAO/client/fetchLists.ts60
-rw-r--r--webAO/client/fixLastArea.ts14
-rw-r--r--webAO/client/handleBans.ts17
-rw-r--r--webAO/client/handleCharacterInfo.ts105
-rw-r--r--webAO/client/isAudio.ts6
-rw-r--r--webAO/client/loadResources.ts79
-rw-r--r--webAO/client/saveChatLogHandle.ts26
-rw-r--r--webAO/dom/showNameClick.ts2
11 files changed, 364 insertions, 359 deletions
diff --git a/webAO/client.ts b/webAO/client.ts
index 9588812..8b2f691 100644
--- a/webAO/client.ts
+++ b/webAO/client.ts
@@ -3,35 +3,18 @@
* made by sD, refactored by oldmud0 and Qubrick
* credits to aleks for original idea and source
*/
-import {isLowMemory} from './client/isLowMemory'
+import { isLowMemory } from './client/isLowMemory'
import FingerprintJS from "@fingerprintjs/fingerprintjs";
-import vanilla_background_arr from "./constants/backgrounds.js";
-import vanilla_evidence_arr from "./constants/evidence.js";
-import {sender, ISender} from './client/sender/index'
-import iniParse from "./iniParse";
-import getCookie from "./utils/getCookie";
-import fileExists from "./utils/fileExists.js";
+import { sender, ISender } from './client/sender/index'
import queryParser from "./utils/queryParser";
import getResources from "./utils/getResources.js";
-import downloadFile from "./services/downloadFile";
import masterViewport, { Viewport } from "./viewport";
import { EventEmitter } from "events";
-import { area_click } from './dom/areaClick'
import { onReplayGo } from './dom/onReplayGo'
-import { safeTags, unescapeChat } from "./encoding";
-import { setChatbox } from "./dom/setChatbox";
-import { request } from "./services/request.js";
-import {
- changeShoutVolume,
- changeSFXVolume,
- changeTestimonyVolume,
-} from "./dom/changeVolume.js";
-import { getFilenameFromPath } from "./utils/paths";
import { packetHandler } from './packets/packetHandler'
-import { showname_click } from './dom/showNameClick'
+import { loadResources } from './client/loadResources'
import { AO_HOST } from './client/aoHost'
-
-const version = process.env.npm_package_version;
+import { fetchBackgroundList, fetchEvidenceList } from './client/fetchLists'
let { ip: serverIP, mode, theme } = queryParser();
let THEME: string = theme || "default";
@@ -82,12 +65,10 @@ fpPromise
.then((fp) => fp.get())
.then((result) => {
hdid = result.visitorId;
- console.log("NEW CLIENT");
- // Create the new client and connect it
client = new Client(serverIP);
client.connect()
- isLowMemory();
+ client.isLowMemory();
client.loadResources();
});
@@ -122,6 +103,8 @@ class Client extends EventEmitter {
_lastTimeICReceived: any;
viewport: Viewport;
connect: () => void;
+ loadResources: () => void
+ isLowMemory: () => void
constructor(address: string) {
super();
@@ -163,6 +146,8 @@ class Client extends EventEmitter {
this.sender = sender
this.viewport = masterViewport(this);
this._lastTimeICReceived = new Date(0);
+ loadResources
+ isLowMemory
}
/**
@@ -188,8 +173,6 @@ class Client extends EventEmitter {
: 0;
}
-
-
/**
* Hook for sending messages to the client
* @param {string} message the message to send
@@ -204,7 +187,6 @@ class Client extends EventEmitter {
* to the server.
*/
joinServer() {
- console.log(this.sender)
this.sender.sendServer(`HI#${hdid}#%`);
this.sender.sendServer("ID#webAO#webAO#%");
if (mode !== "replay") {
@@ -213,78 +195,6 @@ class Client extends EventEmitter {
}
/**
- * Load game resources and stored settings.
- */
- loadResources() {
- document.getElementById("client_version").innerText = `version ${version}`;
-
- // Load background array to select
- const background_select = <HTMLSelectElement>(
- document.getElementById("bg_select")
- );
- background_select.add(new Option("Custom", "0"));
- vanilla_background_arr.forEach((background) => {
- background_select.add(new Option(background));
- });
-
- // Load evidence array to select
- const evidence_select = <HTMLSelectElement>(
- document.getElementById("evi_select")
- );
- evidence_select.add(new Option("Custom", "0"));
- vanilla_evidence_arr.forEach((evidence) => {
- evidence_select.add(new Option(evidence));
- });
-
- // Read cookies and set the UI to its values
- (<HTMLInputElement>document.getElementById("OOC_name")).value =
- getCookie("OOC_name") ||
- `web${String(Math.round(Math.random() * 100 + 10))}`;
-
- // Read cookies and set the UI to its values
- const cookietheme = getCookie("theme") || "default";
-
- (<HTMLOptionElement>(
- document.querySelector(`#client_themeselect [value="${cookietheme}"]`)
- )).selected = true;
- this.viewport.reloadTheme();
-
- const cookiechatbox = getCookie("chatbox") || "dynamic";
-
- (<HTMLOptionElement>(
- document.querySelector(`#client_chatboxselect [value="${cookiechatbox}"]`)
- )).selected = true;
- setChatbox(cookiechatbox);
-
- (<HTMLInputElement>document.getElementById("client_mvolume")).value =
- getCookie("musicVolume") || "1";
- this.viewport.changeMusicVolume();
- (<HTMLAudioElement>document.getElementById("client_sfxaudio")).volume =
- Number(getCookie("sfxVolume")) || 1;
- changeSFXVolume();
- (<HTMLAudioElement>document.getElementById("client_shoutaudio")).volume =
- Number(getCookie("shoutVolume")) || 1;
- changeShoutVolume();
- (<HTMLAudioElement>(
- document.getElementById("client_testimonyaudio")
- )).volume = Number(getCookie("testimonyVolume")) || 1;
- changeTestimonyVolume();
- (<HTMLInputElement>document.getElementById("client_bvolume")).value =
- getCookie("blipVolume") || "1";
- this.viewport.changeBlipVolume();
-
- (<HTMLInputElement>document.getElementById("ic_chat_name")).value =
- getCookie("ic_chat_name");
- (<HTMLInputElement>document.getElementById("showname")).checked = Boolean(
- getCookie("showname")
- );
- showname_click(null);
-
- (<HTMLInputElement>document.getElementById("client_callwords")).value =
- getCookie("callwords");
- }
-
- /**
* Triggered when a connection is established to the server.
*/
onOpen(_e: Event) {
@@ -369,129 +279,6 @@ class Client extends EventEmitter {
}
}
- saveChatlogHandle = async () => {
- const clientLog = document.getElementById("client_log");
- const icMessageLogs = clientLog.getElementsByTagName("p");
- const messages = [];
-
- for (let i = 0; i < icMessageLogs.length; i++) {
- const SHOWNAME_POSITION = 0;
- const TEXT_POSITION = 2;
- const showname = icMessageLogs[i].children[SHOWNAME_POSITION].innerHTML;
- const text = icMessageLogs[i].children[TEXT_POSITION].innerHTML;
- const message = `${showname}: ${text}`;
- messages.push(message);
- }
- const d = new Date();
- let ye = new Intl.DateTimeFormat("en", { year: "numeric" }).format(d);
- let mo = new Intl.DateTimeFormat("en", { month: "short" }).format(d);
- let da = new Intl.DateTimeFormat("en", { day: "2-digit" }).format(d);
-
- const filename = `chatlog-${da}-${mo}-${ye}`.toLowerCase();
- downloadFile(messages.join("\n"), filename);
-
- // Reset Chatbox to Empty
- (<HTMLInputElement>document.getElementById("client_inputbox")).value = "";
- };
-
- /**
- * Handles the incoming character information, and downloads the sprite + ini for it
- * @param {Array} chargs packet arguments
- * @param {Number} charid character ID
- */
- async handleCharacterInfo(chargs: string[], charid: number) {
- const img = <HTMLImageElement>document.getElementById(`demo_${charid}`);
- if (chargs[0]) {
- let cini: any = {};
- const getCharIcon = async () => {
- const extensions = [".png", ".webp"];
- img.alt = chargs[0];
- const charIconBaseUrl = `${AO_HOST}characters/${encodeURI(
- chargs[0].toLowerCase()
- )}/char_icon`;
- for (let i = 0; i < extensions.length; i++) {
- const fileUrl = charIconBaseUrl + extensions[i];
- const exists = await fileExists(fileUrl);
- if (exists) {
- img.alt = chargs[0];
- img.title = chargs[0];
- img.src = fileUrl;
- return;
- }
- }
- };
- getCharIcon();
-
- // If the ini doesn't exist on the server this will throw an error
- try {
- const cinidata = await request(
- `${AO_HOST}characters/${encodeURI(chargs[0].toLowerCase())}/char.ini`
- );
- cini = iniParse(cinidata);
- } catch (err) {
- cini = {};
- img.classList.add("noini");
- console.warn(`character ${chargs[0]} is missing from webAO`);
- // If it does, give the user a visual indication that the character is unusable
- }
-
- const mute_select = <HTMLSelectElement>(
- document.getElementById("mute_select")
- );
- mute_select.add(new Option(safeTags(chargs[0]), String(charid)));
- const pair_select = <HTMLSelectElement>(
- document.getElementById("pair_select")
- );
- pair_select.add(new Option(safeTags(chargs[0]), String(charid)));
-
- // sometimes ini files lack important settings
- const default_options = {
- name: chargs[0],
- showname: chargs[0],
- side: "def",
- blips: "male",
- chat: "",
- category: "",
- };
- cini.options = Object.assign(default_options, cini.options);
-
- // sometimes ini files lack important settings
- const default_emotions = {
- number: 0,
- };
- cini.emotions = Object.assign(default_emotions, cini.emotions);
-
- this.chars[charid] = {
- name: safeTags(chargs[0]),
- showname: safeTags(cini.options.showname),
- desc: safeTags(chargs[1]),
- blips: safeTags(cini.options.blips).toLowerCase(),
- gender: safeTags(cini.options.gender).toLowerCase(),
- side: safeTags(cini.options.side).toLowerCase(),
- chat:
- cini.options.chat === ""
- ? safeTags(cini.options.category).toLowerCase()
- : safeTags(cini.options.chat).toLowerCase(),
- evidence: chargs[3],
- icon: img.src,
- inifile: cini,
- muted: false,
- };
-
- if (
- this.chars[charid].blips === "male" &&
- this.chars[charid].gender !== "male" &&
- this.chars[charid].gender !== ""
- ) {
- this.chars[charid].blips = this.chars[charid].gender;
- }
-
- } else {
- console.warn(`missing charid ${charid}`);
- img.style.display = "none";
- }
- }
-
resetMusicList() {
this.musics = [];
document.getElementById("client_musiclist").innerHTML = "";
@@ -501,144 +288,10 @@ class Client extends EventEmitter {
this.areas = [];
document.getElementById("areas").innerHTML = "";
- this.fetchBackgroundList();
- this.fetchEvidenceList();
- }
-
- async fetchBackgroundList() {
- try {
- const bgdata = await request(`${AO_HOST}backgrounds.json`);
- const bg_array = JSON.parse(bgdata);
- // the try catch will fail before here when there is no file
-
- const bg_select = <HTMLSelectElement>document.getElementById("bg_select");
- bg_select.innerHTML = "";
-
- bg_select.add(new Option("Custom", "0"));
- bg_array.forEach((background: string) => {
- bg_select.add(new Option(background));
- });
- } catch (err) {
- console.warn("there was no backgrounds.json file");
- }
- }
-
- async fetchCharacterList() {
- try {
- const chardata = await request(`${AO_HOST}characters.json`);
- const char_array = JSON.parse(chardata);
- // the try catch will fail before here when there is no file
-
- const char_select = <HTMLSelectElement>(
- document.getElementById("client_ininame")
- );
- char_select.innerHTML = "";
-
- char_array.forEach((character: string) => {
- char_select.add(new Option(character));
- });
- } catch (err) {
- console.warn("there was no characters.json file");
- }
- }
-
- async fetchEvidenceList() {
- try {
- const evidata = await request(`${AO_HOST}evidence.json`);
- const evi_array = JSON.parse(evidata);
- // the try catch will fail before here when there is no file
-
- const evi_select = <HTMLSelectElement>(
- document.getElementById("evi_select")
- );
- evi_select.innerHTML = "";
-
- evi_array.forEach((evi: string) => {
- evi_select.add(new Option(evi));
- });
- evi_select.add(new Option("Custom", "0"));
- } catch (err) {
- console.warn("there was no evidence.json file");
- }
- }
-
- isAudio(trackname: string) {
- const audioEndings = [".wav", ".mp3", ".ogg", ".opus"];
- return (
- audioEndings.filter((ending) => trackname.endsWith(ending)).length === 1
- );
- }
-
- addTrack(trackname: string) {
- const newentry = <HTMLOptionElement>document.createElement("OPTION");
- const songName = getFilenameFromPath(trackname);
- newentry.text = unescapeChat(songName);
- newentry.value = trackname;
- (<HTMLSelectElement>(
- document.getElementById("client_musiclist")
- )).options.add(newentry);
- this.musics.push(trackname);
+ fetchBackgroundList();
+ fetchEvidenceList();
}
- createArea(id: number, name: string) {
- const thisarea = {
- name,
- players: 0,
- status: "IDLE",
- cm: "",
- locked: "FREE",
- };
-
- this.areas.push(thisarea);
-
- // Create area button
- const newarea = document.createElement("SPAN");
- newarea.className = "area-button area-default";
- newarea.id = `area${id}`;
- newarea.innerText = thisarea.name;
- newarea.title =
- `Players: ${thisarea.players}\n` +
- `Status: ${thisarea.status}\n` +
- `CM: ${thisarea.cm}\n` +
- `Area lock: ${thisarea.locked}`;
- newarea.onclick = function () {
- area_click(newarea);
- };
-
- document.getElementById("areas").appendChild(newarea);
- }
-
- /**
- * Area list fuckery
- */
- fix_last_area() {
- if (this.areas.length > 0) {
- const malplaced = this.areas.pop().name;
- const areas = document.getElementById("areas");
- areas.removeChild(areas.lastChild);
- this.addTrack(malplaced);
- }
- }
-
- /**
- * Handles the kicked packet
- * @param {string} type is it a kick or a ban
- * @param {string} reason why
- */
- handleBans(type: string, reason: string) {
- document.getElementById("client_error").style.display = "flex";
- document.getElementById(
- "client_errortext"
- ).innerHTML = `${type}:<br>${reason.replace(/\n/g, "<br />")}`;
- (<HTMLElement>(
- document.getElementsByClassName("client_reconnect")[0]
- )).style.display = "none";
- (<HTMLElement>(
- document.getElementsByClassName("client_reconnect")[1]
- )).style.display = "none";
- }
}
-
-
export default Client; \ No newline at end of file
diff --git a/webAO/client/addTrack.ts b/webAO/client/addTrack.ts
new file mode 100644
index 0000000..247f07e
--- /dev/null
+++ b/webAO/client/addTrack.ts
@@ -0,0 +1,15 @@
+import { client } from "../client";
+import { unescapeChat } from "../encoding";
+import { getFilenameFromPath } from "../utils/paths";
+
+
+export const addTrack = (trackname: string) => {
+ const newentry = <HTMLOptionElement>document.createElement("OPTION");
+ const songName = getFilenameFromPath(trackname);
+ newentry.text = unescapeChat(songName);
+ newentry.value = trackname;
+ (<HTMLSelectElement>(
+ document.getElementById("client_musiclist")
+ )).options.add(newentry);
+ client.musics.push(trackname);
+} \ No newline at end of file
diff --git a/webAO/client/createArea.ts b/webAO/client/createArea.ts
new file mode 100644
index 0000000..63af644
--- /dev/null
+++ b/webAO/client/createArea.ts
@@ -0,0 +1,30 @@
+import { client } from "../client";
+import { area_click } from "../dom/areaClick";
+
+export const createArea = (id: number, name: string) => {
+ const thisarea = {
+ name,
+ players: 0,
+ status: "IDLE",
+ cm: "",
+ locked: "FREE",
+ };
+
+ client.areas.push(thisarea);
+
+ // Create area button
+ const newarea = document.createElement("SPAN");
+ newarea.className = "area-button area-default";
+ newarea.id = `area${id}`;
+ newarea.innerText = thisarea.name;
+ newarea.title =
+ `Players: ${thisarea.players}\n` +
+ `Status: ${thisarea.status}\n` +
+ `CM: ${thisarea.cm}\n` +
+ `Area lock: ${thisarea.locked}`;
+ newarea.onclick = function () {
+ area_click(newarea);
+ };
+
+ document.getElementById("areas")!.appendChild(newarea);
+} \ No newline at end of file
diff --git a/webAO/client/fetchLists.ts b/webAO/client/fetchLists.ts
new file mode 100644
index 0000000..e9772cb
--- /dev/null
+++ b/webAO/client/fetchLists.ts
@@ -0,0 +1,60 @@
+import { AO_HOST } from "./aoHost";
+import { request } from "../services/request.js";
+
+export const fetchBackgroundList = async () => {
+ try {
+ const bgdata = await request(`${AO_HOST}backgrounds.json`);
+ const bg_array = JSON.parse(bgdata);
+ // the try catch will fail before here when there is no file
+
+ const bg_select = <HTMLSelectElement>document.getElementById("bg_select");
+ bg_select.innerHTML = "";
+
+ bg_select.add(new Option("Custom", "0"));
+ bg_array.forEach((background: string) => {
+ bg_select.add(new Option(background));
+ });
+ } catch (err) {
+ console.warn("there was no backgrounds.json file");
+ }
+}
+
+export const fetchCharacterList = async () => {
+ try {
+ const chardata = await request(`${AO_HOST}characters.json`);
+ const char_array = JSON.parse(chardata);
+ // the try catch will fail before here when there is no file
+
+ const char_select = <HTMLSelectElement>(
+ document.getElementById("client_ininame")
+ );
+ char_select.innerHTML = "";
+
+ char_array.forEach((character: string) => {
+ char_select.add(new Option(character));
+ });
+ } catch (err) {
+ console.warn("there was no characters.json file");
+ }
+}
+
+
+export const fetchEvidenceList = async () => {
+ try {
+ const evidata = await request(`${AO_HOST}evidence.json`);
+ const evi_array = JSON.parse(evidata);
+ // the try catch will fail before here when there is no file
+
+ const evi_select = <HTMLSelectElement>(
+ document.getElementById("evi_select")
+ );
+ evi_select.innerHTML = "";
+
+ evi_array.forEach((evi: string) => {
+ evi_select.add(new Option(evi));
+ });
+ evi_select.add(new Option("Custom", "0"));
+ } catch (err) {
+ console.warn("there was no evidence.json file");
+ }
+} \ No newline at end of file
diff --git a/webAO/client/fixLastArea.ts b/webAO/client/fixLastArea.ts
new file mode 100644
index 0000000..e4d8725
--- /dev/null
+++ b/webAO/client/fixLastArea.ts
@@ -0,0 +1,14 @@
+import { client } from "../client";
+
+
+/**
+ * Area list fuckery
+ */
+export const fix_last_area = () => {
+ if (client.areas.length > 0) {
+ const malplaced = client.areas.pop().name;
+ const areas = document.getElementById("areas")!;
+ areas.removeChild(areas.lastChild);
+ client.addTrack(malplaced);
+ }
+} \ No newline at end of file
diff --git a/webAO/client/handleBans.ts b/webAO/client/handleBans.ts
new file mode 100644
index 0000000..b977fc8
--- /dev/null
+++ b/webAO/client/handleBans.ts
@@ -0,0 +1,17 @@
+/**
+ * Handles the kicked packet
+ * @param {string} type is it a kick or a ban
+ * @param {string} reason why
+ */
+export const handleBans = (type: string, reason: string) => {
+ document.getElementById("client_error")!.style.display = "flex";
+ document.getElementById(
+ "client_errortext"
+ )!.innerHTML = `${type}:<br>${reason.replace(/\n/g, "<br />")}`;
+ (<HTMLElement>(
+ document.getElementsByClassName("client_reconnect")[0]
+ )).style.display = "none";
+ (<HTMLElement>(
+ document.getElementsByClassName("client_reconnect")[1]
+ )).style.display = "none";
+} \ No newline at end of file
diff --git a/webAO/client/handleCharacterInfo.ts b/webAO/client/handleCharacterInfo.ts
new file mode 100644
index 0000000..9d74a8b
--- /dev/null
+++ b/webAO/client/handleCharacterInfo.ts
@@ -0,0 +1,105 @@
+import { client } from "../client";
+import { safeTags } from "../encoding";
+import iniParse from "../iniParse";
+import request from "../services/request";
+import fileExists from "../utils/fileExists";
+import { AO_HOST } from "./aoHost";
+
+
+/**
+ * Handles the incoming character information, and downloads the sprite + ini for it
+ * @param {Array} chargs packet arguments
+ * @param {Number} charid character ID
+ */
+export const handleCharacterInfo = async (chargs: string[], charid: number) => {
+ const img = <HTMLImageElement>document.getElementById(`demo_${charid}`);
+ if (chargs[0]) {
+ let cini: any = {};
+ const getCharIcon = async () => {
+ const extensions = [".png", ".webp"];
+ img.alt = chargs[0];
+ const charIconBaseUrl = `${AO_HOST}characters/${encodeURI(
+ chargs[0].toLowerCase()
+ )}/char_icon`;
+ for (let i = 0; i < extensions.length; i++) {
+ const fileUrl = charIconBaseUrl + extensions[i];
+ const exists = await fileExists(fileUrl);
+ if (exists) {
+ img.alt = chargs[0];
+ img.title = chargs[0];
+ img.src = fileUrl;
+ return;
+ }
+ }
+ };
+ getCharIcon();
+
+ // If the ini doesn't exist on the server this will throw an error
+ try {
+ const cinidata = await request(
+ `${AO_HOST}characters/${encodeURI(chargs[0].toLowerCase())}/char.ini`
+ );
+ cini = iniParse(cinidata);
+ } catch (err) {
+ cini = {};
+ img.classList.add("noini");
+ console.warn(`character ${chargs[0]} is missing from webAO`);
+ // If it does, give the user a visual indication that the character is unusable
+ }
+
+ const mute_select = <HTMLSelectElement>(
+ document.getElementById("mute_select")
+ );
+ mute_select.add(new Option(safeTags(chargs[0]), String(charid)));
+ const pair_select = <HTMLSelectElement>(
+ document.getElementById("pair_select")
+ );
+ pair_select.add(new Option(safeTags(chargs[0]), String(charid)));
+
+ // sometimes ini files lack important settings
+ const default_options = {
+ name: chargs[0],
+ showname: chargs[0],
+ side: "def",
+ blips: "male",
+ chat: "",
+ category: "",
+ };
+ cini.options = Object.assign(default_options, cini.options);
+
+ // sometimes ini files lack important settings
+ const default_emotions = {
+ number: 0,
+ };
+ cini.emotions = Object.assign(default_emotions, cini.emotions);
+
+ client.chars[charid] = {
+ name: safeTags(chargs[0]),
+ showname: safeTags(cini.options.showname),
+ desc: safeTags(chargs[1]),
+ blips: safeTags(cini.options.blips).toLowerCase(),
+ gender: safeTags(cini.options.gender).toLowerCase(),
+ side: safeTags(cini.options.side).toLowerCase(),
+ chat:
+ cini.options.chat === ""
+ ? safeTags(cini.options.category).toLowerCase()
+ : safeTags(cini.options.chat).toLowerCase(),
+ evidence: chargs[3],
+ icon: img.src,
+ inifile: cini,
+ muted: false,
+ };
+
+ if (
+ client.chars[charid].blips === "male" &&
+ client.chars[charid].gender !== "male" &&
+ client.chars[charid].gender !== ""
+ ) {
+ client.chars[charid].blips = client.chars[charid].gender;
+ }
+
+ } else {
+ console.warn(`missing charid ${charid}`);
+ img.style.display = "none";
+ }
+} \ No newline at end of file
diff --git a/webAO/client/isAudio.ts b/webAO/client/isAudio.ts
new file mode 100644
index 0000000..430f543
--- /dev/null
+++ b/webAO/client/isAudio.ts
@@ -0,0 +1,6 @@
+export const isAudio = (trackname: string) => {
+ const audioEndings = [".wav", ".mp3", ".ogg", ".opus"];
+ return (
+ audioEndings.filter((ending) => trackname.endsWith(ending)).length === 1
+ );
+} \ No newline at end of file
diff --git a/webAO/client/loadResources.ts b/webAO/client/loadResources.ts
new file mode 100644
index 0000000..7039333
--- /dev/null
+++ b/webAO/client/loadResources.ts
@@ -0,0 +1,79 @@
+import getCookie from "../utils/getCookie";
+import vanilla_evidence_arr from "../constants/evidence.js";
+import vanilla_background_arr from "../constants/backgrounds.js";
+import { client } from "../client";
+import { setChatbox } from "../dom/setChatbox";
+import { changeSFXVolume, changeShoutVolume, changeTestimonyVolume } from "../dom/changeVolume";
+import { showname_click } from "../dom/showNameClick";
+
+const version = process.env.npm_package_version;
+/**
+ * Load game resources and stored settings.
+ */
+export const loadResources = () => {
+ document.getElementById("client_version")!.innerText = `version ${version}`;
+ // Load background array to select
+ const background_select = <HTMLSelectElement>(
+ document.getElementById("bg_select")
+ );
+ background_select.add(new Option("Custom", "0"));
+ vanilla_background_arr.forEach((background) => {
+ background_select.add(new Option(background));
+ });
+
+ // Load evidence array to select
+ const evidence_select = <HTMLSelectElement>(
+ document.getElementById("evi_select")
+ );
+ evidence_select.add(new Option("Custom", "0"));
+ vanilla_evidence_arr.forEach((evidence) => {
+ evidence_select.add(new Option(evidence));
+ });
+
+ // Read cookies and set the UI to its values
+ (<HTMLInputElement>document.getElementById("OOC_name")).value =
+ getCookie("OOC_name") ||
+ `web${String(Math.round(Math.random() * 100 + 10))}`;
+
+ // Read cookies and set the UI to its values
+ const cookietheme = getCookie("theme") || "default";
+
+ (<HTMLOptionElement>(
+ document.querySelector(`#client_themeselect [value="${cookietheme}"]`)
+ )).selected = true;
+ client.viewport.reloadTheme();
+
+ const cookiechatbox = getCookie("chatbox") || "dynamic";
+
+ (<HTMLOptionElement>(
+ document.querySelector(`#client_chatboxselect [value="${cookiechatbox}"]`)
+ )).selected = true;
+ setChatbox(cookiechatbox);
+
+ (<HTMLInputElement>document.getElementById("client_mvolume")).value =
+ getCookie("musicVolume") || "1";
+ client.viewport.changeMusicVolume();
+ (<HTMLAudioElement>document.getElementById("client_sfxaudio")).volume =
+ Number(getCookie("sfxVolume")) || 1;
+ changeSFXVolume();
+ (<HTMLAudioElement>document.getElementById("client_shoutaudio")).volume =
+ Number(getCookie("shoutVolume")) || 1;
+ changeShoutVolume();
+ (<HTMLAudioElement>(
+ document.getElementById("client_testimonyaudio")
+ )).volume = Number(getCookie("testimonyVolume")) || 1;
+ changeTestimonyVolume();
+ (<HTMLInputElement>document.getElementById("client_bvolume")).value =
+ getCookie("blipVolume") || "1";
+ client.viewport.changeBlipVolume();
+
+ (<HTMLInputElement>document.getElementById("ic_chat_name")).value =
+ getCookie("ic_chat_name");
+ (<HTMLInputElement>document.getElementById("showname")).checked = Boolean(
+ getCookie("showname")
+ );
+ showname_click(null);
+
+ (<HTMLInputElement>document.getElementById("client_callwords")).value =
+ getCookie("callwords");
+} \ No newline at end of file
diff --git a/webAO/client/saveChatLogHandle.ts b/webAO/client/saveChatLogHandle.ts
new file mode 100644
index 0000000..bcc1075
--- /dev/null
+++ b/webAO/client/saveChatLogHandle.ts
@@ -0,0 +1,26 @@
+import downloadFile from "../services/downloadFile";
+
+export const saveChatlogHandle = async () => {
+ const clientLog = document.getElementById("client_log")!;
+ const icMessageLogs = clientLog.getElementsByTagName("p");
+ const messages: string[] = [];
+
+ for (let i = 0; i < icMessageLogs.length; i++) {
+ const SHOWNAME_POSITION = 0;
+ const TEXT_POSITION = 2;
+ const showname = icMessageLogs[i].children[SHOWNAME_POSITION].innerHTML;
+ const text = icMessageLogs[i].children[TEXT_POSITION].innerHTML;
+ const message = `${showname}: ${text}`;
+ messages.push(message);
+ }
+ const d = new Date();
+ let ye = new Intl.DateTimeFormat("en", { year: "numeric" }).format(d);
+ let mo = new Intl.DateTimeFormat("en", { month: "short" }).format(d);
+ let da = new Intl.DateTimeFormat("en", { day: "2-digit" }).format(d);
+
+ const filename = `chatlog-${da}-${mo}-${ye}`.toLowerCase();
+ downloadFile(messages.join("\n"), filename);
+
+ // Reset Chatbox to Empty
+ (<HTMLInputElement>document.getElementById("client_inputbox")).value = "";
+}; \ No newline at end of file
diff --git a/webAO/dom/showNameClick.ts b/webAO/dom/showNameClick.ts
index 265f6c8..3e48b70 100644
--- a/webAO/dom/showNameClick.ts
+++ b/webAO/dom/showNameClick.ts
@@ -5,7 +5,7 @@ import setCookie from "../utils/setCookie";
* Triggered when the showname checkboc is clicked
* @param {MouseEvent} event
*/
-export function showname_click(_event: Event) {
+export function showname_click(_event: Event | null) {
setCookie(
"showname",
String((<HTMLInputElement>document.getElementById("showname")).checked)