4 <meta charset="utf-8" http-equiv="Content-Language" content="en"/>
5 <title>FreeSpace Standalone</title>
8 var standalone_socket = new WebSocket("ws://" + document.URL.substr(7).split('/')[0], "standalone");
11 standalone_socket.onmessage = function got_packet(msg) {
12 if (msg.data == "reset") {
14 } else if (msg.data.substring(0, 6) == "popup ") {
15 popup(msg.data.substr(6));
16 } else if (msg.data[0] == 'D') {
17 document.getElementById("debug").textContent = msg.data.substr(2);
18 } else if (msg.data[0] == 'T') {
19 document.title = msg.data.substr(2);
20 } else if (msg.data[0] == 'S') {
21 do_server_tab(msg.data.substr(2));
22 } else if (msg.data[0] == 'M') {
23 do_multi_tab(msg.data.substr(2));
24 } else if (msg.data[0] == 'P') {
25 do_player_tab(msg.data.substr(2));
26 } else if (msg.data[0] == 'G') {
27 do_gs_tab(msg.data.substr(2));
31 alert('<p>Error ' + exception);
35 standalone_socket.send("shutdown");
36 standalone_socket.close();
38 popup("Shutdown;Shutdown complete;");
42 var modal = document.getElementById("popup");
43 var content = [ document.getElementById("modal-title"), document.getElementById("field1"), document.getElementById("field2") ];
47 var fields = msg.split(';');
49 for (x = 0; x < fields.length; x++) {
50 content[x].textContent = fields[x];
53 modal.style.display = "block";
55 modal.style.display = "none";
65 document.getElementById("popup").style.display = "none";
68 document.getElementById("n_conn").textContent = "0";
69 table = document.getElementById("connections");
70 len = table.rows.length;
72 for (j = 1; j < len; j++) {
73 table.rows[j].id = '';
74 table.rows[j].onclick = '';
75 table.rows[j].cells[0].innerHTML = ' ';
76 table.rows[j].cells[1].innerHTML = "";
79 /* multi-player tab */
80 document.getElementById("fps_rel").textContent = "0.0";
81 document.getElementById("mission_name").textContent = "";
82 document.getElementById("mission_time").textContent = "";
84 document.getElementById("max_players").textContent = "";
85 document.getElementById("max_observers").textContent = "";
86 document.getElementById("security").textContent = "";
87 document.getElementById("respawns").textContent = "";
89 table = document.getElementById("mgoals");
90 len = table.rows.length;
92 for (j = 1; j < len; j++) {
93 var cell = table.rows[j].cells[0];
95 if (cell.childNodes.length > 1) {
96 cell.removeChild(cell.childNodes[1]);
100 /* player info tab */
101 document.getElementById("players").selectedIndex = -1;
102 document.getElementById("ship_type").textContent = "";
103 document.getElementById("player_ping").textContent = "";
105 table = document.getElementById("stats");
106 len = table.rows.length;
108 for (j = 1; j < len; j++) {
109 table.rows[j].cells[1].innerHTML = "";
110 table.rows[j].cells[2].innerHTML = "";
114 document.getElementById("gs_players").selectedIndex = -1;
115 document.getElementById("smsg_box").value = "";
118 function do_server_tab(msg) {
124 if (msg.substring(0, 5) == "name ") {
125 document.getElementById("server_name").value = msg.substr(5);
126 } else if (msg.substring(0, 5) == "pass ") {
127 document.getElementById("host_pass").value = msg.substr(5);
128 } else if (msg.substring(0, 5) == "ping ") {
129 table = document.getElementById("connections");
130 var ping_list = msg.substr(5).split(';', 12);
131 len = ping_list.length;
133 for (j = 0; j < len; j++) {
134 var ping = ping_list[j].split(',');
135 row = table.rows.namedItem(ping[0]);
138 row.cells[1].innerHTML = ping[1];
141 } else if (msg.substring(0, 5) == "conn ") {
142 table = document.getElementById("connections");
143 var players = document.getElementById("players");
145 var gs_players = document.getElementById("gs_players");
146 var connections = msg.substr(5).split(';', 12);
147 len = connections.length - 1;
149 if (players.selectedIndex != -1) {
150 cur_player = players.value;
153 while (players.options.length) {
155 gs_players.remove(0);
158 for (j = 0; j < len; j++) {
159 var conn = connections[j].split(',');
160 row = table.rows[j+1];
162 var option = document.createElement("option");
163 option.text = conn[0];
164 gs_players.add(option);
166 option = document.createElement("option");
167 option.text = conn[0];
171 row.cells[0].innerHTML = conn[1];
173 if (Boolean(conn[2])) {
174 row.cells[1].innerHTML = conn[2];
177 row.onclick = function() { kick_conn(conn[0], conn[1]); };
180 gs_players.selectedIndex = -1;
181 players.value = cur_player;
182 document.getElementById("n_conn").textContent = j;
184 len = table.rows.length;
186 for (j = j+1; j < len; j++) {
191 row.cells[0].innerHTML = " "
192 row.cells[1].innetHTML = "";
197 function do_multi_tab(msg) {
198 if (msg.substring(0, 4) == "fps ") {
199 document.getElementById("fps_rel").textContent = msg.substr(4);
200 } else if (msg.substring(0, 5) == "name ") {
201 document.getElementById("mission_name").textContent = msg.substr(5);
202 } else if (msg.substring(0, 5) == "time ") {
203 document.getElementById("mission_time").textContent = msg.substr(5);
204 } else if (msg.substring(0, 5) == "info ") {
205 var nginfo = msg.substr(5).split(',');
206 document.getElementById("max_players").textContent = nginfo[0];
207 document.getElementById("max_observers").textContent = nginfo[1];
208 document.getElementById("security").textContent = nginfo[2];
209 document.getElementById("respawns").textContent = nginfo[3];
210 } else if (msg.substring(0, 5) == "goal ") {
211 var objectives = msg.substr(5).split(';');
212 var gtable = document.getElementById("mgoals");
218 j_len = objectives.length;
220 for (j = 0; j < j_len; j++) {
221 var goals = objectives[j].split(',');
222 var cell = gtable.rows[j+1].cells[0];
224 if (cell.childNodes.length > 1) {
225 cell.removeChild(cell.childNodes[1]);
228 var list = document.createElement("ul");
230 x_len = goals.length;
232 for (x = 0; x < x_len; x++) {
233 var item = document.createElement("li");
234 item.innerHTML = goals[x].substr(2);
236 var status = goals[x].substring(0, 2);
237 if (status == "c ") {
238 item.style.color = "green";
239 } else if (status == "f ") {
240 item.style.color = "red";
242 item.style.color = "#555";
245 list.appendChild(item);
248 cell.appendChild(list);
253 function do_player_tab(msg) {
254 if (msg.substring(0, 5) == "info ") {
255 var pinfo = msg.substr(5).split(';');
257 document.getElementById("ship_type").textContent = pinfo[0];
258 document.getElementById("player_ping").textContent = pinfo[1];
260 var all_stats = pinfo[2].split(',');
261 var mission_stats = pinfo[3].split(',');
262 var table = document.getElementById("stats");
264 var len = table.rows.length;
266 for (j = 1; j < len; j++) {
267 var row = table.rows[j];
269 row.cells[1].innerHTML = all_stats[j-1];
270 row.cells[2].innerHTML = mission_stats[j-1];
275 function do_gs_tab(msg) {
276 if (msg.substring(0, 5) == "mesg ") {
277 document.getElementById("smsg_box").value += msg.substr(5);
281 function change_server_name() {
282 standalone_socket.send("S:name " + document.getElementById("server_name").value);
285 function change_host_pass() {
286 standalone_socket.send("S:pass " + document.getElementById("host_pass").value);
289 function kick_conn(name, addr) {
290 var kick = confirm("Kick player? \n\n" + name + "@" + addr);
293 standalone_socket.send("S:kick " + addr);
297 function send_server_message() {
298 var smsg = document.getElementById("server_message");
299 standalone_socket.send("G:smsg " + smsg.value);
303 function refresh_missions() {
304 standalone_socket.send("G:mrefresh");
307 function switch_tab(tab) {
308 var tabbox = document.getElementById("tab-box");
309 var topnav = document.getElementById("topnav");
312 for (x = 0; x < 4; x++) {
314 topnav.children[x].children[0].className = "active";
315 tabbox.children[x].className = "tab-visible";
317 topnav.children[x].children[0].className = '';
318 tabbox.children[x].className = "tab-hidden";
323 function smsg_submit(e) {
324 e = e || window.event;
326 if (e.keyCode == 13) {
327 document.getElementById("smsg_submit").click();
334 function get_player_info() {
335 var n = document.getElementById("players").selectedIndex;
338 standalone_socket.send("P:info " + document.getElementById("players").options[n].text);
343 var fps = document.getElementById("multi_fps").value;
344 document.getElementById("fps_cap").textContent = fps;
346 standalone_socket.send("M:fps " + fps);
350 <style type="text/css">
352 font-family: Arial, Helvetica, sans-serif
361 background-color: #ddd;
370 display: inline-block;
377 background-color: #444;
381 text-decoration: none;
382 display: inline-block;
388 background-color: #111;
393 list-style-type: none;
397 background-color: #3a3a3a
405 display: inline-block;
409 text-decoration: none;
418 background-color: #111;
422 ul.topnav li.shutdown {
427 ul.topnav li.shutdown a {
428 background-color: #8b0000
431 ul.topnav li.shutdown a:hover {
432 background-color: red;
452 border: 1px solid #444;
454 border-collapse: collapse;
461 background-color: #444;
472 font-family: Courier New, Courier, monospace;
476 #connections tr:nth-child(odd),
477 #stats tr:nth-child(odd) {
478 background-color: #d5d5d5
481 #connections tr:hover,
482 #connections tr:hover:nth-child(odd) {
483 background-color: #eaeaea
490 table.name_pass label {
499 box-sizing: border-box
511 box-sizing: border-box;
513 background-color: #fff;
514 border: 1px solid #bbb;
523 border-collapse: collapse
533 font-family: Courier New, Courier, monospace;
545 display: inline-block;
553 box-sizing: border-box
568 font-family: Courier New, Courier, monospace;
569 padding: 5px 0 5px 10px
575 border-collapse: collapse;
576 display: inline-block
587 background-color: #fff;
598 border-bottom: 1px solid #444
602 background-color: #ddd;
626 background-color: #000;
627 background-color: rgba(0, 0, 0, .4)
631 background-color: #fefefe;
633 border: 2px solid #111;
638 background-color: #444;
654 <div class="container">
655 <ul class="topnav" id="topnav">
656 <li><a onclick="switch_tab(0);" href="javascript:void(0);" class="active">Server</a></li>
657 <li><a onclick="switch_tab(1);" href="javascript:void(0);">Multi-Player</a></li>
658 <li><a onclick="switch_tab(2);" href="javascript:void(0);">Player Info</a></li>
659 <li><a onclick="switch_tab(3);" href="javascript:void(0);">God Stuff</a></li>
660 <li class="shutdown"><a onclick="shutdown();" href="javascript:void(0);">Shutdown</a></li>
663 <div class="tab-box" id="tab-box">
664 <div id="server_tab" class="tab-visible">
665 <table class="name_pass">
666 <tr><td><label for="server_name">Server Name </label></td><td><input id="server_name" type="text" value="" maxlength="31" onchange="change_server_name();"></td></tr>
667 <tr><td><label for="host_pass">Host Password </label></td><td><input id="host_pass" type="text" value="" maxlength="15" onchange="change_host_pass();"></td></tr>
670 <p>Connections : <span id="n_conn">0</span></p>
672 <table id="connections">
673 <tr><th style="min-width:20em;">IP Address</th><th style="min-width:5em;">Ping</th></tr>
674 <tr><td> </td><td></td></tr>
675 <tr><td> </td><td></td></tr>
676 <tr><td> </td><td></td></tr>
677 <tr><td> </td><td></td></tr>
678 <tr><td> </td><td></td></tr>
679 <tr><td> </td><td></td></tr>
680 <tr><td> </td><td></td></tr>
681 <tr><td> </td><td></td></tr>
682 <tr><td> </td><td></td></tr>
683 <tr><td> </td><td></td></tr>
684 <tr><td> </td><td></td></tr>
685 <tr><td> </td><td></td></tr>
690 <div id="multi_tab" class="tab-hidden">
691 <div class="fps_block">
692 <input type="range" id="multi_fps" min="15" max="60" value="30" step="1" oninput="set_fps();">
693 <div class="fps_cap">
694 Frame Cap: <span id="fps_cap">30</span>
696 <div class="fps_rel">
697 Realiazed FPS: <span id="fps_rel">0.0</span>
701 <table class="minfo">
702 <tr><td>Mission Name: </td><td><span id="mission_name"></span></td></tr>
703 <tr><td>Mission Time: </td><td><span id="mission_time"></span></td></tr>
705 <table class="mgoals" id="mgoals">
706 <tr><th>Mission Goals</th></tr>
707 <tr><td>Primary Objectives</td></tr>
708 <tr><td>Secondary Objectives</td></tr>
709 <tr><td>Bonus Objectives</td></tr>
711 <table class="nginfo">
712 <tr><th colspan="2">Netgame Information</th></tr>
713 <tr><td>Max Players</td><td><span id="max_players"></span></td></tr>
714 <tr><td>Max Observers</td><td><span id="max_observers"></span></td></tr>
715 <tr><td>Security</td><td><span id="security"></span></td></tr>
716 <tr><td>Respawns</td><td><span id="respawns"></span></td></tr>
720 <div id="pilot_tab" class="tab-hidden">
721 <div class="player_sel">
722 <label for="players">Player</label>
723 <select id="players" class="players" onchange="get_player_info();">
726 <table class="pinfo">
727 <tr><td>Ship Type: </td><td><span id="ship_type"></span></td></tr>
728 <tr><td>Avg Ping: </td><td><span id="player_ping"></span></td></tr>
732 <tr><th>Stats</th><th>All Time</th><th>Mission</th></tr>
733 <tr><td>Primary Shots</td><td></td><td></td></tr>
734 <tr><td>Primary Hits</td><td></td><td></td></tr>
735 <tr><td>Primary BH Hits</td><td></td><td></td></tr>
736 <tr><td>Primary Hit %</td><td></td><td></td></tr>
737 <tr><td>Primary BH Hit %</td><td></td><td></td></tr>
738 <tr><td>Secondary Shots</td><td></td><td></td></tr>
739 <tr><td>Secondary Hits</td><td></td><td></td></tr>
740 <tr><td>Secondary BH Hits</td><td></td><td></td></tr>
741 <tr><td>Secondary Hit %</td><td></td><td></td></tr>
742 <tr><td>Secondary BH Hit %</td><td></td><td></td></tr>
743 <tr><td>Assists</td><td></td><td></td></tr>
748 <div id="godstuff_tab" class="tab-hidden">
749 <div class="player_sel">
750 <label for="gs_players">Player</label>
751 <select id="gs_players" class="players">
754 <div style="margin-top: 30px;">
756 <label for="server_message">Server Message</label>
758 <input id="server_message" type="text" value="" onkeypress="return smsg_submit(event);">
759 <input id="smsg_submit" type="button" onclick="send_server_message();" style="display:none;">
761 <textarea readonly rows="20" id="smsg_box" autocomplete="off"></textarea>
764 <input class="button" type="button" value="Refresh Missions" onclick="refresh_missions();">
769 <div id="debug" class="debug_state"></div>
772 <div id="popup" class="modal">
773 <div class="modal-content">
774 <div class="modal-title" id="modal-title"></div>
775 <div class="modal-body">
776 <span id="field1"></span> <span id="field2"></span>