server/ui/js/gorobots.js

562 lines
17 KiB
JavaScript

var gorobots_init = function gorobots(my, webgl){
my.width = null;
my.height = null;
my.server = "ws://localhost:8666/ws/";
my.websocket = null;
my.id = null;
my.connection_retry = 3000;
my.state = null;
my.spectator = false;
my.debug = false;
my.debug_draw = true;
var grey = "#999999";
var colors = [
"#222222", // Grey
"#000099",
"#009900",
"#990000",
"#009999",
"#990099",
"#999900",
"#000044",
"#004400",
"#440000",
"#004444",
"#440044",
"#444400",
"#0000cc",
"#00cc00",
"#cc0000",
"#00cccc",
"#cc00cc",
"#cccc00"
];
my.connect = function(server){
connection = new WebSocket(server, null);
my.websocket = connection;
console.log(connection);
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};
connection.onopen = function(){
console.log("Connected to " + server);
my.send_game_request();
};
connection.onclose = function(){
my.id = null;
my.state = null;
my.renderer.reset();
console.log("Connection Closed");
if (my.connection_retry > 0){
// Retry every few seconds
console.log("Lost Connection: " + server);
setTimeout(function(){
my.websocket = my.connect(my.server);
}, my.connection_retry);
}
};
connection.onmessage = function (e) {
// Handshake protocol, we must establish a game ID and send
// the robot config for approval before we can play
new_data = JSON.parse(e.data);
if (my.state === null) {
if (new_data.type == "idreq") {
if ('id' in new_data){
my.id = new_data['id'];
console.log("Assigned ID " + my.id + " by server");
} else {
console.log("server failed to send us an id");
}
my.send_client_id();
my.state = "gameparam";
// send supported encodings
my.websocket.send(JSON.stringify(["json"]));
}
} else if (my.state == "gameparam"){
if (new_data.type == "gameparam") {
// > [OK | FULL | NOT AUTH], board size, game params
my.parse_game_params(new_data);
my.state = "handshake";
my.setup_robot();
}
} else if (my.state == "handshake") {
// We have game details, make the render target
console.log("completed handshake");
console.log(new_data);
if('success' in new_data) {
if (!new_data.success){
alert("Your Robot Config is not valid, adjust your point distributions and try again");
return false;
}
}
my.renderer.setup_render_target(my.width, my.height, my.width, my.height);
my.state = "play";
} else if(my.state == "play") {
if (new_data.type == "handshake") {
// This is the handshake response, we've been assigned an ID
// and are in the game (or TODO: in a lobby).
console.log("we got a handshake when we expect a boardstate packet");
} else if (new_data.type == "stats") {
// XXX: need to actually assign this to the player/robots
// ...
console.log("\\o/ we have stats: " + JSON.stringify(new_data));
} else if (new_data.type == "boardstate") {
my.renderer.begin_frame(new_data['turn']);
var draw_list = my.process_gameplay_packet(new_data);
my.renderer.render(draw_list);
my.renderer.end_frame();
} else if (new_data.type == "gameover") {
my.renderer.reset();
} else {
console.error("unexpected state ...");
}
}
};
return connection;
};
my.prepare_data = function(data){
// get all the robot id's in the scanner list and find them in the
// overall robot list so we can pass them to the robot code
if (data['my_robots']){
for (var i=0; i < data['my_robots'].length; i++){
var bot = data['my_robots'][i];
bot.messages = data.messages;
for(var p in bot['scanners']){
var bot_id = bot['scanners'][p]['id'];
// find the scanner object in the pool of objects
if (bot['scanners'][p]['type'] == 'robot'){
for (var b in data['robots']){
if (data['robots'][b]['id'] == bot_id){
bot['scanners'][p] = data['robots'][b];
bot['scanners'][p].type = "robot";
bot['scanners'][p].friend = false;
}
}
for (var mybot in data['my_robots']){
if (data['my_robots'][mybot].id == bot['scanners'][p].id){
bot['scanners'][p].friend = true;
}
}
}
if (bot['scanners'][p]['type'] == 'projectile'){
for (var b in data['projectiles']){
if (data['projectiles'][b]['id'] == bot_id){
bot['scanners'][p] = data['projectiles'][b];
bot['scanners'][p].type = "projectile";
}
}
}
}
}
}
return data;
};
my.process_gameplay_packet = function(new_data){
my.stats.begin();
my.renderer.clear_debug();
var draw_list = [];
if (new_data.reset){
// my.setup_robot();
my.renderer.reset();
return;
}
if (!my.paused) {
var debug_div = document.getElementById("raw-debug");
if (debug_div){
debug_div.innerHTML = JSON.stringify(new_data, undefined, 2);
}
}
// Prep the data
new_data = my.prepare_data(new_data);
// Dump the contents of the message from the server
if (!my.paused) {
var debug_div = document.getElementById("debug");
if (debug_div){
debug_div.innerHTML = JSON.stringify(new_data, undefined, 2);
}
}
// Update the robots and build a list of what to draw
var my_robots = new_data['my_robots'];
var robots = new_data['robots'];
var all_bots = new_data['all_bots'];
my.all_bots = [];
my.my_bots = my_robots;
// Set the list of players and assign colors
var players = "";
var col = 2;
for (i=0; i < all_bots.length; i++){
my.all_bots.push(all_bots[i]['robot_id']);
// I hate javascript
var health_str = "";
if (all_bots[i]['health'] < 0) {
health_str = "000";
all_bots[i]['color'] = grey;
}
else if (all_bots[i]['health'] < 10) {
health_str = "00" + all_bots[i]['health'];
all_bots[i]['color'] = colors[col];
}
else if (all_bots[i]['health'] < 100){
health_str = "0" + all_bots[i]['health'];
all_bots[i]['color'] = colors[col];
}
else{
health_str = all_bots[i]['health'];
all_bots[i]['color'] = colors[col];
}
var mine = false;
for (var mybot in my.my_bots){
if (my.my_bots[mybot].id == all_bots[i]['robot_id']){
mine = true;
all_bots[i]['color'] = colors[1];
}
}
if (!mine){
col++;
}
players += ("<span style='color: " +
all_bots[i]['color'] +
";'>&nbsp&nbsp" +
all_bots[i]['robot_id'] +
" [" + health_str + "]</span>");
}
var players_div = document.getElementById("players");
if (players_div){
players_div.innerHTML = players;
}
// Now let's deal with all the things in the world
var i = 0;
if (my_robots){
instructions = {};
for (i=0; i < my_robots.length; i++){
if (my_robots[i].health > 0) {
instructions[my_robots[i]['id']] = my.update_robot(my_robots[i], new_data['obj']);
}
for (var bot in all_bots){
if (all_bots[bot]['robot_id'] == my_robots[i]['id']){
col = all_bots[bot]['color'];
}
}
if (my_robots[i].health <= 0){
col = grey;
}
if ("position" in my_robots[i]){
my_robots[i]['color'] = col;
my_robots[i]['type'] = 'robot';
draw_list.push(my_robots[i]);
}
}
if (my.websocket){
var payload = JSON.stringify(instructions);
// console.log(payload);
my.websocket.send(payload);
}
if (my.target < 0 && !my.spectator){
console.log("Watching " + my.my_bots[0].id);
my.renderer.set_focus_robot(my.my_bots[0].id);
my.target = 0;
}
}
if (robots){
for (i=0; i < robots.length; i++){
// Get the color from all_bots
var col = grey;
for (var bot in all_bots){
if (all_bots[bot]['robot_id'] == robots[i]['id']){
col = all_bots[bot]['color'];
}
}
if (robots[i].health <= 0){
col = grey;
}
if ("position" in robots[i]){
robots[i]['color'] = col;
robots[i]['type'] = 'robot';
draw_list.push(robots[i]);
}
}
}
// Draw the projecticles
var projectiles = new_data['projectiles'];
if (projectiles){
for (i=0; i < projectiles.length; i++){
if ("position" in projectiles[i]){
projectiles[i]['type'] = 'bullet';
draw_list.push(projectiles[i]);
}
}
}
// Draw the projecticles
var splosions = new_data['splosions'];
if (splosions){
for (i=0; i < splosions.length; i++){
if ("position" in splosions[i]){
splosions[i]['type'] = 'explosion';
draw_list.push(splosions[i]);
}
}
}
// Draw the objects
var obj = new_data['objects'];
if (obj){
for (i=0; i < obj.length; i++){
var o = {
bounds : obj[i]
};
o['type'] = "object";
o['position'] = {x: obj[i][0], y: obj[i][1]};
draw_list.push(o);
}
}
my.stats.end();
return draw_list;
};
my.eval_input = function( input, output ){
var theResult, evalSucceeded;
try{
theResult = eval( input );
evalSucceeded = true;
}
catch(e){
output.innerHTML = e;
}
if ( evalSucceeded ) {
output.innerHTML = "";
// console.log("OK");
}
return theResult;
};
my.get_robot_code = function(){
var robot_code = editor.getSession().getValue();
var output = document.getElementById('output');
var code = "( " + robot_code + " )";
var rc = my.eval_input(code, output);
return rc.call(this);
};
my.send_game_request = function() {
game = {
"id": my.game_id,
};
console.log(my.websocket.readyState);
my.websocket.send(JSON.stringify(game));
console.log("sent clientid: " + JSON.stringify(game));
};
my.send_client_id = function() {
client_id = {
"type": my.spectator ? "spectator" : "robot",
"name": "dummy",
"id": "24601",
"useragent": "gorobots.js",
};
my.websocket.send(JSON.stringify(client_id));
};
my.parse_game_params = function(params) {
// TODO: flesh out validation?
my.width = new_data.boardsize.width;
my.height = new_data.boardsize.height;
return true;
};
my.setup_robot = function(){
var robot = my.get_robot_code();
if ('setup' in robot){
var map = {"width": my.width, "height": my.height};
var config = {
"stats": robot.setup(map),
"id": my.id
};
// console.log(config);
if (!my.spectator) {
my.websocket.send(JSON.stringify(config));
}
}
};
my.update_robot = function(data, objects){
var robot = my.get_robot_code();
var map = {"width": my.width, "height": my.height, "obj": objects};
var instructions = null;
if ('update' in robot){
var dbg = {
"msg" : function(x, y, msg){
my.renderer.debug_label(x,y,msg);
},
"msg_screen" : function(x, y, msg){
my.renderer.debug_label_screen(x,y,msg);
},
"line" : function(x, y, x2, y2){
my.renderer.debug_line(x,y,x2,y2);
},
};
instructions = robot.update(data, map, dbg);
}
return instructions;
};
my.set_spectator = function(s){
my.spectator = s;
my.target=-1;
$('body').keypress(function(e){
if (my.renderer && my.renderer.canvas.clientWidth === 0){
// dont respond to key events when canvas is not in view
return;
}
if(e.which == 116){
// t
if (my.spectator){
my.target++;
if( my.target < my.all_bots.length){
console.log("Watching " + my.all_bots[my.target]);
my.renderer.set_focus_robot(my.all_bots[my.target]);
}
else {
my.target = -1;
my.renderer.set_focus_robot(null);
}
} else {
my.target++;
if( my.target < my.my_bots.length){
console.log(my.my_bots);
console.log(my.my_bots[my.target].id);
console.log("Watching " + my.my_bots[my.target].id);
my.renderer.set_focus_robot(my.my_bots[my.target].id);
}
else {
my.target = -1;
my.renderer.set_focus_robot(null);
}
}
}
});
};
my.set_server = function(server_name, game_id){
my.server = server_name;
my.game_id = game_id;
my.state = null;
if (my.websocket){
console.log("Switching Server: " + my.server);
my.websocket.close();
my.renderer.shutdown();
}
else{
console.log("Setting Server: " + my.server);
my.websocket = my.connect(my.server);
}
};
my.init = function(){
console.log("Welcome to GoRobots");
if (webgl){
my.renderer = gorobots_render_webgl();
}
else{
my.renderer = gorobots_render_canvas();
}
my.renderer.init("battlefield");
my.stats = new Stats();
my.stats.setMode(0); // 0: fps, 1: ms
// Align top-left
my.stats.domElement.style.position = 'absolute';
my.stats.domElement.style.left = '5px';
my.stats.domElement.style.top = '120px';
document.body.appendChild( my.stats.domElement );
$(my.stats.domElement).hide();
my.paused = false;
$('body').keypress(function(e){
// alert(e.which);
if(e.which == 112){
// p
my.paused = !my.paused;
}
if (my.renderer && my.renderer.canvas.clientWidth === 0){
// dont respond to key events when canvas is not in view
return;
}
if(e.which == 100){
// d
$(my.stats.domElement).toggle();
}
});
};
my.init();
return my;
};