4 <meta charset="utf-8" http-equiv="Content-Language" content="en"/>
5 <title>FreeSpace Standalone</title>
8 var std = new WebSocket((location.protocol === "https:" ? "wss" : "ws") + "://" + location.host, "standalone");
11 std.onclose = function(event) {
12 if (event.code == 1006) {
13 popup("Connection Error;Connection rejected by server;")
15 document.getElementById("dbg").textContent = "socket closed: " + event.code;
19 std.onmessage = function(msg) {
20 if (msg.data == "reset") {
22 } else if (msg.data.substring(0, 6) == "popup ") {
23 popup(msg.data.substr(6));
24 } else if (msg.data[0] == 'D') {
25 document.getElementById("dbg").textContent = msg.data.substr(2);
26 } else if (msg.data[0] == 'T') {
27 document.title = msg.data.substr(2);
28 } else if (msg.data[0] == 'S') {
29 do_server_tab(msg.data.substr(2));
30 } else if (msg.data[0] == 'M') {
31 do_multi_tab(msg.data.substr(2));
32 } else if (msg.data[0] == 'P') {
33 do_player_tab(msg.data.substr(2));
34 } else if (msg.data[0] == 'G') {
35 do_gs_tab(msg.data.substr(2));
39 alert('<p>Error ' + exception);
46 popup("Shutdown;Shutdown complete;");
50 var modal = document.getElementById("pop");
51 var content = [ document.getElementById("pop-t"), document.getElementById("pop-1"), document.getElementById("pop-2") ];
55 var fields = msg.split(';');
57 for (x = 0; x < fields.length; x++) {
58 content[x].textContent = fields[x];
61 modal.style.display = "block";
63 modal.style.display = "none";
73 document.getElementById("pop").style.display = "none";
76 document.getElementById("s_ncon").textContent = "0";
77 table = document.getElementById("s_conn");
78 len = table.rows.length;
80 for (j = 1; j < len; j++) {
81 table.rows[j].onclick = '';
82 table.rows[j].cells[0].innerHTML = ' ';
83 table.rows[j].cells[1].innerHTML = "";
86 /* multi-player tab */
87 document.getElementById("fps_rel").textContent = "0.0";
88 document.getElementById("m_name").textContent = "";
89 document.getElementById("m_time").textContent = "";
91 document.getElementById("m_ng_p").textContent = "";
92 document.getElementById("m_ng_o").textContent = "";
93 document.getElementById("m_ng_s").textContent = "";
94 document.getElementById("m_ng_r").textContent = "";
96 table = document.getElementById("m_g");
97 len = table.rows.length;
99 for (j = 1; j < len; j++) {
100 var cell = table.rows[j].cells[0];
102 if (cell.childNodes.length > 1) {
103 cell.removeChild(cell.childNodes[1]);
107 /* player info tab */
108 document.getElementById("p_p").selectedIndex = -1;
109 document.getElementById("p_s_t").textContent = "";
110 document.getElementById("p_ping").textContent = "";
112 table = document.getElementById("p_s");
113 len = table.rows.length;
115 for (j = 1; j < len; j++) {
116 table.rows[j].cells[1].innerHTML = "";
117 table.rows[j].cells[2].innerHTML = "";
121 document.getElementById("g_p").selectedIndex = -1;
122 document.getElementById("g_b").value = "";
125 function do_server_tab(msg) {
131 if (msg.substring(0, 5) == "name ") {
132 document.getElementById("s_name").value = msg.substr(5);
133 } else if (msg.substring(0, 5) == "pass ") {
134 document.getElementById("s_pass").value = msg.substr(5);
135 } else if (msg.substring(0, 5) == "ping ") {
136 table = document.getElementById("s_conn");
137 var ping_list = msg.substr(5).split(',', 12);
138 len = ping_list.length;
140 for (j = 0; j < len; j++) {
141 table.rows[j+1].cells[1].innerHTML = ping_list[j];
143 } else if (msg.substring(0, 5) == "conn ") {
144 table = document.getElementById("s_conn");
145 var players = document.getElementById("p_p");
148 var gs_players = document.getElementById("g_p");
149 var connections = msg.substr(5).split(';', 12);
151 /* save currently selected player to restore later */
152 if (players.selectedIndex != -1) {
153 cur_player = players.value;
156 while (players.options.length) {
158 gs_players.remove(0);
161 /* new connections */
162 len = connections.length;
164 document.getElementById("s_ncon").textContent = len;
166 for (j = 0; j < len; j++) {
167 var conn = connections[j].split(',');
168 row = table.rows[j+1];
170 var option = document.createElement("option");
171 option.text = conn[0];
172 gs_players.add(option);
174 option = document.createElement("option");
175 option.text = conn[0];
178 /* maybe reselect player */
179 if ( Boolean(cur_player) && conn[0] == cur_player ) {
183 row.cells[0].innerHTML = conn[1];
185 row.onclick = function() { kick_conn(conn[0], conn[1]); };
188 len = table.rows.length;
190 for (j = j+1; j < len; j++) {
194 row.cells[0].innerHTML = " "
195 row.cells[1].innerHTML = "";
198 gs_players.selectedIndex = -1;
199 players.selectedIndex = new_index;
201 if (new_index != -1) {
202 players.value = cur_player;
205 /* re-request player info, or reset values */
210 function do_multi_tab(msg) {
211 if (msg.substring(0, 5) == "rfps ") {
212 document.getElementById("fps_rel").textContent = msg.substr(4);
213 } else if (msg.substring(0, 5) == "name ") {
214 document.getElementById("m_name").textContent = msg.substr(5);
215 } else if (msg.substring(0, 5) == "time ") {
216 document.getElementById("m_time").textContent = msg.substr(5);
217 } else if (msg.substring(0, 5) == "info ") {
218 var nginfo = msg.substr(5).split(',');
219 document.getElementById("m_ng_p").textContent = nginfo[0];
220 document.getElementById("m_ng_o").textContent = nginfo[1];
221 document.getElementById("m_ng_s").textContent = nginfo[2];
222 document.getElementById("m_ng_r").textContent = nginfo[3];
223 } else if (msg.substring(0, 5) == "goal ") {
224 var objectives = msg.substr(5).split(';');
225 var gtable = document.getElementById("m_g");
231 j_len = objectives.length;
233 for (j = 0; j < j_len; j++) {
234 var goals = objectives[j].split(',');
235 var cell = gtable.rows[j+1].cells[0];
237 if (cell.childNodes.length > 1) {
238 cell.removeChild(cell.childNodes[1]);
241 var list = document.createElement("ul");
243 x_len = goals.length;
245 for (x = 0; x < x_len; x++) {
246 var item = document.createElement("li");
247 item.innerHTML = goals[x].substr(2);
249 var status = goals[x].substring(0, 2);
250 if (status == "c ") {
251 item.style.color = "green";
252 } else if (status == "f ") {
253 item.style.color = "red";
255 item.style.color = "#555";
258 list.appendChild(item);
261 cell.appendChild(list);
266 function do_player_tab(msg) {
267 if (msg.substring(0, 5) == "info ") {
268 var pinfo = msg.substr(5).split(';');
270 document.getElementById("p_s_t").textContent = pinfo[0];
271 document.getElementById("p_ping").textContent = pinfo[1];
273 var all_stats = pinfo[2].split(',');
274 var mission_stats = pinfo[3].split(',');
275 var table = document.getElementById("p_s");
277 var len = table.rows.length;
279 for (j = 0; j < len; j++) {
280 var row = table.rows[j+1];
282 row.cells[1].innerHTML = all_stats[j];
283 row.cells[2].innerHTML = mission_stats[j];
288 function do_gs_tab(msg) {
289 if (msg.substring(0, 5) == "mesg ") {
290 document.getElementById("g_b").value += msg.substr(5);
294 function change_s_name() {
295 std.send("S:name " + document.getElementById("s_name").value);
298 function change_s_pass() {
299 std.send("S:pass " + document.getElementById("s_pass").value);
302 function kick_conn(name, addr) {
303 var kick = confirm("Kick player? \n\n" + name + "@" + addr);
306 std.send("S:kick " + addr);
310 function send_smsg() {
311 var smsg = document.getElementById("g_m");
312 std.send("G:smsg " + smsg.value);
316 function mrefresh() {
317 std.send("G:mrefresh");
320 function switch_tab(tab) {
321 var tabbox = document.getElementById("tab-box");
322 var nav = document.getElementById("nav");
325 for (x = 0; x < 4; x++) {
327 nav.children[x].children[0].className = "active";
328 tabbox.children[x].className = "tab-visible";
330 nav.children[x].children[0].className = '';
331 tabbox.children[x].className = "tab-hidden";
336 function smsg_submit(e) {
337 e = e || window.event;
339 if (e.keyCode == 13) {
340 document.getElementById("g_s").click();
347 function get_pinfo() {
348 var players = document.getElementById("p_p");
350 if (players.selectedIndex != -1) {
351 std.send("P:info " + players.value);
353 document.getElementById("p_s_t").textContent = "";
354 document.getElementById("p_ping").textContent = "";
356 var table = document.getElementById("p_s");
357 var len = table.rows.length;
359 for (var j = 1; j < len; j++) {
360 table.rows[j].cells[1].innerHTML = "";
361 table.rows[j].cells[2].innerHTML = "";
367 var fps = document.getElementById("m_fps").value;
368 document.getElementById("fps_connap").textContent = fps;
370 std.send("M:fps " + fps);
374 <style type="text/css">
376 font-family: Arial, Helvetica, sans-serif
385 background-color: #ddd;
394 display: inline-block;
401 background-color: #444;
405 text-decoration: none;
406 display: inline-block;
412 background-color: #111;
417 list-style-type: none;
421 background-color: #3a3a3a
429 display: inline-block;
433 text-decoration: none;
442 background-color: #111;
452 background-color: #8b0000
455 #nav li.shutdown a:hover {
456 background-color: red;
476 border: 1px solid #444;
478 border-collapse: collapse;
485 background-color: #444;
496 font-family: Courier New, Courier, monospace;
500 #s_conn tr:nth-child(odd),
501 #p_s tr:nth-child(odd) {
502 background-color: #d5d5d5
506 #s_conn tr:hover:nth-child(odd) {
507 background-color: #eaeaea
523 box-sizing: border-box
540 box-sizing: border-box;
542 background-color: #fff;
543 border: 1px solid #bbb;
550 border-collapse: collapse
558 font-family: Courier New, Courier, monospace;
566 display: inline-block;
572 font-family: Courier New, Courier, monospace;
573 padding: 5px 0 5px 10px
579 box-sizing: border-box
595 border-collapse: collapse;
596 display: inline-block
607 background-color: #fff;
618 border-bottom: 1px solid #444
622 background-color: #ddd;
646 background-color: #000;
647 background-color: rgba(0, 0, 0, .4)
651 background-color: #fefefe;
653 border: 2px solid #111;
658 background-color: #444;
674 <div class="container">
676 <li><a onclick="switch_tab(0);" href="javascript:void(0);" class="active">Server</a></li>
677 <li><a onclick="switch_tab(1);" href="javascript:void(0);">Multi-Player</a></li>
678 <li><a onclick="switch_tab(2);" href="javascript:void(0);">Player Info</a></li>
679 <li><a onclick="switch_tab(3);" href="javascript:void(0);">God Stuff</a></li>
680 <li class="shutdown"><a onclick="shutdown();" href="javascript:void(0);">Shutdown</a></li>
683 <div class="tab-box" id="tab-box">
685 <div class="tab-visible">
686 <table class="s_n_p">
687 <tr><td><label for="s_name">Server Name </label></td><td><input id="s_name" type="text" value="" maxlength="31" onchange="change_s_name();"></td></tr>
688 <tr><td><label for="s_pass">Host Password </label></td><td><input id="s_pass" type="text" value="" maxlength="15" onchange="change_s_pass();"></td></tr>
691 <p>Connections : <span id="s_ncon">0</span></p>
694 <tr><th style="min-width:20em;">IP Address</th><th style="min-width:6em;">Ping</th></tr>
695 <tr><td> </td><td></td></tr>
696 <tr><td> </td><td></td></tr>
697 <tr><td> </td><td></td></tr>
698 <tr><td> </td><td></td></tr>
699 <tr><td> </td><td></td></tr>
700 <tr><td> </td><td></td></tr>
701 <tr><td> </td><td></td></tr>
702 <tr><td> </td><td></td></tr>
703 <tr><td> </td><td></td></tr>
704 <tr><td> </td><td></td></tr>
705 <tr><td> </td><td></td></tr>
706 <tr><td> </td><td></td></tr>
711 <!-- multi-player tab -->
712 <div class="tab-hidden">
714 <input type="range" id="m_fps" min="10" max="120" value="60" step="1" oninput="set_fps();">
716 Frame Cap: <span id="fps_connap">60</span>
719 Realiazed FPS: <span id="fps_rel">0.0</span>
724 <tr><td>Mission Name: </td><td><span id="m_name"></span></td></tr>
725 <tr><td>Mission Time: </td><td><span id="m_time"></span></td></tr>
728 <tr><th>Mission Goals</th></tr>
729 <tr><td>Primary Objectives</td></tr>
730 <tr><td>Secondary Objectives</td></tr>
731 <tr><td>Bonus Objectives</td></tr>
734 <tr><th colspan="2">Netgame Information</th></tr>
735 <tr><td>Max Players</td><td><span id="m_ng_p"></span></td></tr>
736 <tr><td>Max Observers</td><td><span id="m_ng_o"></span></td></tr>
737 <tr><td>Security</td><td><span id="m_ng_s"></span></td></tr>
738 <tr><td>Respawns</td><td><span id="m_ng_r"></span></td></tr>
743 <div class="tab-hidden">
744 <div class="players">
745 <label for="p_p">Player</label>
746 <select id="p_p" onchange="get_pinfo();">
750 <tr><td>Ship Type: </td><td><span id="p_s_t"></span></td></tr>
751 <tr><td>Avg Ping: </td><td><span id="p_ping"></span></td></tr>
755 <tr><th>Stats</th><th>All Time</th><th>Mission</th></tr>
756 <tr><td>Primary Shots</td><td></td><td></td></tr>
757 <tr><td>Primary Hits</td><td></td><td></td></tr>
758 <tr><td>Primary BH Hits</td><td></td><td></td></tr>
759 <tr><td>Primary Hit %</td><td></td><td></td></tr>
760 <tr><td>Primary BH Hit %</td><td></td><td></td></tr>
761 <tr><td>Secondary Shots</td><td></td><td></td></tr>
762 <tr><td>Secondary Hits</td><td></td><td></td></tr>
763 <tr><td>Secondary BH Hits</td><td></td><td></td></tr>
764 <tr><td>Secondary Hit %</td><td></td><td></td></tr>
765 <tr><td>Secondary BH Hit %</td><td></td><td></td></tr>
766 <tr><td>Assists</td><td></td><td></td></tr>
772 <div class="tab-hidden">
773 <div class="players">
774 <label for="g_p">Player</label>
780 <label for="g_m">Server Message</label>
782 <input id="g_m" type="text" value="" onkeypress="return smsg_submit(event);">
783 <input id="g_s" type="button" onclick="send_smsg();" style="display:none;">
785 <textarea readonly rows="20" id="g_b" autocomplete="off"></textarea>
788 <input class="button" type="button" value="Refresh Missions" onclick="mrefresh();">
798 <div id="pop-t"></div>
800 <span id="pop-1"></span> <span id="pop-2"></span>