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 == "popup ") {
15 popup(msg.data.substr(7));
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 if (fields[x].length) {
51 content[x].textContent = fields[x];
55 modal.style.display = "block";
57 modal.style.display = "none";
67 document.getElementById("popup").style.display = "none";
70 document.getElementById("n_conn").textContent = "0";
71 table = document.getElementById("connections");
72 len = table.rows.length;
74 for (j = 1; j < len; j++) {
75 table.rows[j].id = '';
76 table.rows[j].onclick = '';
77 table.rows[j].cells[0].innerHTML = ' ';
78 table.rows[j].cells[1].innerHTML = "";
81 /* multi-player tab */
82 document.getElementById("fps_rel").textContent = "0.0";
83 document.getElementById("mission_name").textContent = "";
84 document.getElementById("mission_time").textContent = "";
86 document.getElementById("max_players").textContent = "";
87 document.getElementById("max_observers").textContent = "";
88 document.getElementById("security").textContent = "";
89 document.getElementById("respawns").textContent = "";
91 table = document.getElementById("mgoals");
92 len = table.rows.length;
94 for (j = 1; j < len; j++) {
95 var cell = table.rows[j].cells[0];
97 if (cell.childNodes.length > 1) {
98 cell.removeChild(cell.childNodes[1]);
102 /* player info tab */
103 document.getElementById("players").selectedIndex = -1;
104 document.getElementById("ship_type").textContent = "";
105 document.getElementById("player_ping").textContent = "";
107 table = document.getElementById("stats");
108 len = table.rows.length;
110 for (j = 1; j < len; j++) {
111 table.rows[j].cells[1].innerHTML = "";
112 table.rows[j].cells[2].innerHTML = "";
116 document.getElementById("gs_players").selectedIndex = -1;
117 document.getElementById("smsg_box").value = "";
120 function do_server_tab(msg) {
126 if (msg.substring(0, 5) == "name ") {
127 document.getElementById("server_name").value = msg.substr(5);
128 } else if (msg.substring(0, 5) == "pass ") {
129 document.getElementById("host_pass").value = msg.substr(5);
130 } else if (msg.substring(0, 5) == "ping ") {
131 table = document.getElementById("connections");
132 var ping_list = msg.substr(5).split(';', 12);
133 len = ping_list.length;
135 for (j = 0; j < len; j++) {
136 var ping = ping_list[j].split(',');
137 row = table.rows.namedItem(ping[0]);
140 row.cells[1].innerHTML = ping[1];
143 } else if (msg.substring(0, 5) == "conn ") {
144 table = document.getElementById("connections");
145 var players = document.getElementById("players");
147 var gs_players = document.getElementById("gs_players");
148 var connections = msg.substr(5).split(';', 12);
149 len = connections.length - 1;
151 if (players.selectedIndex != -1) {
152 cur_player = players.value;
155 while (players.options.length) {
157 gs_players.remove(0);
160 for (j = 0; j < len; j++) {
161 var conn = connections[j].split(',');
162 row = table.rows[j+1];
164 var option = document.createElement("option");
165 option.text = conn[0];
166 gs_players.add(option);
168 option = document.createElement("option");
169 option.text = conn[0];
173 row.cells[0].innerHTML = conn[1];
175 if (Boolean(conn[2])) {
176 row.cells[1].innerHTML = conn[2];
179 row.onclick = function() { kick_conn(conn[0], conn[1]); };
182 gs_players.selectedIndex = -1;
183 players.value = cur_player;
184 document.getElementById("n_conn").textContent = j;
186 len = table.rows.length;
188 for (j = j+1; j < len; j++) {
193 row.cells[0].innerHTML = " "
194 row.cells[1].innetHTML = "";
199 function do_multi_tab(msg) {
200 if (msg.substring(0, 4) == "fps ") {
201 document.getElementById("fps_rel").textContent = msg.substr(4);
202 } else if (msg.substring(0, 5) == "name ") {
203 document.getElementById("mission_name").textContent = msg.substr(5);
204 } else if (msg.substring(0, 5) == "time ") {
205 document.getElementById("mission_time").textContent = msg.substr(5);
206 } else if (msg.substring(0, 5) == "info ") {
207 var nginfo = msg.substr(5).split(',');
208 document.getElementById("max_players").textContent = nginfo[0];
209 document.getElementById("max_observers").textContent = nginfo[1];
210 document.getElementById("security").textContent = nginfo[2];
211 document.getElementById("respawns").textContent = nginfo[3];
212 } else if (msg.substring(0, 5) == "goal ") {
213 var objectives = msg.substr(5).split(';');
214 var gtable = document.getElementById("mgoals");
220 j_len = objectives.length;
222 for (j = 0; j < j_len; j++) {
223 var goals = objectives[j].split(',');
224 var cell = gtable.rows[j+1].cells[0];
226 if (cell.childNodes.length > 1) {
227 cell.removeChild(cell.childNodes[1]);
230 var list = document.createElement("ul");
232 x_len = goals.length;
234 for (x = 0; x < x_len; x++) {
235 var item = document.createElement("li");
236 item.innerHTML = goals[x].substr(2);
238 var status = goals[x].substring(0, 2);
239 if (status == "c ") {
240 item.style.color = "green";
241 } else if (status == "f ") {
242 item.style.color = "red";
244 item.style.color = "#555";
247 list.appendChild(item);
250 cell.appendChild(list);
255 function do_player_tab(msg) {
256 if (msg.substring(0, 5) == "info ") {
257 var pinfo = msg.substr(5).split(';');
259 document.getElementById("ship_type").textContent = pinfo[0];
260 document.getElementById("player_ping").textContent = pinfo[1];
262 var all_stats = pinfo[2].split(',');
263 var mission_stats = pinfo[3].split(',');
264 var table = document.getElementById("stats");
266 var len = table.rows.length;
268 for (j = 1; j < len; j++) {
269 var row = table.rows[j];
271 row.cells[1].innerHTML = all_stats[j-1];
272 row.cells[2].innerHTML = mission_stats[j-1];
277 function do_gs_tab(msg) {
278 if (msg.substring(0, 5) == "mesg ") {
279 document.getElementById("smsg_box").value += msg.substr(5);
283 function change_server_name() {
284 standalone_socket.send("S:name " + document.getElementById("server_name").value);
287 function change_host_pass() {
288 standalone_socket.send("S:pass " + document.getElementById("host_pass").value);
291 function kick_conn(name, addr) {
292 var kick = confirm("Kick player? \n\n" + name + "@" + addr);
295 standalone_socket.send("S:kick " + addr);
299 function send_server_message() {
300 var smsg = document.getElementById("server_message");
301 standalone_socket.send("G:smsg " + smsg.value);
305 function refresh_missions() {
306 standalone_socket.send("G:mrefresh");
309 function switch_tab(tab) {
310 var tabbox = document.getElementById("tab-box");
311 var topnav = document.getElementById("topnav");
314 for (x = 0; x < 4; x++) {
316 topnav.children[x].children[0].className = "active";
317 tabbox.children[x].className = "tab-visible";
319 topnav.children[x].children[0].className = '';
320 tabbox.children[x].className = "tab-hidden";
325 function smsg_submit(e) {
326 e = e || window.event;
328 if (e.keyCode == 13) {
329 document.getElementById("smsg_submit").click();
336 function get_player_info() {
337 var n = document.getElementById("players").selectedIndex;
340 standalone_socket.send("P:info " + document.getElementById("players").options[n].text);
345 var fps = document.getElementById("multi_fps").value;
346 document.getElementById("fps_cap").textContent = fps;
348 standalone_socket.send("M:fps " + fps);
352 <style type="text/css">
354 font-family: Arial, Helvetica, sans-serif
363 background-color: #ddd;
372 display: inline-block;
379 background-color: #444;
383 text-decoration: none;
384 display: inline-block;
390 background-color: #111;
395 list-style-type: none;
399 background-color: #3a3a3a
407 display: inline-block;
411 text-decoration: none;
420 background-color: #111;
424 ul.topnav li.shutdown {
429 ul.topnav li.shutdown a {
430 background-color: #8b0000
433 ul.topnav li.shutdown a:hover {
434 background-color: red;
454 border: 1px solid #444;
456 border-collapse: collapse;
463 background-color: #444;
474 font-family: Courier New, Courier, monospace;
478 #connections tr:nth-child(odd),
479 #stats tr:nth-child(odd) {
480 background-color: #d5d5d5
483 #connections tr:hover,
484 #connections tr:hover:nth-child(odd) {
485 background-color: #eaeaea
492 table.name_pass label {
501 box-sizing: border-box
513 box-sizing: border-box;
515 background-color: #fff;
516 border: 1px solid #bbb;
525 border-collapse: collapse
535 font-family: Courier New, Courier, monospace;
547 display: inline-block;
555 box-sizing: border-box
570 font-family: Courier New, Courier, monospace;
571 padding: 5px 0 5px 10px
577 border-collapse: collapse;
578 display: inline-block
589 background-color: #fff;
600 border-bottom: 1px solid #444
604 background-color: #ddd;
628 background-color: #000;
629 background-color: rgba(0, 0, 0, .4)
633 background-color: #fefefe;
635 border: 2px solid #111;
640 background-color: #444;
656 <div class="container">
657 <ul class="topnav" id="topnav">
658 <li><a onclick="switch_tab(0);" href="javascript:void(0);" class="active">Server</a></li>
659 <li><a onclick="switch_tab(1);" href="javascript:void(0);">Multi-Player</a></li>
660 <li><a onclick="switch_tab(2);" href="javascript:void(0);">Player Info</a></li>
661 <li><a onclick="switch_tab(3);" href="javascript:void(0);">God Stuff</a></li>
662 <li class="shutdown"><a onclick="shutdown();" href="javascript:void(0);">Shutdown</a></li>
665 <div class="tab-box" id="tab-box">
666 <div id="server_tab" class="tab-visible">
667 <table class="name_pass">
668 <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>
669 <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>
672 <p>Connections : <span id="n_conn">0</span></p>
674 <table id="connections">
675 <tr><th style="min-width:20em;">IP Address</th><th style="min-width:5em;">Ping</th></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>
686 <tr><td> </td><td></td></tr>
687 <tr><td> </td><td></td></tr>
692 <div id="multi_tab" class="tab-hidden">
693 <div class="fps_block">
694 <input type="range" id="multi_fps" min="15" max="60" value="30" step="1" oninput="set_fps();">
695 <div class="fps_cap">
696 Frame Cap: <span id="fps_cap">30</span>
698 <div class="fps_rel">
699 Realiazed FPS: <span id="fps_rel">0.0</span>
703 <table class="minfo">
704 <tr><td>Mission Name: </td><td><span id="mission_name"></span></td></tr>
705 <tr><td>Mission Time: </td><td><span id="mission_time"></span></td></tr>
707 <table class="mgoals" id="mgoals">
708 <tr><th>Mission Goals</th></tr>
709 <tr><td>Primary Objectives</td></tr>
710 <tr><td>Secondary Objectives</td></tr>
711 <tr><td>Bonus Objectives</td></tr>
713 <table class="nginfo">
714 <tr><th colspan="2">Netgame Information</th></tr>
715 <tr><td>Max Players</td><td><span id="max_players"></span></td></tr>
716 <tr><td>Max Observers</td><td><span id="max_observers"></span></td></tr>
717 <tr><td>Security</td><td><span id="security"></span></td></tr>
718 <tr><td>Respawns</td><td><span id="respawns"></span></td></tr>
722 <div id="pilot_tab" class="tab-hidden">
723 <div class="player_sel">
724 <label for="players">Player</label>
725 <select id="players" class="players" onchange="get_player_info();">
728 <table class="pinfo">
729 <tr><td>Ship Type: </td><td><span id="ship_type"></span></td></tr>
730 <tr><td>Avg Ping: </td><td><span id="player_ping"></span></td></tr>
734 <tr><th>Stats</th><th>All Time</th><th>Mission</th></tr>
735 <tr><td>Primary Shots</td><td></td><td></td></tr>
736 <tr><td>Primary Hits</td><td></td><td></td></tr>
737 <tr><td>Primary BH Hits</td><td></td><td></td></tr>
738 <tr><td>Primary Hit %</td><td></td><td></td></tr>
739 <tr><td>Primary BH Hit %</td><td></td><td></td></tr>
740 <tr><td>Secondary Shots</td><td></td><td></td></tr>
741 <tr><td>Secondary Hits</td><td></td><td></td></tr>
742 <tr><td>Secondary BH Hits</td><td></td><td></td></tr>
743 <tr><td>Secondary Hit %</td><td></td><td></td></tr>
744 <tr><td>Secondary BH Hit %</td><td></td><td></td></tr>
745 <tr><td>Assists</td><td></td><td></td></tr>
750 <div id="godstuff_tab" class="tab-hidden">
751 <div class="player_sel">
752 <label for="gs_players">Player</label>
753 <select id="gs_players" class="players">
756 <div style="margin-top: 30px;">
758 <label for="server_message">Server Message</label>
760 <input id="server_message" type="text" value="" onkeypress="return smsg_submit(event);">
761 <input id="smsg_submit" type="button" onclick="send_server_message();" style="display:none;">
763 <textarea readonly rows="20" id="smsg_box" autocomplete="off"></textarea>
766 <input class="button" type="button" value="Refresh Missions" onclick="refresh_missions();">
771 <div id="debug" class="debug_state"></div>
774 <div id="popup" class="modal">
775 <div class="modal-content">
776 <div class="modal-title" id="modal-title"></div>
777 <div class="modal-body">
778 <span id="field1"></span> <span id="field2"></span>