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 += ("  " + all_bots[i]['robot_id'] + " [" + health_str + "]"); } 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; };