diff options
Diffstat (limited to 'webAO')
| -rw-r--r-- | webAO/client.html | 613 | ||||
| -rw-r--r-- | webAO/client.js | 342 | ||||
| -rw-r--r-- | webAO/client/setEmote.js | 43 | ||||
| -rw-r--r-- | webAO/dom/changeSFXVolume.js | 10 | ||||
| -rw-r--r-- | webAO/dom/changeShoutVolume.js | 10 | ||||
| -rw-r--r-- | webAO/dom/toggleEffect.js | 13 | ||||
| -rw-r--r-- | webAO/favicon.ico | bin | 5694 -> 0 bytes | |||
| -rw-r--r-- | webAO/images/desc.png | bin | 50785 -> 0 bytes | |||
| -rw-r--r-- | webAO/index.html | 126 | ||||
| -rw-r--r-- | webAO/logo-new-512.png | bin | 238578 -> 0 bytes | |||
| -rw-r--r-- | webAO/logo-new.png | bin | 29302 -> 0 bytes | |||
| -rw-r--r-- | webAO/manifest.json | 23 | ||||
| -rw-r--r-- | webAO/master.js | 2 | ||||
| -rw-r--r-- | webAO/packets/ms.js | 28 | ||||
| -rw-r--r-- | webAO/styles/master.css | 2 | ||||
| -rw-r--r-- | webAO/sw.js | 26 | ||||
| -rw-r--r-- | webAO/utils/fileExists.js | 17 | ||||
| -rw-r--r-- | webAO/utils/fileExistsSync.js | 11 | ||||
| -rw-r--r-- | webAO/utils/getAnimLength.js | 22 | ||||
| -rw-r--r-- | webAO/utils/getResources.js | 39 | ||||
| -rw-r--r-- | webAO/utils/queryParser.js | 9 |
21 files changed, 261 insertions, 1075 deletions
diff --git a/webAO/client.html b/webAO/client.html deleted file mode 100644 index 5dd0264..0000000 --- a/webAO/client.html +++ /dev/null @@ -1,613 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> - -<head> - <title>Attorney Online session</title> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <meta name="description" content="An off-the-cuff courtroom drama simulator"> - <meta name="author" content="stonedDiscord"> - - <meta property="og:title" content="Attorney Online"> - <meta property="og:description" content="Attorney Online is an online version of the world-renowned courtroom drama simulator that allows you to create and play out cases in an off-the-cuff format."> - <meta property="og:type" content="website"> - <meta property="og:url" content="http://web.aceattorneyonline.com/"> - <meta property="og:image" content="https://repository-images.githubusercontent.com/78860508/89fcba80-aafd-11e9-80db-c5b10c01aba9"> - - <meta property="twitter:card" content="summary_large_image"> - <meta property="twitter:title" content="Attorney Online"> - <meta property="twitter:description" content="Attorney Online is an online version of the world-renowned courtroom drama simulator that allows you to create and play out cases in an off-the-cuff format."> - <meta property="twitter:url" content="http://web.aceattorneyonline.com/"> - <meta property="twitter:image" content="https://repository-images.githubusercontent.com/78860508/89fcba80-aafd-11e9-80db-c5b10c01aba9"> - - <meta http-equiv="Content-Security-Policy" content="script-src-elem 'self' 'unsafe-inline' https://ajax.googleapis.com; - script-src 'self' 'unsafe-inline' 'unsafe-eval' https://ajax.googleapis.com; - style-src-elem 'self' 'unsafe-inline' https://golden-layout.com; - style-src 'self' 'unsafe-inline' https://golden-layout.com; - img-src 'self' data: file: *; - connect-src 'self' ws: file: *; - media-src 'self' file: *;"> - - <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"> - <link rel="apple-touch-icon" href="/images/logo-new.png"/> - <link rel="stylesheet" type="text/css" href="styles/client.css?v=1.0.3" id="client_stylesheet"> - <link rel="stylesheet" type="text/css" href="styles/default.css?v=1.0.1" id="client_theme"> - <link rel="stylesheet" type="text/css" href="styles/chatbox/aa.css?v=1.0.1" id="chatbox_theme"> - <link rel="stylesheet" type="text/css" href="styles/nameplates.css" id="nameplate_setting"> - <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> - <link type="text/css" rel="stylesheet" href="golden/css/goldenlayout.css" /> - <link type="text/css" rel="stylesheet" - href="https://golden-layout.com/files/latest/css/goldenlayout-dark-theme.css" /> - <script src="lib/jdataview.min.js"></script> - <script src="lib/gify.min.js"></script> - <script src="ui.b.js"></script> - <script src="client.b.js?v=1.0.2"></script> -</head> - -<body> - <div id="client_loading"> - <h1 id="client_loadingtext">Loading</h1> - <noscript><p style="color: red;">webAO requires JavaScript to work</p></noscript> - <p>Having trouble? <a href="https://discord.gg/9rYQVVQ">Join us on Discord</a></p> - <button class="client_reconnect" onclick="ReconnectButton()">Reconnect</button> - </div> - <div id="client_charselect"> - <p>Choose your character</p> - <button onclick="pickChar(-1)">Or spectate</button> - <br><br> - <input id="client_charactersearch" placeholder="Search" oninput="chartable_filter(event)"></input> - <br><br> - <div id="client_chartable"></div> - </div> - <div id="client_error" class="error" style="display: none"> - <h1 id="client_errortext">You were disconnected from the server.</h1> - <p style="color: #a00">Code: - <span id="error_id">(none)</span> - </p> - <button class="client_reconnect" onclick="ReconnectButton()">Reconnect</button> - </div> -</body> - -<template id="client_wrapper"> - <meta name="frame-title" lang="en" content="Game"> - <div id="client_icwrapper"> - <div id="client_background"> - <div id="client_gamewindow"> - <div id="client_fullview"> - <img id="client_court" onerror="switchPanTilt(2);" onload="switchPanTilt(1);"> - <div id="client_stitch_court"> - <img id="client_court_def" onerror="imgError(this);"> - <img id="client_court_deft" onerror="imgError(this);"> - <img id="client_court_wit" onerror="imgError(this);"> - <img id="client_court_prot" onerror="imgError(this);"> - <img id="client_court_pro" onerror="imgError(this);"> - </div> - <div id="client_def_pair_char" class="client_char" alt="Paired character"> - <img id="client_def_pair_gif" onerror="charError(this);"> - <img id="client_def_pair_png" onerror="charError(this);"> - <img id="client_def_pair_apng" onerror="charError(this);"> - <img id="client_def_pair_webp" onerror="charError(this);"> - </div> - <div id="client_def_char" class="client_char" alt="Character"> - <img id="client_def_char_gif" onerror="charError(this);"> - <img id="client_def_char_png" onerror="charError(this);"> - <img id="client_def_char_apng" onerror="charError(this);"> - <img id="client_def_char_webp" onerror="charError(this);"> - </div> - <div id="client_wit_pair_char" class="client_char" alt="Paired character"> - <img id="client_wit_pair_gif" onerror="charError(this);"> - <img id="client_wit_pair_png" onerror="charError(this);"> - <img id="client_wit_pair_apng" onerror="charError(this);"> - <img id="client_wit_pair_webp" onerror="charError(this);"> - </div> - <div id="client_wit_char" class="client_char" alt="Character"> - <img id="client_wit_char_gif" onerror="charError(this);"> - <img id="client_wit_char_png" onerror="charError(this);"> - <img id="client_wit_char_apng" onerror="charError(this);"> - <img id="client_wit_char_webp" onerror="charError(this);"> - </div> - <div id="client_pro_pair_char" class="client_char" alt="Paired character"> - <img id="client_pro_pair_gif" onerror="charError(this);"> - <img id="client_pro_pair_png" onerror="charError(this);"> - <img id="client_pro_pair_apng" onerror="charError(this);"> - <img id="client_pro_pair_webp" onerror="charError(this);"> - </div> - <div id="client_pro_char" class="client_char" alt="Character"> - <img id="client_pro_char_gif" onerror="charError(this);"> - <img id="client_pro_char_png" onerror="charError(this);"> - <img id="client_pro_char_apng" onerror="charError(this);"> - <img id="client_pro_char_webp" onerror="charError(this);"> - </div> - <img id="client_def_bench" class="client_bench"> - <img id="client_wit_bench" class="client_bench"> - <img id="client_pro_bench" class="client_bench"> - </div> - <div id="client_classicview"> - <img id="client_court_classic" onerror="imgError(this);"> - <div id="client_pair_char" class="client_char" alt="Paired character"> - <img id="client_pair_gif" onerror="charError(this);"> - <img id="client_pair_png" onerror="charError(this);"> - <img id="client_pair_apng" onerror="charError(this);"> - <img id="client_pair_webp" onerror="charError(this);"> - </div> - <div id="client_char" class="client_char" alt="Character"> - <img id="client_char_gif" onerror="charError(this);"> - <img id="client_char_png" onerror="charError(this);"> - <img id="client_char_apng" onerror="charError(this);"> - <img id="client_char_webp" onerror="charError(this);"> - </div> - <img id="client_bench_classic" class="client_bench"> - </div> - <img id="client_fg" alt="Various overlay" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="> - <img id="client_evi" src="" alt="Character Evidence" onerror="imgError(this);"> - <img id="client_testimony" alt="Testimony overlay" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" onerror="imgError(this);"> - <img id="client_shout" alt="Shout overlay" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="> - <div id="client_chatcontainer" style="font-size: 12px; opacity: 0;"> - <div id="client_chatdecoration"></div> - <div id="client_name"> - <p id="client_inner_name"></p> - </div> - <div id="client_chat"> - <p id="client_inner_chat"></p> - <div id="client_chatwaiting">►</div> - </div> - </div> - <div id="client_trackstatus" style="display: none;"><p id="client_trackstatustext">None</p></div> - </div> - </div> - <input id="client_inputbox" class="long" type="text" onkeypress="onEnter(event)" - placeholder="Say something…" autocomplete="off"> - <div id="client_bars"> - <span id="client_defense_hp" class="health-box"> - <div class="health-bar"></div> - </span> - <span id="client_prosecutor_hp" class="health-box"> - <div class="health-bar"></div> - </span> - </div> - <div id="client_iccontrols"> - <meta name="frame-title" lang="en" content="miscellaneous"> - <div id="client_emo"> - </div> - <br> - <div id="character_options"> - <div id="emote_options"> - <button id="button_1" alt="Hold it!" class="objection_button" onclick="toggleShout(1)">Hold it!</button> - <button id="button_2" alt="Objection!" class="objection_button" - onclick="toggleShout(2)">Objection!</button> - <button id="button_3" alt="Take That!" class="objection_button" onclick="toggleShout(3)">Take - That!</button> - <button id="button_4" alt="Custom" class="objection_button" onclick="toggleShout(4)" style="display: none"> - Custom</button> - <br> - <br> - <label for="textcolor">Text Color:</label> - <select id="textcolor" name="textcolor"> - <option value="0">White</option> - <option value="1">Green</option> - <option value="2">Red</option> - <option value="3">Orange</option> - <option value="4">Blue</option> - </select> - <label for="sendsfx"> SFX: </label> - <input type="checkbox" id="sendsfx" name="sendsfx" value="sendsfx" checked> - <label for="sendpreanim"> Preanimation: </label> - <input type="checkbox" id="sendpreanim" name="sendpreanim" value="sendpreanim"> - <br> - <br> - <button id="button_flip" alt="Flip" class="client_button" onclick="toggleEffect(this)" style="display: none">Flip</button> - <button id="button_flash" alt="Flash" class="client_button" onclick="toggleEffect(this)">Flash</button> - <button id="button_shake" alt="Shake" class="client_button" onclick="toggleEffect(this)" style="display: none">Shake</button> - </div> - <br> - <br> - <div id="character_options"> - <label for="role_select">Role:</label> - <select id="role_select" name="role_select" onchange="changeRoleOOC()"> - <option value="">Default</option> - <option value="def">Defense</option> - <option value="pro">Prosecution</option> - <option value="jud">Judge</option> - <option value="wit">Witness</option> - <option value="hld">Helper Defense</option> - <option value="hlp">Helper Prosecution</option> - <option value="jur">Jury</option> - <option value="sea">Seance</option> - </select> - <br> - <br> - <button id="char_change" alt="Change" class="client_button hover_button" onclick="changeCharacter()">Change - Character</button> - <button id="char_random" alt="Random" class="client_button hover_button" - onclick="randomCharacterOOC()">Random Character</button> - <br> - <br> - <span id="pairing" style="display: none"> - <label for="pair_select">Pairing partner:</label> - <select name="pair_select" id="pair_select"> - <option value="-1">None</option> - </select> - <table style="border: none;margin-left: auto;margin-right: auto;"> - <tr ><td><p>Horizontal offset:</p></td><td><input type="range" name="pair_offset" id="pair_offset" min="-100" max="100" value="0"></td></tr> - <tr id="y_offset" style="display: none"><td><p >Vertical offset:</p></td><td><input type="range" name="pair_y_offset" id="pair_y_offset" min="-100" max="100" value="0"></td></tr> - </table> - <input id="pair_reset" type="button" value="Reset" onclick="resetOffset()"> - <br> - <br> - <br> - <span id="cccc" style="display: none"> - <label for="ic_chat_name">Custom Showname:</label> - <input id="ic_chat_name" name="ic_chat_name" type="text"> - <br> - <label for="showname">Show others:</label> - <input id="showname" name="showname" type="checkbox" onclick="showname_click()"> - <br> - <br> - <label for="check_nonint">Noninterrupting Preanimation:</label> - <input type="checkbox" name="check_nonint" id="check_nonint"> - </span> - <br> - <br> - <span id="2.7" style="display: none"> - <label for="check_loopsfx">Looping SFX:</label> - <input type="checkbox" name="check_loopsfx" id="check_loopsfx"> - </span> - <br> - <br> - <span id="2.8" style="display: none"> - <label for="check_additive">Additive:</label> - <input type="checkbox" name="check_additive" id="check_additive"> - <br> - <br> - <label for="effect_select">Effect:</label> - <select id="effect_select" name="effect_select"> - <option value="||">None</option> - <option value="realization||sfx-realization">Realization</option> - <option value="hearts||sfx-squee">Hearts</option> - <option value="reaction||sfx-reactionding">Reaction</option> - <option value="impact||sfx-fan">Impact</option> - </select> - </span> - </div> - </div> - <fieldset style="margin:10px;"> - <legend>Actions</legend> - <!-- Judge Commands --> - <span id="judge_action" style="display:none"> - <span id="menu_wt" onclick="initWT()" class="judge_button" - style="color: blue"><i>Witness<br>Testimony</i></span> - - <span id="menu_ce" onclick="initCE()" class="judge_button" - style="color: red"><i>Cross<br>Examination</i></span> - - <span id="menu_nguilty" onclick="notguilty()" class="judge_button" - style="color: white; font-family: serif; text-shadow: -1px 0 #000, 0 1px #000, 1px 0 #000, 0 -1px #000; font-size: 1.5em; line-height: 0.75;">Not<br>Guilty</span> - - <span id="menu_guilty" onclick="guilty()" class="judge_button" - style="color: black; font-family: serif; font-size: 1.5em;">Guilty</span> - - <br> - <span style="display:inline-block; vertical-align: middle;"> - <span id="menu_rhpd" onclick="redHPD()" class="healthchange_button"> - ⊟ - </span> - <span style="font-size: 1.25em">Defense</span> - <span id="menu_ahpd" onclick="addHPD()" class="healthchange_button"> - ⊞ - </span> - </span> - <span style="display:inline-block; vertical-align: middle;"> - <span id="menu_ahpp" onclick="addHPP()" class="healthchange_button"> - ⊞ - </span> - <span style="font-size: 1.25em">Prosecution</span> - <span id="menu_rhpp" onclick="redHPP()" class="healthchange_button"> - ⊟ - </span> - </span> - </span> - <!-- No Commands --> - <span id="no_action"> - No judge actions available for this role. - </span> - <br> - <br> - <span id="muting"> - <label for="mute_select" style="float: left">Mute a character: </label> - <select name="mute_select" id="mute_select" size="15" style="float: left" - onchange="mutelist_click(event)"></select> - </span> - </fieldset> - </div> - </div> -</template> - -<template id="mainmenu"> - <meta name="frame-title" lang="en" content="Log"> - <div id="client_menu"> - <div id="client_menu_buttons"> - <div class="hrtext">Main Menu</div> - <span id="menu_1" onclick="toggleMenu(1)" class="menu_button active"> - <b class="menu_icon">📍</b> - <div class="menu_text">Areas</div> - </span> - <span id="menu_2" onclick="toggleMenu(2)" class="menu_button"> - <b class="menu_icon">💼</b> - <div class="menu_text">Evidence</div> - </span> - <span id="menu_3" onclick="toggleMenu(3)" class="menu_button"> - <b class="menu_icon">🔧</b> - <div class="menu_text">Settings</div> - </span> - <span id="menu_4" onclick="toggleMenu(4)" class="menu_button"> - <b class="menu_icon">❓</b> - <div class="menu_text">About</div> - </span> - <span id="menu_cm" onclick="callMod()" class="menu_button"> - <b class="menu_icon">🚨</b> - <div class="menu_text" style="color: #ce2727;">Call Mod</div> - </span> - </div> - <div class="hrtext"> - <span id="content_name">Content</span> - </div> - <!-- Areas section --> - <span class="menu_content active" id="content_1"> - <meta name="frame-title" lang="en" content="Areas"> - <div id="areas"></div> - <br> - <fieldset style="text-align: left"> - <legend>Current Area Background</legend> - <span> - <img id="bg_preview" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" alt="Background Preview" onerror="imgError(this);"> - </span> - <span style="display:inline-block"> - <label for="bg_filename">Background:</label> - <br> - <select id="bg_select" name="bg_select" onchange="updateBackgroundPreview()" - style="margin-top:10px"></select> - <br> - <input id="bg_filename" name="bg_filename" type="text" style="margin-top:10px"> - <br> - <br> - <button id="bg_change" alt="Change" class="client_button hover_button" - onclick="changeBackgroundOOC()">Change</button> - </span> - </fieldset> - <fieldset style="text-align: left; display: none"> - <legend>Timers</legend> - <span id="client_timer0">00:00:00</span> - <span id="client_timer1">00:00:00</span> - <span id="client_timer2">00:00:00</span> - <span id="client_timer3">00:00:00</span> - <span id="client_timer4">00:00:00</span> - <span id="client_timer5">00:00:00</span> - <span id="client_timer6">00:00:00</span> - <span id="client_timer7">00:00:00</span> - <span id="client_timer8">00:00:00</span> - <span id="client_timer9">00:00:00</span> - <span id="client_timer10">00:00:00</span> - <span id="client_timer11">00:00:00</span> - <span id="client_timer12">00:00:00</span> - <span id="client_timer13">00:00:00</span> - <span id="client_timer14">00:00:00</span> - <span id="client_timer15">00:00:00</span> - <span id="client_timer16">00:00:00</span> - <span id="client_timer17">00:00:00</span> - <span id="client_timer18">00:00:00</span> - <span id="client_timer19">00:00:00</span> - <span id="client_timer20">00:00:00</span> - </fieldset> - </span> - - <!-- Evidence section --> - <span class="menu_content" id="content_2"> - <meta name="frame-title" lang="en" content="Evidence"> - <fieldset style="text-align: left; display: flex; flex-direction: column;"> - <legend>Information</legend> - <hr> - <div style="display: flex;"> - <img id="evi_preview" class="evi_icon" src="" alt="Evidence Icon" onerror="imgError(this);"> - <div id="evi_options"> - <input id="evi_name" name="evi_name" type="text" placeholder="Evidence name"> - <br> - <label for="evi_filename">Icon:</label> - <select id="evi_select" name="evi_select" onchange="updateEvidenceIcon()"></select> - <input id="evi_filename" name="evi_filename" type="text" - placeholder="Custom filename"> - </div> - </div> - <hr> - <div style="display: flex; padding-top: 5px;"> - <textarea id="evi_desc" name="evi_desc" rows="2" cols="20" - placeholder="Evidence description"></textarea> - </div> - <div style="display: block; text-align: center; padding-top: 20px;"> - <button id="evi_add" alt="Add Evidence" class="client_button hover_button" - onclick="addEvidence()">Add</button> - <button id="evi_edit" alt="Edit Evidence" class="client_button hover_button inactive" - onclick="editEvidence()">Edit</button> - <button id="evi_cancel" alt="Cancel Evidence" class="client_button hover_button inactive" - onclick="cancelEvidence()">Cancel</button> - <button id="evi_del" alt="Remove Evidence" class="client_button hover_button inactive" - onclick="deleteEvidence()">Remove</button> - </div> - </fieldset> - <br> - <div id="evidences"></div> - <br> - <button id="button_present" alt="Present" class="client_button" onclick="toggleEffect(this)">Present</button> - </span> - - <!-- Settings section --> - <span class="menu_content" id="content_3"> - <meta name="frame-title" lang="en" content="Settings"> - <h2>Volume</h2> - <p>Music</p> - <input id="client_mvolume" class="long" type="range" min="0" max="1" value="1" step="0.01" - onchange="changeMusicVolume()"> - - <p>SFX</p> - <audio id="client_sfxaudio" onvolumechange="changeSFXVolume()" onerror="opusCheck()" controls></audio> - - <p>Shouts</p> - <audio id="client_shoutaudio" onvolumechange="changeShoutVolume()" onerror="opusCheck()" controls></audio> - - <p>Testimony/Guilty</p> - <audio id="client_testimonyaudio" onvolumechange="changeTestimonyVolume()" onerror="opusCheck()" controls></audio> - - <p>Blip</p> - <input id="client_bvolume" class="long" type="range" min="0" max="1" value="1" step="0.01" - onchange="changeBlipVolume()"> - <br> - <br> - <label for="client_themeselect">Menu theme:</label> - <select id="client_themeselect" name="client_themeselect" onchange="reloadTheme()"> - <option value="default" selected>Default</option> - <option value="classic">Classic</option> - <option value="soj">DD / SoJ</option> - <option value="cyber">Cyber</option> - <option value="trilogy">Trilogy</option> - </select> - <br> - <br> - <label for="client_chatboxselect">Chatbox theme:</label> - <select id="client_chatboxselect" name="client_chatboxselect" onchange="setChatbox(this.value)"> - <option value="dynamic" selected>Use characters</option> - <option value="aa">AA</option> - <option value="chatdd">DD / SoJ</option> - <option value="dgs">DGS</option> - <option value="chatplvsaa">PL vs AA</option> - <option value="trilogy">Trilogy</option> - <option value="chatfuture">Future theme</option> - <option value="legacy">old webAO</option> - <option value="chat999">999</option> - <option value="acww">Animal Crossing</option> - <option value="dr1">DR 1</option> - <option value="chatdr2">DR 2</option> - <option value="drv3">DR 3</option> - <option value="drae">DR: AE</option> - <option value="ddlc">DDLC</option> - <option value="homestuck">Homestuck</option> - <option value="key">Key</option> - <option value="n64zelda">N64 Zelda</option> - <option value="papermario">Paper Mario</option> - <option value="chatp3">Persona 3</option> - <option value="p4">Persona 4</option> - <option value="p5">Persona 5</option> - <option value="halla">VA-11 HALL-A</option> - <option value="whentheycry">When They Cry Series</option> - <option value="yakuza">Yakuza</option> - <option value="yttd">YTTD</option> - </select> - <!-- - <br> - <br> - <button id="client_modcall" onclick="modcall_test()">Test modcall</button> - --> - <br> - <br> - <p>Ini editing (experimental)</p> - <label for="client_ininame">Iniedit Character:</label> - <select type="text" id="client_ininame" name="client_ininame"></select> - <button id="client_inichange" onclick="iniedit()">Change</button> - <br> - <br> - <p>Pan-tilt (experimental)</p> - <label for="client_pantilt">Enable:</label> - <input type="checkbox" id="client_pantilt" name="client_pantilt" onclick="switchPanTilt()"> - <br> - <br> - <p>16:9 viewport (experimental)</p> - <label for="client_hdviewport">Enable:</label> - <input type="checkbox" id="client_hdviewport" name="client_hdviewport" onclick="switchAspectRatio()"> - <br> - <label for="client_hdviewport_offset">Offset chatbox:</label> - <input type="checkbox" id="client_hdviewport_offset" id="client_hdviewport_offset" onclick="switchChatOffset()"> - <br> - <br> - <label for="client_callwords">Callwords:</label> - <br> - <textarea id="client_callwords" name="client_callwords" rows="4" cols="10" - placeholder="Put 1 callword per line here" onchange="changeCallwords()"></textarea> - <br> - <br> - <span style="color:red">↓ Only touch these settings if you know what you are doing. ↓</span> - <br> - <br> - <label for="client_encoding">Client side chat encoding:</label> - <select id="client_encoding" name="client_encoding"> - <option value="none" selected>None</option> - <option value="unicode">Unicode</option> - <option value="utf16">UTF-16</option> - </select> - <br> - <br> - <label for="client_decoding">Client side chat decoding:</label> - <select id="client_decoding" name="client_decoding"> - <option value="none">None</option> - <option value="unicode" selected>Unicode</option> - <option value="utf16">UTF-16</option> - </select> - <br> - <br> - <label for="bg_command">Change background command:</label> - <input id="bg_command" name="bg_command" type="text" value="bg $1"> - <br> - <br> - <label for="randomchar_command">Random character command:</label> - <input id="randomchar_command" name="randomchar_command" type="text" value="randomchar"> - <br> - <br> - <span style="color:blue">Changing these settings will save them as a cookie.<br> - By doing so, you agree to it being saved.<br> - If you don't agree, disable cookies for this site in your browser.</span> - </span> - - <!-- About section --> - <span class="menu_content" id="content_4"> - <meta name="frame-title" lang="en" content="About"> - <img id="about-logo" src="images/logo-new.png" alt="Attorney Online logo"> - <h1 style="line-height: .3em;">webAO</h1> - <h3 id="client_version">version</h3> - <p>Client created by - <a href="https://github.com/stonedDiscord">@stonedDiscord</a> and fixed up by - <a href="https://github.com/oldmud0">@oldmud0</a> and - <a href="https://github.com/qubrick">Qubrick</a>.</p> - <p><a href="https://github.com/AttorneyOnline/webAO">Follow development on our GitHub</a></p> - <p>Special thanks to Aleks for the first webAO PoC.</p> - <p><a href="styles/igiari/readme.txt">Igiari font by Caveras</a></p> - </span> - </div> -</template> - -<template id="log"> - <meta name="frame-title" lang="en" content="Log"> - <div id="client_log"> - <div class="hrtext">↓ log starts here ↓</div> - </div> -</template> - -<template id="ooc"> - <meta name="frame-title" lang="en" content="Server"> - <div style="height: 100%; display: flex; flex-direction: column;"> - <textarea id="client_ooclog" style="flex: 1 auto" readonly></textarea> - <span id="client_oocinput"> - <input id="OOC_name" name="OOC_name" type="text"> - <input id="client_oocinputbox" type="text" onkeypress="onOOCEnter(event)"> - </span> - <span id="client_replaycontrols" style="display: none; white-space: nowrap;"> - <input id="client_replaygo" style="width: 25%;" type="button" onclick="onReplayGo(event)" value="GO"> - <input id="client_replaytimer" style="width: 25%;" type="number" value="2000"> - </span> - </div> -</template> - -<template id="music"> - <meta name="frame-title" lang="en" content="Music"> - <input id="client_musicsearch" placeholder="Search" oninput="musiclist_filter(event)"></input> - <select id="client_musiclist" size="5" onchange="musiclist_click(event)"> - </select> -</template> - -</html> diff --git a/webAO/client.js b/webAO/client.js index c10d25b..adab9dd 100644 --- a/webAO/client.js +++ b/webAO/client.js @@ -19,28 +19,29 @@ import vanilla_evidence_arr from './constants/evidence.js'; import chatbox_arr from './styles/chatbox/chatboxes.js'; import iniParse from './iniParse'; -import calculatorHandler from './utils/calculatorHandler.js'; import getCookie from './utils/getCookie.js'; import setCookie from './utils/setCookie.js'; import request from './services/request.js'; +import { changeShoutVolume } from './dom/changeShoutVolume.js'; +import { changeSFXVolume } from './dom/changeSFXVolume.js'; +import setEmote from './client/setEmote.js'; +import fileExists from './utils/fileExists.js'; +import queryParser from './utils/queryParser.js'; +import getAnimLength from './utils/getAnimLength.js'; +import getResources from './utils/getResources.js'; const version = process.env.npm_package_version; let client; let viewport; - // Get the arguments from the URL bar -const queryDict = {}; -location.search.substr(1).split('&').forEach((item) => { - queryDict[item.split('=')[0]] = item.split('=')[1]; -}); - -let { ip: serverIP, mode } = queryDict; - +let { + ip: serverIP, mode, asset, theme, +} = queryParser(); // Unless there is an asset URL specified, use the wasabi one const DEFAULT_HOST = 'http://attorneyoffline.de/base/'; -let AO_HOST = queryDict.asset || DEFAULT_HOST; -const THEME = queryDict.theme || 'default'; +let AO_HOST = asset || DEFAULT_HOST; +const THEME = theme || 'default'; const UPDATE_INTERVAL = 60; @@ -121,44 +122,7 @@ class Client extends EventEmitter { this.banned = false; - this.resources = { - holdit: { - src: `${AO_HOST}misc/default/holdit_bubble.png`, - duration: 720, - }, - objection: { - src: `${AO_HOST}misc/default/objection_bubble.png`, - duration: 720, - }, - takethat: { - src: `${AO_HOST}misc/default/takethat_bubble.png`, - duration: 840, - }, - custom: { - src: '', - duration: 840, - }, - witnesstestimony: { - src: `${AO_HOST}themes/${THEME}/witnesstestimony.gif`, - duration: 1560, - sfx: `${AO_HOST}sounds/general/sfx-testimony.opus`, - }, - crossexamination: { - src: `${AO_HOST}themes/${THEME}/crossexamination.gif`, - duration: 1600, - sfx: `${AO_HOST}sounds/general/sfx-testimony2.opus`, - }, - guilty: { - src: `${AO_HOST}themes/${THEME}/guilty.gif`, - duration: 2870, - sfx: `${AO_HOST}sounds/general/sfx-guilty.opus`, - }, - notguilty: { - src: `${AO_HOST}themes/${THEME}/notguilty.gif`, - duration: 2440, - sfx: `${AO_HOST}sounds/general/sfx-notguilty.opus`, - }, - }; + this.resources = getResources(AO_HOST, THEME); this.selectedEmote = -1; this.selectedEvidence = 0; @@ -220,15 +184,15 @@ class Client extends EventEmitter { } /** - * Gets the player's currently selected emote. - */ + * Gets the player's currently selected emote. + */ get emote() { return this.emotes[this.selectedEmote]; } /** - * Gets the current evidence ID unless the player doesn't want to present any evidence - */ + * Gets the current evidence ID unless the player doesn't want to present any evidence + */ get evidence() { return (document.getElementById('button_present').classList.contains('dark')) ? this.selectedEvidence : 0; } @@ -238,12 +202,7 @@ class Client extends EventEmitter { * @param {string} message the message to send */ sendServer(message) { - console.debug(`C: ${message}`); - if (mode === 'replay') { - this.sendSelf(message); - } else { - this.serv.send(message); - } + mode === 'replay' ? this.sendSelf(message) : this.serv.send(message); } /** @@ -270,7 +229,9 @@ class Client extends EventEmitter { */ sendOOC(message) { setCookie('OOC_name', document.getElementById('OOC_name').value); - this.sendServer(`CT#${escapeChat(encodeChat(document.getElementById('OOC_name').value))}#${escapeChat(encodeChat(message))}#%`); + const oocName = `${escapeChat(encodeChat(document.getElementById('OOC_name').value))}`; + const oocMessage = `${escapeChat(encodeChat(message))}`; + this.sendServer(`CT#${oocName}#${oocMessage}#%`); } /** @@ -427,8 +388,6 @@ class Client extends EventEmitter { * to the server. */ joinServer() { - console.log(`Your emulated HDID is ${hdid}`); - this.sendServer(`HI#${hdid}#%`); this.sendServer('ID#webAO#webAO#%'); if (mode !== 'replay') { this.checkUpdater = setInterval(() => this.sendCheck(), 5000); } @@ -1537,7 +1496,7 @@ class Client extends EventEmitter { this.charID = Number(args[3]); document.getElementById('client_charselect').style.display = 'none'; - const me = this.character; + const me = this.chars[this.charID]; this.selectedEmote = -1; const { emotes } = this; const emotesList = document.getElementById('client_emo'); @@ -1742,22 +1701,6 @@ class Viewport { } /** - * Returns whether or not the viewport is busy - * performing a task (animating). - */ - get isAnimating() { - return this._animating; - } - - /** - * Sets the volume of the blip sounds. - * @param {number} volume - */ - set blipVolume(volume) { - this.blipChannels.forEach((channel) => channel.volume = volume); - } - - /** * Sets the volume of the music. * @param {number} volume */ @@ -1794,21 +1737,21 @@ class Viewport { const bgfolder = viewport.bgFolder; const view = document.getElementById('client_fullview'); - + let bench; if ('def,pro,wit'.includes(position)) { - bench = document.getElementById('client_'+position+'_bench'); + bench = document.getElementById(`client_${position}_bench`); } else { bench = document.getElementById('client_bench_classic'); } - + let court; if ('def,pro,wit'.includes(position)) { - court = document.getElementById('client_court_'+position); + court = document.getElementById(`client_court_${position}`); } else { court = document.getElementById('client_court_classic'); } - + const positions = { def: { bg: 'defenseempty.png', @@ -1867,7 +1810,7 @@ class Viewport { } if (viewport.chatmsg.type === 5) { - console.warn("this is a zoom"); + console.warn('this is a zoom'); court.src = `${AO_HOST}themes/default/${encodeURI(speedLines)}`; bench.style.opacity = 0; } else { @@ -1930,76 +1873,6 @@ class Viewport { } /** - * Gets animation length. If the animation cannot be found, it will - * silently fail and return 0 instead. - * @param {string} filename the animation file name - */ - - async getAnimLength(url) { - const extensions = ['.gif', '.webp']; - for (const extension of extensions) { - const urlWithExtension = url + extension; - const exists = await fileExists(urlWithExtension); - if (exists) { - const fileBuffer = await requestBuffer(urlWithExtension); - const length = calculatorHandler[extension](fileBuffer); - return length; - } - } - return 0; - } - - oneSuccess(promises) { - return Promise.all(promises.map((p) => - // If a request fails, count that as a resolution so it will keep - // waiting for other possible successes. If a request succeeds, - // treat it as a rejection so Promise.all immediately bails out. - p.then( - (val) => Promise.reject(val), - (err) => Promise.resolve(err), - ))).then( - // If '.all' resolved, we've just got an array of errors. - (errors) => Promise.reject(errors), - // If '.all' rejected, we've got the result we wanted. - (val) => Promise.resolve(val), - ); - } - - rejectOnError(f) { - return new Promise((resolve, reject) => f.then((res) => { - if (res.ok) resolve(f); - else reject(f); - })); - } - - /** - * Adds up the frame delays to find out how long a GIF is - * I totally didn't steal this - * @param {data} gifFile the GIF data - */ - calculateGifLength(gifFile) { - const d = new Uint8Array(gifFile); - // Thanks to http://justinsomnia.org/2006/10/gif-animation-duration-calculation/ - // And http://www.w3.org/Graphics/GIF/spec-gif89a.txt - let duration = 0; - for (let i = 0; i < d.length; i++) { - // Find a Graphic Control Extension hex(21F904__ ____ __00) - if (d[i] === 0x21 - && d[i + 1] === 0xF9 - && d[i + 2] === 0x04 - && d[i + 7] === 0x00) { - // Swap 5th and 6th bytes to get the delay per frame - const delay = (d[i + 5] << 8) | (d[i + 4] & 0xFF); - - // Should be aware browsers have a minimum frame delay - // e.g. 6ms for IE, 2ms modern browsers (50fps) - duration += delay < 2 ? 10 : delay; - } - } - return duration * 10; - } - - /** * Updates the testimony overaly */ updateTestimony() { @@ -2038,45 +1911,6 @@ class Viewport { } /** - * Sets all the img tags to the right sources - * @param {*} chatmsg - */ - setEmote(charactername, emotename, prefix, pair, side) { - const pairID = pair ? 'pair' : 'char'; - const characterFolder = `${AO_HOST}characters/`; - const position = 'def,pro,wit'.includes(side) ? `${side}_` : ''; - - const gif_s = document.getElementById(`client_${position}${pairID}_gif`); - const png_s = document.getElementById(`client_${position}${pairID}_png`); - const apng_s = document.getElementById(`client_${position}${pairID}_apng`); - const webp_s = document.getElementById(`client_${position}${pairID}_webp`); - const extensionsMap = { - '.gif': gif_s, - '.png': png_s, - '.apng': apng_s, - '.webp': webp_s, - }; - - for (const [extension, htmlElement] of Object.entries(extensionsMap)) { - // Hides all sprites before creating a new sprite - if (this.lastChar !== this.chatmsg.name) { - htmlElement.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 = fileExistsSync(url); - if (exists) { - htmlElement.src = url; - return; - } - } - } - - /** * Sets a new emote. * This sets up everything before the tick() loops starts * a lot of things can probably be moved here, like starting the shout animation if there is one @@ -2114,7 +1948,8 @@ class Viewport { } this.lastEvi = this.chatmsg.evidence; - if ('def,pro,wit'.includes(this.chatmsg.side)) { + const validSides = ['def', 'pro', 'wit']; + if (validSides.includes(this.chatmsg.side)) { charLayers = document.getElementById(`client_${this.chatmsg.side}_char`); pairLayers = document.getElementById(`client_${this.chatmsg.side}_pair_char`); } @@ -2139,10 +1974,10 @@ class Viewport { checkCallword(this.chatmsg.content); - this.setEmote(this.chatmsg.name.toLowerCase(), this.chatmsg.sprite, '(a)', false, this.chatmsg.side); + setEmote(AO_HOST, this, this.chatmsg.name.toLowerCase(), this.chatmsg.sprite, '(a)', false, this.chatmsg.side); if (this.chatmsg.other_name) { - this.setEmote(this.chatmsg.other_name.toLowerCase(), this.chatmsg.other_emote, '(a)', false, this.chatmsg.side); + setEmote(AO_HOST, this, this.chatmsg.other_name.toLowerCase(), this.chatmsg.other_emote, '(a)', false, this.chatmsg.side); } // gets which shout shall played @@ -2168,23 +2003,15 @@ class Viewport { this.chatmsg.startpreanim = true; let gifLength = 0; - switch (this.chatmsg.type) { - // case 0: - // normal emote, no preanim - case 1: - // play preanim - // Hide message box - chatContainerBox.style.opacity = 0; - // If preanim existed then determine the length - gifLength = await this.getAnimLength(`${AO_HOST}characters/${encodeURI(this.chatmsg.name.toLowerCase())}/${encodeURI(this.chatmsg.preanim)}`); - this.chatmsg.startspeaking = false; - break; - // case 5: - // zoom - default: - this.chatmsg.startspeaking = true; - break; + + if (this.chatmsg.type === 1) { + chatContainerBox.style.opacity = 0; + gifLength = await getAnimLength(`${AO_HOST}characters/${encodeURI(this.chatmsg.name.toLowerCase())}/${encodeURI(this.chatmsg.preanim)}`); + this.chatmsg.startspeaking = false; + } else { + this.chatmsg.startspeaking = true; } + this.chatmsg.preanimdelay = parseInt(gifLength); this.changeBackground(chatmsg.side); @@ -2193,11 +2020,7 @@ class Viewport { resizeChatbox(); // Flip the character - if (this.chatmsg.flip === 1) { - charLayers.style.transform = 'scaleX(-1)'; - } else { - charLayers.style.transform = 'scaleX(1)'; - } + charLayers.style.transform = this.chatmsg.flip === 1 ? 'scaleX(-1)' : 'scaleX(1)'; // Shift by the horizontal offset switch (this.chatmsg.side) { @@ -2220,11 +2043,7 @@ class Viewport { charLayers.style.top = `${Number(this.chatmsg.self_offset[1])}%`; // flip the paired character - if (this.chatmsg.other_flip === 1) { - pairLayers.style.transform = 'scaleX(-1)'; - } else { - pairLayers.style.transform = 'scaleX(1)'; - } + pairLayers.style.transform = this.chatmsg.other_flip === 1 ? 'scaleX(-1)' : 'scaleX(1)'; this.blipChannels.forEach((channel) => channel.src = `${AO_HOST}sounds/general/sfx-blip${encodeURI(this.chatmsg.blips.toLowerCase())}.opus`); @@ -2238,10 +2057,18 @@ class Viewport { // apply effects fg.style.animation = ''; + const badEffects = ['-', 'none']; + if (this.chatmsg.effects[0] && !badEffects.includes(this.chatmsg.effects[i].toLowerCase())) { + const baseEffectUrl = `${AO_HOST}themes/default/effects/`; + fg.src = `${baseEffectUrl}${encodeURI(this.chatmsg.effects[0].toLowerCase())}.webp`; + } else { + fg.src = transparentPNG; + } - if (this.chatmsg.effects[0] && this.chatmsg.effects[0] !== '-' && this.chatmsg.effects[0].toLowerCase() !== 'none' ) { fg.src = `${AO_HOST}themes/default/effects/${encodeURI(this.chatmsg.effects[0].toLowerCase())}.webp`; } else { fg.src = transparentPNG; } - - if (this.chatmsg.sound === '0' || this.chatmsg.sound === '1' || this.chatmsg.sound === '' || this.chatmsg.sound === undefined) { this.chatmsg.sound = this.chatmsg.effects[2]; } + const soundChecks = ['0', '1', '', undefined]; + if (soundChecks.some((check) => this.chatmsg.sound === check)) { + this.chatmsg.sound = this.chatmsg.effects[2]; + } this.tick(); } @@ -2320,7 +2147,7 @@ class Viewport { shoutSprite.style.opacity = 0; shoutSprite.style.animation = ''; const preanim = this.chatmsg.preanim.toLowerCase(); - this.setEmote(charName, preanim, '', false, this.chatmsg.side); + setEmote(AO_HOST, this, charName, preanim, '', false, this.chatmsg.side); charLayers.style.opacity = 1; } @@ -2371,17 +2198,17 @@ class Viewport { } if (this.chatmsg.other_name) { - this.setEmote(pairName, pairEmote, '(a)', true, this.chatmsg.side); + setEmote(AO_HOST, this, pairName, pairEmote, '(a)', true, this.chatmsg.side); pairLayers.style.opacity = 1; } else { pairLayers.style.opacity = 0; } - this.setEmote(charName, charEmote, '(b)', false, this.chatmsg.side); + setEmote(AO_HOST, this, charName, charEmote, '(b)', false, this.chatmsg.side); charLayers.style.opacity = 1; if (this.textnow === this.chatmsg.content) { - this.setEmote(charName, charEmote, '(a)', false, this.chatmsg.side); + setEmote(AO_HOST, this, charName, charEmote, '(a)', false, this.chatmsg.side); charLayers.style.opacity = 1; waitingBox.style.opacity = 1; this._animating = false; @@ -2402,7 +2229,7 @@ class Viewport { if (this.textnow === this.chatmsg.content) { this._animating = false; - this.setEmote(charName, charEmote, '(a)', false, this.chatmsg.side); + setEmote(AO_HOST, this, charName, charEmote, '(a)', false, this.chatmsg.side); charLayers.style.opacity = 1; waitingBox.style.opacity = 1; clearTimeout(this.updater); @@ -2629,22 +2456,6 @@ export function changeMusicVolume() { window.changeMusicVolume = changeMusicVolume; /** - * Triggered by the sound effect volume slider. - */ -export function changeSFXVolume() { - setCookie('sfxVolume', document.getElementById('client_sfxaudio').volume); -} -window.changeSFXVolume = changeSFXVolume; - -/** - * Triggered by the shout volume slider. - */ -export function changeShoutVolume() { - setCookie('shoutVolume', document.getElementById('client_shoutaudio').volume); -} -window.changeShoutVolume = changeShoutVolume; - -/** * Triggered by the testimony volume slider. */ export function changeTestimonyVolume() { @@ -2833,29 +2644,6 @@ async function requestBuffer(url) { } /** - * Checks if a file exists at the specified URI. - * @param {string} url the URI to be checked - */ -async function fileExists(url) { - try { - await request(url); - return true; - } catch (err) { - return false; - } -} -const fileExistsSync = (url) => { - try { - const http = new XMLHttpRequest(); - http.open('HEAD', url, false); - http.send(); - return http.status != 404; - } catch (e) { - return false; - } -}; - -/** * Triggered when the reconnect button is pushed. */ export function ReconnectButton() { @@ -3316,20 +3104,6 @@ export function updateBackgroundPreview() { window.updateBackgroundPreview = updateBackgroundPreview; /** - * Highlights and selects an effect for in-character chat. - * If the same effect button is selected, then the effect is canceled. - * @param {string} effect the new effect to be selected - */ -export function toggleEffect(button) { - if (button.classList.contains('dark')) { - button.className = 'client_button'; - } else { - button.className = 'client_button dark'; - } -} -window.toggleEffect = toggleEffect; - -/** * Highlights and selects a menu. * @param {string} menu the menu to be selected */ diff --git a/webAO/client/setEmote.js b/webAO/client/setEmote.js new file mode 100644 index 0000000..16c95be --- /dev/null +++ b/webAO/client/setEmote.js @@ -0,0 +1,43 @@ +import fileExistsSync from '../utils/fileExistsSync'; + +/** + * Sets all the img tags to the right sources + * @param {*} chatmsg + */ + +const setEmote = (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 gif_s = document.getElementById(`client_${position}${pairID}_gif`); + const png_s = document.getElementById(`client_${position}${pairID}_png`); + const apng_s = document.getElementById(`client_${position}${pairID}_apng`); + const webp_s = document.getElementById(`client_${position}${pairID}_webp`); + const extensionsMap = { + '.gif': gif_s, + '.png': png_s, + '.apng': apng_s, + '.webp': webp_s, + }; + + for (const [extension, htmlElement] of Object.entries(extensionsMap)) { + // Hides all sprites before creating a new sprite + if (client.lastChar !== client.chatmsg.name) { + htmlElement.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 = fileExistsSync(url); + if (exists) { + htmlElement.src = url; + return; + } + } +}; +export default setEmote; diff --git a/webAO/dom/changeSFXVolume.js b/webAO/dom/changeSFXVolume.js new file mode 100644 index 0000000..0c3009f --- /dev/null +++ b/webAO/dom/changeSFXVolume.js @@ -0,0 +1,10 @@ +import setCookie from '../utils/setCookie'; + +/** + * Triggered by the sound effect volume slider. + */ + +export function changeSFXVolume() { + setCookie('sfxVolume', document.getElementById('client_sfxaudio').volume); +} +window.changeSFXVolume = changeSFXVolume; diff --git a/webAO/dom/changeShoutVolume.js b/webAO/dom/changeShoutVolume.js new file mode 100644 index 0000000..db67e2d --- /dev/null +++ b/webAO/dom/changeShoutVolume.js @@ -0,0 +1,10 @@ +import setCookie from '../utils/setCookie'; + +/** + * Triggered by the shout volume slider. + */ + +export function changeShoutVolume() { + setCookie('shoutVolume', document.getElementById('client_shoutaudio').volume); +} +window.changeShoutVolume = changeShoutVolume; diff --git a/webAO/dom/toggleEffect.js b/webAO/dom/toggleEffect.js new file mode 100644 index 0000000..3d19c9c --- /dev/null +++ b/webAO/dom/toggleEffect.js @@ -0,0 +1,13 @@ +/** + * Highlights and selects an effect for in-character chat. + * If the same effect button is selected, then the effect is canceled. + * @param {string} effect the new effect to be selected + */ +export function toggleEffect(button) { + if (button.classList.contains('dark')) { + button.className = 'client_button'; + } else { + button.className = 'client_button dark'; + } +} +window.toggleEffect = toggleEffect; diff --git a/webAO/favicon.ico b/webAO/favicon.ico Binary files differdeleted file mode 100644 index 83b380d..0000000 --- a/webAO/favicon.ico +++ /dev/null diff --git a/webAO/images/desc.png b/webAO/images/desc.png Binary files differdeleted file mode 100644 index 4d8ec37..0000000 --- a/webAO/images/desc.png +++ /dev/null diff --git a/webAO/index.html b/webAO/index.html deleted file mode 100644 index c82cacf..0000000 --- a/webAO/index.html +++ /dev/null @@ -1,126 +0,0 @@ -<html> -<head> - <title>Attorney Online ONLINE</title> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - <meta name="description" content="An off-the-cuff courtroom drama simulator"> - <meta name="author" content="stonedDiscord"> - - <meta property="og:title" content="Attorney Online"> - <meta property="og:description" content="Attorney Online is an online version of the world-renowned courtroom drama simulator that allows you to create and play out cases in an off-the-cuff format."> - <meta property="og:type" content="website"> - <meta property="og:url" content="http://web.aceattorneyonline.com/"> - <meta property="og:image" content="https://repository-images.githubusercontent.com/78860508/89fcba80-aafd-11e9-80db-c5b10c01aba9"> - - <meta property="twitter:card" content="summary_large_image"> - <meta property="twitter:title" content="Attorney Online"> - <meta property="twitter:description" content="Attorney Online is an online version of the world-renowned courtroom drama simulator that allows you to create and play out cases in an off-the-cuff format."> - <meta property="twitter:url" content="http://web.aceattorneyonline.com/"> - <meta property="twitter:image" content="https://repository-images.githubusercontent.com/78860508/89fcba80-aafd-11e9-80db-c5b10c01aba9"> - - <meta http-equiv="Content-Security-Policy" - content="default-src 'self' 'unsafe-inline' 'unsafe-eval' *.aceattorneyonline.com data:; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; connect-src 'self' ws:;"> - <meta http-equiv="X-Content-Security-Policy" - content="default-src 'self' 'unsafe-inline' 'unsafe-eval' *.aceattorneyonline.com data:; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; connect-src 'self' ws:;"> - <meta http-equiv="X-WebKit-CSP" - content="default-src 'self' 'unsafe-inline' 'unsafe-eval' *.aceattorneyonline.com data:; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; connect-src 'self' ws:;"> - - <meta name="viewport" content="width=700, initial-scale=1"> - <meta name="theme-color" content="#2c3d51"> - - <link href="https://fonts.googleapis.com/css?family=Poiret+One" rel="stylesheet"> - <link href="https://fonts.googleapis.com/css?family=Oswald%7CRoboto+Condensed" rel="stylesheet"> - <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"> - <link rel="apple-touch-icon" href="/images/logo-new.png"/> - <link rel="stylesheet" type="text/css" href="styles/master.css"> - <link href="vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet"> - <link rel="icon" href="images/favicon.ico"> - <script src="master.b.js"></script> - <link rel="manifest" href="manifest.json"> - <script> - if ('serviceWorker' in navigator) { - window.addEventListener('load', () => { - navigator.serviceWorker.register('../sw.js').then( () => { - console.log('Service Worker Registered') - }) - }) -} - </script> - - -</head> - -<body> - <nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-dark fixed-top"> - <div class="container"> - <div class="collapse navbar-collapse" id="navbarResponsive"> - <ul class="navbar-nav ml-auto"> - <li class="nav-item"> - <a class="nav-link" href="https://aceattorneyonline.com/#">Home</a> - </li> - <li class="nav-item"> - <a class="nav-link" href="https://aceattorneyonline.com/#about">About</a> - </li> - <li class="nav-item"> - <a class="nav-link" href="https://aceattorneyonline.com/#download">Download</a> - </li> - <li class="nav-item"> - <a class="nav-link" href="https://aceattorneyonline.com/#faq">FAQ</a> - </li> - <li class="nav-item"> - <a class="nav-link" href="https://aceattorneyonline.com/help.html">Help</a> - </li> - <li class="nav-item"> - <a class="nav-link" target="_blank" href="https://discord.gg/wWvQ3pw">Discord</a> - </li> - <li class="nav-item"> - <a class="nav-link" href="https://aceattorneyonline.com/blog">Blog</a> - </li> - <li class="nav-item"> - <a class="nav-link" href="http://web.aceattorneyonline.com/">Play Online</a> - </li> - </ul> - </div> - </div> - </nav> - <div id="serverlist_container"> - <h2>Server List</h2> - <div id="https_error" class="error" style="display: none;"> - <p>https is not supported</p> - <p>Please <a href="http://web.aceattorneyonline.com/">click here</a> to be redirected to the http version</p> - </div> - <div id="ms_error" class="error" style="display: none;"> - <p>Could not connect to the master server.</p> - <p>Please check your firewall.</p> - <p id="ms_error_code">A network error occurred</p> - </div> - <noscript> - <div id="js_error" class="error"> - <p>webAO requires JavaScript to work</p> - </div> - </noscript> - <ul class="serverlist" id="masterlist"> - <li id="server-2" class="available" onmouseover="setServ(-2)"> - <p>Singleplayer (beta)</p> - <a class="button" href="client.html?mode=replay">Try</a> - </li> - <li id="server-1" class="unavailable" onmouseover="setServ(-1)"> - <p>Localhost</p> - <a class="button" href="client.html?mode=watch&ip=127.0.0.1:50001">Watch</a> - <a class="button" href="client.html?mode=join&ip=127.0.0.1:50001">Join</a> - </li> - </ul> - <div id="info_container"> - <p id="serverinfo">Masterserver version - ...</p> - <p id="clientinfo">Client version - ...</p> - <textarea id="masterchat" readonly></textarea> - <p>Having trouble? <a href="https://discord.gg/9rYQVVQ">Join us on Discord</a></p> - </div> - </div> - <div id="serverdescription_container"> - <p id="serverdescription_content"> - </p> - </div> -</body> - -</html>
\ No newline at end of file diff --git a/webAO/logo-new-512.png b/webAO/logo-new-512.png Binary files differdeleted file mode 100644 index 33fd586..0000000 --- a/webAO/logo-new-512.png +++ /dev/null diff --git a/webAO/logo-new.png b/webAO/logo-new.png Binary files differdeleted file mode 100644 index f53fe30..0000000 --- a/webAO/logo-new.png +++ /dev/null diff --git a/webAO/manifest.json b/webAO/manifest.json deleted file mode 100644 index acda5d5..0000000 --- a/webAO/manifest.json +++ /dev/null @@ -1,23 +0,0 @@ - { - "name": "Ace Attorney Online", - "short_name": "WebAO", - "start_url": "index.html", - "scope": "./", - "icons": [ - { - "src": "/logo-new.png", - "sizes": "128x128", - "type": "image/png" - }, - { - "src": "/logo-new-512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "any maskable" - - } - ], - "theme_color": "#2c3d51", - "background_color": "#2c3d51", - "display": "standalone" - }
\ No newline at end of file diff --git a/webAO/master.js b/webAO/master.js index 7e4906e..df79d85 100644 --- a/webAO/master.js +++ b/webAO/master.js @@ -58,7 +58,6 @@ export function setServ(ID) { window.setServ = setServ; function onOpen(_e) { - console.log(`Your emulated HDID is ${hdid}`); masterserver.send('ID#webAO#webAO#%'); masterserver.send('ALL#%'); @@ -120,7 +119,6 @@ function checkOnline(serverID, coIP) { }; oserv.onerror = function (_evt) { - console.warn(`${coIP} threw an error.`); document.getElementById(`server${serverID}`).className = 'unavailable'; }; } diff --git a/webAO/packets/ms.js b/webAO/packets/ms.js new file mode 100644 index 0000000..26851bd --- /dev/null +++ b/webAO/packets/ms.js @@ -0,0 +1,28 @@ +export default { + deskmod, + preanim, + name, + emote, + message, + side, + sfx_name, + emote_modifier, + sfx_delay, + objection_modifier, + evidence, + flip, + realization, + text_color, + showname, + other_charid, + self_hoffset, + self_yoffset, + noninterrupting_preanim, + looping_sfx, + screenshake, + frame_screenshake, + frame_realization, + frame_sfx, + additive, + effect, +}; diff --git a/webAO/styles/master.css b/webAO/styles/master.css index 5d957a0..1ea4796 100644 --- a/webAO/styles/master.css +++ b/webAO/styles/master.css @@ -53,7 +53,7 @@ width: 185px; height: 276px; padding: 0px; - background: url("../images/desc.png") no-repeat; + background: url("../desc.png") no-repeat; border: 2px solid #888; border-radius: 5px; } diff --git a/webAO/sw.js b/webAO/sw.js deleted file mode 100644 index 09a2251..0000000 --- a/webAO/sw.js +++ /dev/null @@ -1,26 +0,0 @@ -const cacheName = 'webAO'; - -// Cache all the files to make a PWA -self.addEventListener('install', (e) => { - e.waitUntil( - caches.open(cacheName).then((cache) => - // Our application only has two files here index.html and manifest.json - // but you can add more such as style.css as your app grows - cache.addAll([ - './', - './index.html', - '../manifest.json', - ])), - ); -}); - -// Our service worker will intercept all fetch requests -// and check if we have cached the file -// if so it will serve the cached file -self.addEventListener('fetch', (event) => { - event.respondWith( - caches.open(cacheName) - .then((cache) => cache.match(event.request, { ignoreSearch: true })) - .then((response) => response || fetch(event.request)), - ); -}); diff --git a/webAO/utils/fileExists.js b/webAO/utils/fileExists.js new file mode 100644 index 0000000..261acda --- /dev/null +++ b/webAO/utils/fileExists.js @@ -0,0 +1,17 @@ +const fileExists = async (url) => { + const xhr = new XMLHttpRequest(); + xhr.open('GET', url, true); + xhr.onload = function (e) { + if (xhr.readyState === 4) { + if (xhr.status === 200) { + return true; + } + return false; + } + }; + xhr.onerror = function (e) { + return false; + }; + xhr.send(null); +}; +export default fileExists; diff --git a/webAO/utils/fileExistsSync.js b/webAO/utils/fileExistsSync.js new file mode 100644 index 0000000..1d7fde2 --- /dev/null +++ b/webAO/utils/fileExistsSync.js @@ -0,0 +1,11 @@ +const fileExistsSync = (url) => { + try { + const http = new XMLHttpRequest(); + http.open('HEAD', url, false); + http.send(); + return http.status != 404; + } catch (e) { + return false; + } +}; +export default fileExistsSync; diff --git a/webAO/utils/getAnimLength.js b/webAO/utils/getAnimLength.js new file mode 100644 index 0000000..e64703f --- /dev/null +++ b/webAO/utils/getAnimLength.js @@ -0,0 +1,22 @@ +import calculatorHandler from './calculatorHandler'; +import fileExists from './fileExists.js'; +/** + * Gets animation length. If the animation cannot be found, it will + * silently fail and return 0 instead. + * @param {string} filename the animation file name + */ + +const getAnimLength = async (url) => { + const extensions = ['.gif', '.webp']; + for (const extension of extensions) { + const urlWithExtension = url + extension; + const exists = await fileExists(urlWithExtension); + if (exists) { + const fileBuffer = await requestBuffer(urlWithExtension); + const length = calculatorHandler[extension](fileBuffer); + return length; + } + } + return 0; +}; +export default getAnimLength; diff --git a/webAO/utils/getResources.js b/webAO/utils/getResources.js new file mode 100644 index 0000000..a0c513e --- /dev/null +++ b/webAO/utils/getResources.js @@ -0,0 +1,39 @@ +const getResources = (AO_HOST, THEME) => ({ + holdit: { + src: `${AO_HOST}misc/default/holdit_bubble.png`, + duration: 720, + }, + objection: { + src: `${AO_HOST}misc/default/objection_bubble.png`, + duration: 720, + }, + takethat: { + src: `${AO_HOST}misc/default/takethat_bubble.png`, + duration: 840, + }, + custom: { + src: '', + duration: 840, + }, + witnesstestimony: { + src: `${AO_HOST}themes/${THEME}/witnesstestimony.gif`, + duration: 1560, + sfx: `${AO_HOST}sounds/general/sfx-testimony.opus`, + }, + crossexamination: { + src: `${AO_HOST}themes/${THEME}/crossexamination.gif`, + duration: 1600, + sfx: `${AO_HOST}sounds/general/sfx-testimony2.opus`, + }, + guilty: { + src: `${AO_HOST}themes/${THEME}/guilty.gif`, + duration: 2870, + sfx: `${AO_HOST}sounds/general/sfx-guilty.opus`, + }, + notguilty: { + src: `${AO_HOST}themes/${THEME}/notguilty.gif`, + duration: 2440, + sfx: `${AO_HOST}sounds/general/sfx-notguilty.opus`, + }, +}); +export default getResources; diff --git a/webAO/utils/queryParser.js b/webAO/utils/queryParser.js new file mode 100644 index 0000000..1c2b83a --- /dev/null +++ b/webAO/utils/queryParser.js @@ -0,0 +1,9 @@ +// Get the arguments from the URL bar +const queryParser = () => { + const queryDict = {}; + location.search.substr(1).split('&').forEach((item) => { + queryDict[item.split('=')[0]] = item.split('=')[1]; + }); + return queryDict; +}; +export default queryParser; |
