562 lines
17 KiB
JavaScript
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'] +
|
||
|
";'>  " +
|
||
|
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;
|
||
|
};
|