diff options
| author | stonedDiscord <Tukz@gmx.de> | 2022-10-12 18:25:14 +0200 |
|---|---|---|
| committer | stonedDiscord <Tukz@gmx.de> | 2022-10-12 18:25:14 +0200 |
| commit | 8a7942c0565298c29edbf0b271d5d7c7f9e56fd8 (patch) | |
| tree | 67b788f40b7a4713904836de05f0e5876c32bd79 /webAO/client | |
| parent | a83c8962b68f2cc0a0e22d988b8ff030057454e5 (diff) | |
| parent | 82983e0c38383ec2602b4f41327342d1c8d0a8fd (diff) | |
Merge branch 'master' into 2fa
Diffstat (limited to 'webAO/client')
32 files changed, 866 insertions, 46 deletions
diff --git a/webAO/client/__tests__/setEmote.test.js b/webAO/client/__tests__/setEmote.test.js index 1db13c9..53bb68d 100644 --- a/webAO/client/__tests__/setEmote.test.js +++ b/webAO/client/__tests__/setEmote.test.js @@ -9,10 +9,13 @@ jest.mock('../../utils/fileExists'); describe('setEmote', () => { const AO_HOST = ''; Client.mockReturnValue({ - lastChar: 'long', - chatmsg: { - name: 'byte', - }, + viewport: { + lastChar: 'long', + chatmsg: { + name: 'byte', + }, + } + }); const client = new Client('127.0.0.1'); const firstExtension = '.gif'; 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/aoHost.js b/webAO/client/aoHost.ts index b387608..9b0a768 100644 --- a/webAO/client/aoHost.js +++ b/webAO/client/aoHost.ts @@ -1,5 +1,7 @@ import queryParser from '../utils/queryParser' let { asset } = queryParser(); const DEFAULT_HOST = 'http://attorneyoffline.de/base/'; -const AO_HOST = asset || DEFAULT_HOST -export default AO_HOST +export let AO_HOST = asset || DEFAULT_HOST +export const setAOhost = (val: string) => { + AO_HOST = val +} diff --git a/webAO/client/appendICLog.ts b/webAO/client/appendICLog.ts new file mode 100644 index 0000000..f8b7852 --- /dev/null +++ b/webAO/client/appendICLog.ts @@ -0,0 +1,57 @@ +import { lastICMessageTime, setLastICMessageTime } from "../client"; + + + +/** + * Appends a message to the in-character chat log. + * @param {string} msg the string to be added + * @param {string} name the name of the sender + */ +export function appendICLog( + msg: string, + showname = "", + nameplate = "", + time = new Date() +) { + const entry = document.createElement("p"); + const shownameField = document.createElement("span"); + const nameplateField = document.createElement("span"); + const textField = document.createElement("span"); + nameplateField.className = "iclog_name iclog_nameplate"; + nameplateField.appendChild(document.createTextNode(nameplate)); + + shownameField.className = "iclog_name iclog_showname"; + if (showname === "" || !showname) { + shownameField.appendChild(document.createTextNode(nameplate)); + } else { + shownameField.appendChild(document.createTextNode(showname)); + } + + textField.className = "iclog_text"; + textField.appendChild(document.createTextNode(msg)); + + entry.appendChild(shownameField); + entry.appendChild(nameplateField); + entry.appendChild(textField); + + // Only put a timestamp if the minute has changed. + if (lastICMessageTime.getMinutes() !== time.getMinutes()) { + const timeStamp = document.createElement("span"); + timeStamp.className = "iclog_time"; + timeStamp.innerText = time.toLocaleTimeString(undefined, { + hour: "numeric", + minute: "2-digit", + }); + entry.appendChild(timeStamp); + } + + const clientLog = document.getElementById("client_log")!; + clientLog.appendChild(entry); + + /* This is a little buggy - some troubleshooting might be desirable */ + if (clientLog.scrollTop > clientLog.scrollHeight - 800) { + clientLog.scrollTop = clientLog.scrollHeight; + } + + setLastICMessageTime(new Date()); +}
\ No newline at end of file diff --git a/webAO/client/checkCallword.ts b/webAO/client/checkCallword.ts new file mode 100644 index 0000000..f6cffbc --- /dev/null +++ b/webAO/client/checkCallword.ts @@ -0,0 +1,17 @@ +import { client } from "../client"; +import { AO_HOST } from "./aoHost"; + +/** + * check if the message contains an entry on our callword list + * @param {string} message + */ +export function checkCallword(message: string, sfxAudio: HTMLAudioElement) { + client.callwords.forEach(testCallword); + function testCallword(item: string) { + if (item !== "" && message.toLowerCase().includes(item.toLowerCase())) { + sfxAudio.pause(); + sfxAudio.src = `${AO_HOST}sounds/general/sfx-gallery.opus`; + sfxAudio.play(); + } + } +}
\ 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..f1aa99f --- /dev/null +++ b/webAO/client/fixLastArea.ts @@ -0,0 +1,15 @@ +import { client } from "../client"; +import { addTrack } from "./addTrack"; + + +/** + * 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); + 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/isLowMemory.ts b/webAO/client/isLowMemory.ts new file mode 100644 index 0000000..caa6784 --- /dev/null +++ b/webAO/client/isLowMemory.ts @@ -0,0 +1,10 @@ +import { setOldLoading } from '../client' +export const isLowMemory = () => { + if ( + /webOS|iPod|BlackBerry|BB|PlayBook|IEMobile|Windows Phone|Kindle|Silk|PlayStation|Nintendo|Opera Mini/i.test( + navigator.userAgent + ) + ) { + setOldLoading(true); + } +} diff --git a/webAO/client/loadResources.ts b/webAO/client/loadResources.ts new file mode 100644 index 0000000..4954966 --- /dev/null +++ b/webAO/client/loadResources.ts @@ -0,0 +1,81 @@ +import getCookie from "../utils/getCookie"; +import vanilla_evidence_arr from "../constants/evidence.js"; +import vanilla_background_arr from "../constants/backgrounds.js"; +import { changeMusicVolume } from '../dom/changeMusicVolume' +import { setChatbox } from "../dom/setChatbox"; +import { changeSFXVolume, changeShoutVolume, changeTestimonyVolume } from "../dom/changeVolume"; +import { showname_click } from "../dom/showNameClick"; +import { changeBlipVolume } from '../dom/changeBlipVolume' +import { reloadTheme } from '../dom/reloadTheme' +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; + 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"; + 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"; + 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/resetICParams.ts b/webAO/client/resetICParams.ts new file mode 100644 index 0000000..414da27 --- /dev/null +++ b/webAO/client/resetICParams.ts @@ -0,0 +1,21 @@ +import { selectedShout, setSelectedShout } from "../client"; + +/** + * Resets the IC parameters for the player to enter a new chat message. + * This should only be called when the player's previous chat message + * was successfully sent/presented. + */ +export function resetICParams() { + (<HTMLInputElement>document.getElementById("client_inputbox")).value = ""; + document.getElementById("button_flash")!.className = "client_button"; + document.getElementById("button_shake")!.className = "client_button"; + + (<HTMLInputElement>document.getElementById("sendpreanim")).checked = false; + (<HTMLInputElement>document.getElementById("sendsfx")).checked = false; + + if (selectedShout) { + document.getElementById(`button_${selectedShout}`)!.className = + "client_button"; + setSelectedShout(0); + } +}
\ 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/client/sender/index.ts b/webAO/client/sender/index.ts new file mode 100644 index 0000000..41a6bd5 --- /dev/null +++ b/webAO/client/sender/index.ts @@ -0,0 +1,68 @@ +import { sendIC } from "./sendIC"; +import { sendSelf } from './sendSelf' +import { sendServer } from './sendServer' +import { sendCheck } from './sendCheck' +import {sendHP} from './sendHP' +import {sendOOC} from './sendOOC' +import {sendCharacter} from './sendCharacter' +import {sendRT} from './sendRT' +import {sendMusicChange} from './sendMusicChange' +import {sendZZ} from './sendZZ' +import {sendEE} from './sendEE' +import {sendDE} from './sendDE' +import {sendPE} from './sendPE' +export interface ISender { + sendIC: (deskmod: number, + preanim: string, + name: string, + emote: string, + message: string, + side: string, + sfx_name: string, + emote_modifier: number, + sfx_delay: number, + objection_modifier: number, + evidence: number, + flip: boolean, + realization: boolean, + text_color: number, + showname: string, + other_charid: string, + self_hoffset: number, + self_yoffset: number, + noninterrupting_preanim: boolean, + looping_sfx: boolean, + screenshake: boolean, + frame_screenshake: string, + frame_realization: string, + frame_sfx: string, + additive: boolean, + effect: string) => void + sendSelf: (message: string) => void + sendServer: (message: string) => void + sendCheck: () => void + sendHP: (side: number, hp: number) => void + sendOOC: (message: string) => void + sendCharacter: (character: number) => void + sendRT: (testimony: string) => void + sendMusicChange: (track: string) => void + sendZZ: (msg: string) => void + sendEE: (id: number, name: string, desc: string, img: string) => void + sendDE: (id: number) => void + sendPE: (name: string, desc: string, img: string) => void +} +export const sender = { + sendIC, + sendSelf, + sendServer, + sendCheck, + sendHP, + sendOOC, + sendCharacter, + sendRT, + sendMusicChange, + sendZZ, + sendEE, + sendDE, + sendPE +}
\ No newline at end of file diff --git a/webAO/client/sender/sendCharacter.ts b/webAO/client/sender/sendCharacter.ts new file mode 100644 index 0000000..5e81727 --- /dev/null +++ b/webAO/client/sender/sendCharacter.ts @@ -0,0 +1,11 @@ +import { client } from "../../client"; + +/** + * Requests to play as a specified character. + * @param {number} character the character ID + */ +export const sendCharacter = (character: number) => { + if (character === -1 || client.chars[character].name) { + client.sender.sendServer(`CC#${client.playerID}#${character}#web#%`); + } +}
\ No newline at end of file diff --git a/webAO/client/sender/sendCheck.ts b/webAO/client/sender/sendCheck.ts new file mode 100644 index 0000000..91b3a02 --- /dev/null +++ b/webAO/client/sender/sendCheck.ts @@ -0,0 +1,8 @@ +import { client } from "../../client"; + +/** + * Sends a keepalive packet. + */ +export const sendCheck = () => { + client.sender.sendServer(`CH#${client.charID}#%`); +} diff --git a/webAO/client/sender/sendDE.ts b/webAO/client/sender/sendDE.ts new file mode 100644 index 0000000..4d94d65 --- /dev/null +++ b/webAO/client/sender/sendDE.ts @@ -0,0 +1,9 @@ +import { client } from "../../client"; + +/** + * Sends delete evidence command. + * @param {number} evidence id + */ +export const sendDE = (id: number) => { + client.sender.sendServer(`DE#${id}#%`); +}
\ No newline at end of file diff --git a/webAO/client/sender/sendEE.ts b/webAO/client/sender/sendEE.ts new file mode 100644 index 0000000..7c5bfe3 --- /dev/null +++ b/webAO/client/sender/sendEE.ts @@ -0,0 +1,16 @@ +import { client } from "../../client"; +import { escapeChat } from "../../encoding"; + + +/** + * Sends edit evidence command. + * @param {number} evidence id + * @param {string} evidence name + * @param {string} evidence description + * @param {string} evidence image filename + */ +export const sendEE = (id: number, name: string, desc: string, img: string) => { + client.sender.sendServer( + `EE#${id}#${escapeChat(name)}#${escapeChat(desc)}#${escapeChat(img)}#%` + ); +}
\ No newline at end of file diff --git a/webAO/client/sender/sendHP.ts b/webAO/client/sender/sendHP.ts new file mode 100644 index 0000000..d007094 --- /dev/null +++ b/webAO/client/sender/sendHP.ts @@ -0,0 +1,10 @@ +import { client } from "../../client"; + +/** + * Sends health point command. + * @param {number} side the position + * @param {number} hp the health point + */ +export const sendHP = (side: number, hp: number) => { + client.sender.sendServer(`HP#${side}#${hp}#%`); +}
\ No newline at end of file diff --git a/webAO/client/sender/sendIC.ts b/webAO/client/sender/sendIC.ts new file mode 100644 index 0000000..9064115 --- /dev/null +++ b/webAO/client/sender/sendIC.ts @@ -0,0 +1,106 @@ +import { extrafeatures } from "../../client"; +import { escapeChat } from "../../encoding"; +import {client} from '../../client' +import queryParser from "../../utils/queryParser"; +let {mode} = queryParser() + +/** + * Sends an in-character chat message. + * @param {number} deskmod controls the desk + * @param {string} speaking who is speaking + * @param {string} name the name of the current character + * @param {string} silent whether or not it's silent + * @param {string} message the message to be sent + * @param {string} side the name of the side in the background + * @param {string} sfx_name the name of the sound effect + * @param {number} emote_modifier whether or not to zoom + * @param {number} sfx_delay the delay (in milliseconds) to play the sound effect + * @param {number} objection_modifier the number of the shout to play + * @param {string} evidence the filename of evidence to show + * @param {boolean} flip change to 1 to reverse sprite for position changes + * @param {boolean} realization screen flash effect + * @param {number} text_color text color + * @param {string} showname custom name to be displayed (optional) + * @param {number} other_charid paired character (optional) + * @param {number} self_offset offset to paired character (optional) + * @param {number} noninterrupting_preanim play the full preanim (optional) + */ +export const sendIC = ( + deskmod: number, + preanim: string, + name: string, + emote: string, + message: string, + side: string, + sfx_name: string, + emote_modifier: number, + sfx_delay: number, + objection_modifier: number, + evidence: number, + flip: boolean, + realization: boolean, + text_color: number, + showname: string, + other_charid: string, + self_hoffset: number, + self_yoffset: number, + noninterrupting_preanim: boolean, + looping_sfx: boolean, + screenshake: boolean, + frame_screenshake: string, + frame_realization: string, + frame_sfx: string, + additive: boolean, + effect: string +) => { + let extra_cccc = ""; + let other_emote = ""; + let other_offset = ""; + let extra_27 = ""; + let extra_28 = ""; + + if (extrafeatures.includes("cccc_ic_support")) { + const self_offset = extrafeatures.includes("y_offset") + ? `${self_hoffset}<and>${self_yoffset}` + : self_hoffset; // HACK: this should be an & but client fucked it up and all the servers adopted it + if (mode === "replay") { + other_emote = "##"; + other_offset = "#0#0"; + } + extra_cccc = `${escapeChat( + showname + )}#${other_charid}${other_emote}#${self_offset}${other_offset}#${Number( + noninterrupting_preanim + )}#`; + + if (extrafeatures.includes("looping_sfx")) { + extra_27 = `${Number(looping_sfx)}#${Number( + screenshake + )}#${frame_screenshake}#${frame_realization}#${frame_sfx}#`; + if (extrafeatures.includes("effects")) { + extra_28 = `${Number(additive)}#${escapeChat(effect)}#`; + } + } + } + + const serverMessage = + `MS#${deskmod}#${escapeChat(preanim)}#${escapeChat(name)}#${escapeChat( + emote + )}` + + `#${escapeChat(message)}#${escapeChat(side)}#${escapeChat( + sfx_name + )}#${emote_modifier}` + + `#${client.charID}#${sfx_delay}#${Number(objection_modifier)}#${Number( + evidence + )}#${Number(flip)}#${Number( + realization + )}#${text_color}#${extra_cccc}${extra_27}${extra_28}%`; + + client.sender.sendServer(serverMessage); + if (mode === "replay") { + (<HTMLInputElement>( + document.getElementById("client_ooclog") + )).value += `wait#${(<HTMLInputElement>document.getElementById("client_replaytimer")).value + }#%\r\n`; + } +}
\ No newline at end of file diff --git a/webAO/client/sender/sendMusic.ts b/webAO/client/sender/sendMusic.ts new file mode 100644 index 0000000..eceba08 --- /dev/null +++ b/webAO/client/sender/sendMusic.ts @@ -0,0 +1,10 @@ +import { client } from "../../client"; + + +/** + * Requests to select a music track. + * @param {number?} song the song to be played + */ +export const sendMusic = (song: string) => { + client.sender.sendServer(`MC#${song}#${client.charID}#%`); +}
\ No newline at end of file diff --git a/webAO/client/sender/sendMusicChange.ts b/webAO/client/sender/sendMusicChange.ts new file mode 100644 index 0000000..50c6306 --- /dev/null +++ b/webAO/client/sender/sendMusicChange.ts @@ -0,0 +1,10 @@ +import { client } from "../../client"; + + +/** + * Requests to change the music to the specified track. + * @param {string} track the track ID + */ +export const sendMusicChange = (track: string) => { + client.sender.sendServer(`MC#${track}#${client.charID}#%`); +} diff --git a/webAO/client/sender/sendOOC.ts b/webAO/client/sender/sendOOC.ts new file mode 100644 index 0000000..9674ad9 --- /dev/null +++ b/webAO/client/sender/sendOOC.ts @@ -0,0 +1,33 @@ +import { client } from '../../client' +import { escapeChat } from '../../encoding'; +import setCookie from '../../utils/setCookie'; +import { saveChatlogHandle } from '../../client/saveChatLogHandle' +/** + * Sends an out-of-character chat message. + * @param {string} message the message to send + */ +export const sendOOC = (message: string) => { + setCookie( + "OOC_name", + (<HTMLInputElement>document.getElementById("OOC_name")).value + ); + const oocName = `${escapeChat( + (<HTMLInputElement>document.getElementById("OOC_name")).value + )}`; + const oocMessage = `${escapeChat(message)}`; + + const commands = { + "/save_chatlog": saveChatlogHandle, + }; + const commandsMap = new Map(Object.entries(commands)); + + if (oocMessage && commandsMap.has(oocMessage.toLowerCase())) { + try { + commandsMap.get(oocMessage.toLowerCase())(); + } catch (e) { + // Command Not Recognized + } + } else { + client.sender.sendServer(`CT#${oocName}#${oocMessage}#%`); + } +}
\ No newline at end of file diff --git a/webAO/client/sender/sendPE.ts b/webAO/client/sender/sendPE.ts new file mode 100644 index 0000000..984fc4d --- /dev/null +++ b/webAO/client/sender/sendPE.ts @@ -0,0 +1,14 @@ +import { client } from "../../client"; +import { escapeChat } from "../../encoding"; + +/** + * Sends add evidence command. + * @param {string} evidence name + * @param {string} evidence description + * @param {string} evidence image filename + */ +export const sendPE = (name: string, desc: string, img: string) => { + client.sender.sendServer( + `PE#${escapeChat(name)}#${escapeChat(desc)}#${escapeChat(img)}#%` + ); +}
\ No newline at end of file diff --git a/webAO/client/sender/sendRT.ts b/webAO/client/sender/sendRT.ts new file mode 100644 index 0000000..2d6c60a --- /dev/null +++ b/webAO/client/sender/sendRT.ts @@ -0,0 +1,9 @@ +import { client } from "../../client"; + +/** + * Sends testimony command. + * @param {string} testimony type + */ +export const sendRT = (testimony: string) => { + client.sender.sendServer(`RT#${testimony}#%`); +}
\ No newline at end of file diff --git a/webAO/client/sender/sendSelf.ts b/webAO/client/sender/sendSelf.ts new file mode 100644 index 0000000..66c35fa --- /dev/null +++ b/webAO/client/sender/sendSelf.ts @@ -0,0 +1,13 @@ +import { client } from "../../client"; + + +/** + * Hook for sending messages to the client + * @param {string} message the message to send + */ +export const sendSelf = (message: string) => { + (<HTMLInputElement>( + document.getElementById("client_ooclog") + )).value += `${message}\r\n`; + client.handleSelf(message); +}
\ No newline at end of file diff --git a/webAO/client/sender/sendServer.ts b/webAO/client/sender/sendServer.ts new file mode 100644 index 0000000..a9da3bd --- /dev/null +++ b/webAO/client/sender/sendServer.ts @@ -0,0 +1,10 @@ +import { client } from "../../client"; +import queryParser from "../../utils/queryParser"; +let { mode } = queryParser() +/** + * Hook for sending messages to the server + * @param {string} message the message to send + */ +export const sendServer = (message: string) => { + mode === "replay" ? client.sender.sendSelf(message) : client.serv.send(message); +}
\ No newline at end of file diff --git a/webAO/client/sender/sendZZ.ts b/webAO/client/sender/sendZZ.ts new file mode 100644 index 0000000..237ab37 --- /dev/null +++ b/webAO/client/sender/sendZZ.ts @@ -0,0 +1,13 @@ +import { client, extrafeatures } from "../../client"; + +/** + * Sends call mod command. + * @param {string} message to mod + */ +export const sendZZ = (msg: string) => { + if (extrafeatures.includes("modcall_reason")) { + client.sender.sendServer(`ZZ#${msg}#%`); + } else { + client.sender.sendServer("ZZ#%"); + } +}
\ No newline at end of file diff --git a/webAO/client/setEmote.js b/webAO/client/setEmote.js deleted file mode 100644 index f682fe5..0000000 --- a/webAO/client/setEmote.js +++ /dev/null @@ -1,40 +0,0 @@ -import transparentPng from '../constants/transparentPng'; -import fileExists from '../utils/fileExists'; - -/** - * Sets all the img tags to the right sources - * @param {*} chatmsg - */ - -const setEmote = async (AO_HOST, client, charactername, emotename, prefix, pair, side) => { - const pairID = pair ? 'pair' : 'char'; - const characterFolder = `${AO_HOST}characters/`; - const acceptedPositions = ['def', 'pro', 'wit']; - const position = acceptedPositions.includes(side) ? `${side}_` : ''; - const emoteSelector = document.getElementById(`client_${position}${pairID}_img`) - const extensionsMap = [ - '.gif', - '.png', - '.apng', - '.webp' - ]; - - for (const extension of extensionsMap) { - // Hides all sprites before creating a new sprite - if (client.lastChar !== client.chatmsg.name) { - emoteSelector.src = transparentPng; - } - let url; - if (extension === '.png') { - url = `${characterFolder}${encodeURI(charactername)}/${encodeURI(emotename)}${extension}`; - } else { - url = `${characterFolder}${encodeURI(charactername)}/${encodeURI(prefix)}${encodeURI(emotename)}${extension}`; - } - const exists = await fileExists(url); - if (exists) { - emoteSelector.src = url; - break; - } - } -}; -export default setEmote; diff --git a/webAO/client/setEmote.ts b/webAO/client/setEmote.ts new file mode 100644 index 0000000..f4fbdbb --- /dev/null +++ b/webAO/client/setEmote.ts @@ -0,0 +1,55 @@ +import Client from "../client"; +import transparentPng from "../constants/transparentPng"; +import fileExists from "../utils/fileExists"; + +/** + * Sets all the img tags to the right sources + * @param {*} chatmsg + */ + +const setEmote = async ( + AO_HOST: string, + client: Client, + charactername: string, + emotename: string, + prefix: string, + pair: boolean, + side: string +) => { + const pairID = pair ? "pair" : "char"; + const characterFolder = `${AO_HOST}characters/`; + const acceptedPositions = ["def", "pro", "wit"]; + const position = acceptedPositions.includes(side) ? `${side}_` : ""; + const emoteSelector = document.getElementById( + `client_${position}${pairID}_img` + ) as HTMLImageElement; + const extensionsMap = [".gif", ".png", ".apng", ".webp", ".webp.static"]; + + for (const extension of extensionsMap) { + // Hides all sprites before creating a new sprite + + if (client.viewport.getLastCharacter() !== client.viewport.getChatmsg().name) { + emoteSelector.src = transparentPng; + } + let url; + if (extension === ".png") { + url = `${characterFolder}${encodeURI(charactername)}/${encodeURI( + emotename + )}${extension}`; + } else if (extension === ".webp.static") { + url = `${characterFolder}${encodeURI(charactername)}/${encodeURI( + emotename + )}.webp`; + } else { + url = `${characterFolder}${encodeURI(charactername)}/${encodeURI( + prefix + )}${encodeURI(emotename)}${extension}`; + } + const exists = await fileExists(url); + if (exists) { + emoteSelector.src = url; + break; + } + } +}; +export default setEmote; |
