diff --git a/scripts/functions-body.js b/scripts/functions-body.js index 04a3220..8b2daec 100644 --- a/scripts/functions-body.js +++ b/scripts/functions-body.js @@ -1,447 +1,447 @@ /* * 3DCycles - A lightcycle game. * Copyright (C) 2019 Glen Harpring * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ function getPlayer(name) { name = removeColors(name).filter(); var matches = []; for(var i=engine.players.length;i--;) { if(engine.players[i].getBoringName().filter() == name) { return engine.players[i]; } else if(engine.players[i].getBoringName().filter().indexOf(name) > -1) { matches.push(i); } } if(matches.length > 1) { engine.console.print("Too many matches for "+name+". Try something more exact to narrow down the search.\n"); } else if(matches.length < 1) { engine.console.print("No matches for "+name+". Try a different name.\n"); } else { return engine.players[matches[0]]; } } function retToLastSafe(cycle,w1x,w1y,w2x,w2y) { var dist = distanceoflines(cycle.position.x,cycle.position.y,cycle.position.x,cycle.position.y,w1x,w1y,w2x,w2y); console.warn(cycle.name+" phased through a wall "+dist+"m.\n"); //if(dist == 0) return; dist -= settings.CYCLE_RUBBER_MINDISTANCE; cycle.position.x -= cycle.lastdir.front[0]*dist; cycle.position.y -= cycle.lastdir.front[1]*dist; if(lineIntersect(cycle.position.x,cycle.position.y,cycle.lastpos.x,cycle.lastpos.y,w1x,w1y,w2x,w2y)) { //cycle.position.x += cycle.lastdir.front[0]*(dist*2); cycle.position.y += cycle.lastdir.front[1]*(dist*2); //if(lineIntersect(cycle.position.x,cycle.position.y,cycle.lastpos.x,cycle.lastpos.y,w1x,w1y,w2x,w2y)) { var dist = distanceoflines(cycle.lastpos.x,cycle.lastpos.y,cycle.lastpos.x,cycle.lastpos.y,w1x,w1y,w2x,w2y); dist -= settings.CYCLE_RUBBER_MINDISTANCE; cycle.position.x = cycle.lastpos.x+ (cycle.lastdir.front[0]*dist)/*+ (cycle.lastsensor.left*cycle.lastdir.left[0])+ (cycle.lastsensor.right*cycle.lastdir.right[0])*/; cycle.position.y = cycle.lastpos.y+ (cycle.lastdir.front[1]*dist)/*+ (cycle.lastsensor.left*cycle.lastdir.left[1])+ (cycle.lastsensor.right*cycle.lastdir.right[1])*/; /*while(lineIntersect(cycle.position.x,cycle.position.y,cycle.lastpos.x,cycle.lastpos.y,w1x,w1y,w2x,w2y)) { cycle.position.x -= (1/1000)*cycle.lastdir.front[0]; cycle.position.y -= (1/1000)*cycle.lastdir.front[1]; } cycle.collidetime = 0; cycle.lastspeed = 0;*/ if(lineIntersect(cycle.position.x,cycle.position.y,cycle.lastpos.x,cycle.lastpos.y,w1x,w1y,w2x,w2y)) { if(engine.network) { //request new cycle trails } else { doDeath(cycle); engine.console.print(cycle.name+" phased through a wall and has been terminated.\n"); } } else { cycle.rubber += cycle.speed; cycle.sensor.front = settings.CYCLE_RUBBER_MINDISTANCE; } } } else { cycle.rubber += cycle.speed; cycle.sensor.front = settings.CYCLE_RUBBER_MINDISTANCE; } if(engine.haswall) recalcCurrWall(cycle); } function getCycleSensors(full=false) { var oneline = ""; var range = settings.CYCLE_SENSORS_RANGE; for(var x=engine.players.length-1;x>=0;--x) if(engine.players[x] !== undefined) { //if(full) { engine.players[x].sensor.left = engine.players[x].sensor.right = engine.players[x].sensor.leftTurn = engine.players[x].sensor.rightTurn = engine.players[x].sensor.front = engine.players[x].sensor.rear = Infinity; engine.players[x].sensor.nearestobj = engine.players[x].sensor.lnearestobj = false; engine.players[x].sensor.rnearestobj = false; } engine.players[x].sensor.bottom = 0; engine.players[x].sensor.frontWallHeight = Infinity; engine.players[x].sensor.objleft = engine.players[x].sensor.objright = engine.players[x].sensor.objfront = engine.players[x].sensor.objrear = false; engine.players[x].sensor.nearcycle = false; engine.players[x].dir.front = cdir(engine.players[x].rotation.z); engine.players[x].dir.left = cdir(engine.players[x].rotation.z+(Math.PI/2)); engine.players[x].dir.right = cdir(engine.players[x].rotation.z-(Math.PI/2)); engine.players[x].dir.leftTurn = cdir(engine.players[x].rotation.z+(Math.PI/(settings.ARENA_AXES*0.5))); engine.players[x].dir.rightTurn = cdir(engine.players[x].rotation.z-(Math.PI/(settings.ARENA_AXES*0.5))); } - for(var x=engine.map.zones.length-1;x>=0;--x) + for(var x=engine.zones.children.length-1;x>=0;--x) { engine.zones.children[x].walldist = Infinity; } if(!engine.dedicated) var campos = engine.camera.position, ppos = engine.players[engine.viewTarget].position; for(var y=engine.map.walls.length-1;y>=0;--y) { //console.log("ohi"); var lookThroughWall = false; for(var i=engine.map.walls[y].length-1;i>=0;--i) { - var w1x = engine.map.walls[y][i][0], w1y = engine.map.walls[y][i][1]; + var w1x = engine.map.walls[y][i][0], w1y = engine.map.walls[y][i][1], p=engine.map.walls[y][i+1]; - if(engine.map.walls[y][i+1] !== undefined) + if(p !== undefined) { - var w2x = engine.map.walls[y][i+1][0], w2y = engine.map.walls[y][i+1][1]; + var w2x = p[0], w2y = p[1]/*,w2z = p[2]*/; for(var x=engine.players.length-1;x>=0;--x) if(engine.players[x] !== undefined && engine.players[x].alive) { var cycle = engine.players[x]; var posx = cycle.position.x, posy = cycle.position.y, posz = cycle.position.z; if(lineIntersect(posx,posy,cycle.lastpos.x,cycle.lastpos.y,w1x,w1y,w2x,w2y)) { retToLastSafe(cycle,w1x,w1y,w2x,w2y); } else { var dir = engine.players[x].dir.front, ldir = engine.players[x].dir.left, rdir = engine.players[x].dir.right ltdir = engine.players[x].dir.leftTurn, rtdir = engine.players[x].dir.rightTurn; var rg = /*cycle.sensor.front==Infinity?*/(cycle.speed*range);//:cycle.sensor.front; //var output = pointLineDistance(w1x,w1y,w2x,w2y,posx,posy); //var testx = (w2x-w1x)*dir[0], testy = (w2y-w1y)*dir[1], tpx = posx*(-dir[0]), tpy = posy*(-dir[1]); //if(cycle == engine.players[engine.viewTarget]) oneline += ""+(w2x-w1x)+"\t\t\t\t\t\t\t"+posx+"\t\t\t\t\t\t\t"+(w2x-w1x)+"\t\t\t\t\t\t\t"+posy+";\n"; //if(((w2x+w1x)/2) >= posy*dir[0] && ((w2y+w1y)/2) >= posx*dir[1]) //if(isinfront(w1x,w1y,w2x,w2y,posx,posy,dir)) coord = [w1x,w1y,w2x,w2y]; if(lineIntersect(posx,posy,posx+(dir[0]*rg),posy+(dir[1]*rg),w1x,w1y,w2x,w2y)) { //var ff = distanceoflines(posx,posy,posx+(dir[0]/6),posy+(dir[1]/6),w1x,w1y,w2x,w2y); var ff = distanceoflines(posx,posy,posx,posy,w1x,w1y,w2x,w2y); /*forward = Math.min(forward,ff); if(ff == forward) type = "rim";//*/ if(ff < cycle.sensor.front) { cycle.sensor.front=ff; cycle.sensor.nearestobj = "rim";} } else if(lineIntersect(posx,posy,posx+(ldir[0]*rg),posy+(ldir[1]*rg),w1x,w1y,w2x,w2y)) { var ll = distanceoflines(posx,posy,posx,posy,w1x,w1y,w2x,w2y); if(ll < cycle.sensor.left) { cycle.sensor.left=ll; cycle.sensor.lnearestobj = "rim";} } else if(lineIntersect(posx,posy,posx+(rdir[0]*rg),posy+(rdir[1]*rg),w1x,w1y,w2x,w2y)) { var rr = distanceoflines(posx,posy,posx,posy,w1x,w1y,w2x,w2y); if(rr < cycle.sensor.right) { cycle.sensor.right=rr; cycle.sensor.rnearestobj = "rim";} } if(lineIntersect(posx,posy,posx+(ltdir[0]*rg),posy+(ltdir[1]*rg),w1x,w1y,w2x,w2y)) { var ll = distanceoflines(posx,posy,posx,posy,w1x,w1y,w2x,w2y); if(ll < cycle.sensor.leftTurn) { cycle.sensor.leftTurn=ll; } } else if(lineIntersect(posx,posy,posx+(rtdir[0]*rg),posy+(rtdir[1]*rg),w1x,w1y,w2x,w2y)) { var rr = distanceoflines(posx,posy,posx,posy,w1x,w1y,w2x,w2y); if(rr < cycle.sensor.rightTurn) { cycle.sensor.rightTurn=rr;} } /* if(((w2x+w1x)/2) >= posy*ldir[0] && ((w2y+w1y)/2) >= posx*ldir[1]) { var ll = distanceoflines(posx,posy,posx+(ldir[0]),posy+(ldir[1]),w1x,w1y,w2x,w2y); left = Math.min(left,ll); } if(((w2x+w1x)/2) >= posy*rdir[0] && ((w2y+w1y)/2) >= posx*rdir[1]) { var rr = distanceoflines(posx,posy,posx+(rdir[0]),posy+(rdir[1]),w1x,w1y,w2x,w2y); right = Math.min(right,rr); } */ } } - for(var x=engine.map.zones.length-1;x>=0;--x) + for(var x=engine.zones.children.length-1;x>=0;--x) { - var zone = engine.map.zones[x]; - var posx = zone[1], posy = zone[2],w2z = p[2]*1; - var walldist = distanceoflines(posx,posy,posx,posy,w1x,w1y,w2x,w2y)-zone[3]; - if(walldist < engine.zones.children[x].walldist) + var zone = engine.zones.children[x]; + var posx = zone.position.x, posy = zone.position.y; + var walldist = distanceoflines(posx,posy,posx,posy,w1x,w1y,w2x,w2y)-zone.cfg.radius; + if(walldist < zone.walldist) { - engine.zones.children[x].walldist = walldist; + zone.walldist = walldist; } } if(!engine.dedicated && !lookThroughWall) lookThroughWall = (engine.walls.children[y]&&engine.walls.children[y].geometry.vertices[engine.walls.children[y].geometry.vertices.length-1].z) > campos.z && lineIntersect(campos.x,campos.y,ppos.x,ppos.y,w1x,w1y,w2x,w2y); } } if(!engine.dedicated && engine.walls.children[y]) engine.walls.children[y].visible = !lookThroughWall; } for(var a=engine.players.length-1;a>=0;--a) if(engine.players[a] !== undefined) { var walls = engine.players[a].walls.map; var len = walls.length; for(var i=len-1;i>=0;--i) { var p1 = walls[i]; //var w1x = p1[0],w1y = p1[1],w1z = p1[2]; if(walls[i+1] !== undefined) { var p2 = walls[i+1]; //var w2x = p2[0],w2y = p2[1],w2z = p2[2]; for(var x=engine.players.length-1;x>=0;--x) if(engine.players[x] !== undefined && engine.players[x].alive) { //var cycle = engine.players[x]; //var isplayer = (engine.players[a] == engine.players[x]); if(engine.players[a] != engine.players[x] || i <= len-(settings.ARENA_AXES)) { //var posx = engine.players[x].position.x, posy = engine.players[x].position.y, posz = engine.players[x].position.z; if(p1[2]||0 <= engine.players[x].position.z && (p1[2]||0)+1 >= engine.players[x].position.z) { if(lineIntersect(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].lastpos.x,engine.players[x].lastpos.y,p1[0],p1[1],p2[0],p2[1])) { retToLastSafe(engine.players[x],p1[0],p1[1],p2[0],p2[1]); } else { var dir = engine.players[x].dir.front, ldir = engine.players[x].dir.left, rdir = engine.players[x].dir.right, ltdir = engine.players[x].dir.leftTurn, rtdir = engine.players[x].dir.rightTurn; //var rg = engine.players[x].sensor.front==Infinity?(engine.players[x].speed*range):engine.players[x].sensor.front; //if(engine.players[x].sensor.front==Infinity) var rg=engine.players[x].speed*range;//else var rg=engine.players[x].sensor.front; //if(!(engine.players[x].position.x == p2[0] && engine.players[x].position.y == p2[1])) { if(lineIntersect(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x+(dir[0]*rg),engine.players[x].position.y+(dir[1]*rg),p1[0],p1[1],p2[0],p2[1])) { var ff=distanceoflines(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x,engine.players[x].position.y,p1[0],p1[1],p2[0],p2[1]); /*forward = Math.min(forward,ff); if(ff == forward) type = engine.players[x];//*/ if(ff < engine.players[x].sensor.front) { engine.players[x].sensor.front=ff; engine.players[x].sensor.nearestobj = engine.players[a]; if(engine.players[a] != engine.players[x]) { engine.players[x].sensor.lastnonselfobj = engine.players[a]; } } } else if(lineIntersect(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x+(ldir[0]*rg),engine.players[x].position.y+(ldir[1]*rg),p1[0],p1[1],p2[0],p2[1])) { var ll = distanceoflines(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x,engine.players[x].position.y,p1[0],p1[1],p2[0],p2[1]); if(ll < engine.players[x].sensor.left) { engine.players[x].sensor.left=ll; engine.players[x].sensor.lnearestobj = engine.players[a]; engine.players[x].sensor.objleft = engine.players[a]; } } else if(lineIntersect(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x+(rdir[0]*rg),engine.players[x].position.y+(rdir[1]*rg),p1[0],p1[1],p2[0],p2[1])) { var rr = distanceoflines(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x,engine.players[x].position.y,p1[0],p1[1],p2[0],p2[1]); if(rr < engine.players[x].sensor.right) { engine.players[x].sensor.right=rr; engine.players[x].sensor.rnearestobj = engine.players[x].sensor.objright = engine.players[a]; } } else if(lineIntersect(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x+(-dir[0]*rg),engine.players[x].position.y+(-dir[1]*rg),p1[0],p1[1],p2[0],p2[1])) { var bb=distanceoflines(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x,engine.players[x].position.y,p1[0],p1[1],p2[0],p2[1]); if(bb < engine.players[x].sensor.rear) { engine.players[x].sensor.rear=bb; engine.players[x].sensor.objrear = engine.players[a]; } } if(lineIntersect(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x+(ltdir[0]*rg),engine.players[x].position.y+(ltdir[1]*rg),p1[0],p1[1],p2[0],p2[1])) { var ll = distanceoflines(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x,engine.players[x].position.y,p1[0],p1[1],p2[0],p2[1]); if(ll < engine.players[x].sensor.leftTurn) { engine.players[x].sensor.leftTurn=ll;} } else if(lineIntersect(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x+(rtdir[0]*rg),engine.players[x].position.y+(rtdir[1]*rg),p1[0],p1[1],p2[0],p2[1])) { var rr = distanceoflines(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x,engine.players[x].position.y,p1[0],p1[1],p2[0],p2[1]); if(rr < engine.players[x].sensor.rightTurn) { engine.players[x].sensor.rightTurn=rr;} } } } } } } } } }//*/ /*for(var x=engine.map.zones.length-1;x>=0;--x) { var zone = engine.map.zones[x]; for(var y=engine.players.length-1;y>=0;--y) if(engine.players[y] !== undefined) { var ff = Math.sqrt(((zone[1]-p2x)**2)+((zone[2]-p2y)**2))-zone[3]; if(ff < cycle.sensor.front) { cycle.sensor.front=ff; cycle.sensor.nearestobj = "zone"; } } }*/ //console.log(forward); if(oneline != "") console.log(oneline); for(var x=engine.players.length-1;x>=0;--x) if((cycle=engine.players[x]) !== undefined && cycle.lastpos) { cycle.lastpos.x = cycle.position.x; cycle.lastpos.y = cycle.position.y; cycle.lastpos.z = cycle.position.z; engine.players[x].lastdir = { front:engine.players[x].dir.front, left:engine.players[x].dir.left, right:engine.players[x].dir.right }; engine.players[x].lastsensor = { front:engine.players[x].sensor.front, left:engine.players[x].sensor.left, right:engine.players[x].sensor.right }; cycle.intersectTest = []; } } function maxSpeed() { if(settings.CYCLE_SPEED_DECAY_ABOVE > 0 ) var max_cs = settings.CYCLE_SPEED / settings.CYCLE_SPEED_DECAY_ABOVE; else var max_cs = settings.CYCLE_SPEED * 100; var max_fastest = engine.fastestSpeed; // return Math.max(max_cs,max_fastest); } function handleChat(cycle,output) { var split = output.split(" "); /*if(split[0][0] == "/") { switch(split[0]) { case "/console": case "/admin": if(!engine.dedicated || split[0] != "/console") { split.shift(); loadcfg(split.join(" ")); break; } default: if(engine.network) { } else { engine.console.print('Unknown chat command "'+split[0]+'".\n'); } break; } }*/ if(split[0] == "/console" && !engine.dedicated) { split.shift(); loadcfg(split.join(" ")); } else if(split[0] == "/admin" && !engine.network) { split.shift(); var ln = split.join(" "); loadcfg(ln); engine.console.print('Remote admin command0x7f7fff: '+ln+'\n'); } else { cycle.doChat(output); } } if(typeof(document) == "undefined") { function centerMessage(msg,time=5000) { console.log(msg); if(window.svr) { if(time == Infinity) time = Number.MAX_VALUE; var data = JSON.stringify({type:"cen",data:{msg:msg,time:time}}); window.svr.clients.forEach(function(ws){ws.send(data);}); } } } else { function centerMessage(msg,time=5000) { var cm = document.getElementById("centerMessage"); cm.innerHTML = replaceColors(htmlEntities(msg)); cm.style.opacity = 1; cm.style.display = "block"; engine.cMFadeOutAfter = performance.now()+time; } } function toLadderLog(event,params) { if(settings["LADDERLOG_WRITE_"+event]) { } } diff --git a/scripts/game.js b/scripts/game.js index af60710..951b9c6 100644 --- a/scripts/game.js +++ b/scripts/game.js @@ -1,1083 +1,1083 @@ /* * 3DCycles - A lightcycle game. * Copyright (C) 2019 Glen Harpring * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ function doNewRound() { if(engine.uRound !== false) { clearTimeout(engine.uRound); engine.uRound = false; } endRound(); setTimeout(newRound,engine.dedicated?300:0); //give clients an opportunity to sync their data } function endRound() { if(window.svr) { window.svr.clients.forEach(function(ws){ws.send('{"type":"endRound"}')}); window.svr.clients.forEach(function(ws){ws.send('{"type":"syncdata","gtime":-4000}')}); } if(ctx) { audioStop(); if(settings.SOUNDS_EXTRO) playSound(bufferLoader.bufferList[bufferLoader.other+2],0.5,1,false,ctx.destination); } engine.roundCommencing = true; //engine.hud.hide(); if(engine.hud) engine.hud.game.style.opacity = 0; engine.console.print("Deleting objects...\n",false); if(!engine.network) { if(settings.ROUND_CENTER_MESSAGE != "") { centerMessage(settings.ROUND_CENTER_MESSAGE); } } engine.gtime = -4000; for(var x=engine.players.length-1;x>=0;--x) if(typeof(engine.players[x]) != "undefined") { engine.players[x].alive = false; } while(engine.scene.children.length > 0) { engine.scene.remove(engine.scene.children[0]); } //if(!engine.network) engine.players.splice(0); } function endGame() { endRound(); engine.players.splice(0); engine.round = 0; } function playGame() { engine.playGame = true; if(!engine.scene) { init(); } else { engine.paused = false; if(engine.hud) engine.hud.show(); } hideMenu(); newRound(); engine.inputState = 'game'; //change input state to accept game controls if(engine.network) { document.getElementById("progtitle").innerHTML = tStringify("@progtitleshort@ • Playing online"); } else { document.getElementById("progtitle").innerHTML = tStringify("@progtitleshort@ • Playing locally"); } } function revertMap() { var mapfile = settings.RESOURCE_REPOSITORY_CACHE+(settings.MAP_FILE.replace(/\(.+\)/,"")); engine.console.print("Downloading map from "+mapfile+"...\n",false); httpGetAsync(mapfile,loadRound,function() { engine.console.print("Unable to load map file. Ignoring for now...",false); loadRound(); }); } function newRound() { engine.roundCommencing = true; /////////////LIGHTS var light1 = new THREE.AmbientLight( 0x666666 ); // soft white light engine.scene.add( light1 ); var light = new THREE.DirectionalLight( 0xffffff, 1 ); light.castShadow = true; light.position.set( 4, 1, 0 ); engine.scene.add( light ); var light2 = new THREE.DirectionalLight( 0xffffff, 1 ); light2.castShadow = true; light2.position.set( -4, -1, 0 ); engine.scene.add( light2 ); //////////end of lights var aspectRatio = (window.innerWidth / window.innerHeight); engine.camera = new THREE.PerspectiveCamera( settings.CAMERA_FOV, aspectRatio, settings.CAMERA_NEAR_RENDER, settings.CAMERA_FAR_RENDER ); engine.camera.userViewDir = false; engine.camera.up = new THREE.Vector3(0,0,1); //Z is up, X and Y is l+r and b+f //engine.camera.position.set(247, 247, 3); engine.viewTarget = engine.activePlayer; //engine.cameraOrbit = new THREE.OrbitControls(engine.camera); //engine.cameraOrbit.maxDistance = 400; //BELOW THIS LINE DEPENDS ON GAME TYPE //MAP var maps = settings.MAP_ROTATION.split(";"); if(settings.ROTATION_TYPE > 0) { switch(settings.ROTATION_TYPE) { case 1: engine.currrot += 1; break; case 2: // when matches are implemented if(engine.rounds == 0) engine.currrot += 1; break; } if(engine.currrot > maps.length) engine.currrot = 0; settings.MAP_FILE = maps[engine.currrot]; } if(settings.MAP_FILE != "" && settings.MAP_FILE != engine.loadedMap) { var mapfile = settings.RESOURCE_REPOSITORY_SERVER+(settings.MAP_FILE.replace(/\(.+\)/,"")); engine.console.print("Downloading map from "+mapfile+"...\n",false); httpGetAsync(mapfile,loadRound,revertMap); //loadRound(httpGet(mapfile)); } else { loadRound(); } } function teamColor(id) { id += 1; if(settings["TEAM_NAME_"+id]) { return new THREE.Color(settings["TEAM_RED_"+id]/15,settings["TEAM_GREEN_"+id]/15,settings["TEAM_BLUE_"+id]/15); } return new THREE.Color(); } function createAIsettings() { var AI_NUM = 1; for(var z=engine.players.length-1;z>=0;--z) if(engine.players[z] && engine.players[z].AI) {AI_NUM++;} var cycleColor = [0x000000,0xff0000,0x00ff00,0x0000ff][Math.round(Math.random()*3)]; var tailColor = [0x0000ff,0xff0000,0xffff00,0x00ff00][Math.round(Math.random()*3)]; if(!settings.ALLOW_TEAM_NAME_COLOR) { cycleColor = tailColor = teamColor(1); } var colorcode = cycleColor.toString(16); colorcode = ("0".repeat(6-colorcode.length))+colorcode; var cycleinfo = { ai:true, cycleColor:cycleColor, tailColor:tailColor, /*engineType: 5,*/ engineType:(settings.players[0])?settings.players[0].engineType:5, spectating:false, name: settings.AI_DUAL_COLOR_NAME?'AI0x'+colorcode+'#'+AI_NUM:'AI#'+AI_NUM }; return cycleinfo; } function calculateSpawn(x) { var spawnslength = engine.map.spawns.length; if(!engine.map.spawns[x]) { var mult = Math.floor((x/spawnslength)); var currspawn = x-(spawnslength*mult); var alt = (mult/2 != Math.floor(mult/2)); console.log(mult); if(alt) mult = -Math.ceil(mult/2) else mult = mult/2 console.log(mult,currspawn); var spawns = JSON.parse(JSON.stringify(engine.map.spawns[Math.min(currspawn,(spawnslength-1))]||[])); spawns[0] -= mult*settings.SPAWN_WINGMEN_SIDE; spawns[1] -= Math.abs(mult)*settings.SPAWN_WINGMEN_BACK; } else { var spawns = engine.map.spawns[x]; } return spawns; } function processPlayer(x,cfg) { var spawns = calculateSpawn(x); if(engine.players[x]) { var cycle = engine.players[x]; cycle.engineType = (typeof(cfg)=="undefined")?5:cfg.engineType; if(x == engine.activePlayer && !engine.dedicated) { var cycleColor = cfg.cycleColor,tailColor = cfg.tailColor; if(!settings.ALLOW_TEAM_NAME_COLOR) { cycleColor = tailColor = teamColor(0); } if(cycle.name != cfg.name) { var out = cycle.getColoredName()+"0x7fff7f renamed to "; cycle.cycleColor = cycleColor; cycle.tailColor = tailColor; cycle.name = cfg.name; engine.console.print(out+cycle.getColoredName()+"\n"); } else { cycle.cycleColor = cycleColor; cycle.tailColor = tailColor; } if(cycle.spectating != cfg.spectating) { cycle.spectating = cfg.spectating; if(cycle.spectating) { engine.console.print(cycle.getColoredName()+"0xff7f7f left to spectator mode.\n"); } else { engine.console.print(cycle.getColoredName()+"0x7fff7f entered from spectator mode.\n"); } } } else { if(!settings.ALLOW_TEAM_NAME_COLOR) { cycleColor = tailColor = teamColor(1); } } } else { cfg.x = spawns[0]; cfg.y = spawns[1]; cfg.z = spawns[2]; engine.players[x] = (new Player(cfg)); var cycle = engine.players[x]; if(cycle.spectating) { engine.console.print(cycle.getColoredName()+"0xff7f7f entered as spectator.\n"); } else { engine.console.print(cycle.getColoredName()+"0x7fff7f entered the game.\n"); } } if(cycle.spectating) { cycle.team = null; } else if(!cycle.team) { if(engine.teams.length < settings.TEAMS_MAX) { engine.teams.push(cycle.team = new Team({name:cfg.name,x:spawns[0], y:spawns[1], z:spawns[2], dir:deg2rad(spawns[3])})); } else { var minPCount = 0, minPlayers = Infinity, minTeam; for(var x=engine.teams.length-1;x>=0;--x) { if(engine.teams[x].members.length == minPlayers) { minPCount++; if(minTeam.push) { minTeam.push(x); } else { minTeam = [minTeam,x]; } } else if(engine.teams[x].members.length < minPlayers) { minPlayers = engine.teams[x].members.length; minTeam = x; minPCount = 1; } } if(minPCount != 1) { minTeam = Math.floor(Math.random()*minTeam.length); } cycle.team = engine.teams[minTeam]; } cycle.team.members.push(cycle); } } function ensurePlayersSane(removeAIs=true) { var numAIs = 0, numPlay = 0, numSpec = 0, numWantPlay = 0; for(var x=engine.players.length-1;x>=0;--x) if(engine.players[x]) { if(engine.players[x].AI) numAIs++; if(engine.players[x].spectating) numSpec++; else numPlay++; //if(engine.players[x].spectating && !settings.players[x].spectating) numWantPlay++; } var numHuman = numPlay-numAIs; if(removeAIs) { for(var x=settings.TEAMS_MAX;x=0;--i) { engine.console.print(engine.teams[x].members[i].getColoredName()+"0xff7f7f left to spectator mode.\n"); engine.teams[x].members[i].spectating = true; } } engine.teams.splice(settings.TEAMS_MAX); } for(var x=settings.players.length-1;x>=0;--x) if(settings.players[x]) { if(engine.players[x] && engine.players[x].AI) { engine.players[engine.players.length-1] = engine.players[x]; engine.players[x] = undefined; } if(!engine.players[x]) { numPlay++; numHuman++; } processPlayer(x,settings.players[x]); } if(removeAIs) { console.log(numHuman); var shouldAIs = Math.max(0,(settings.MIN_PLAYERS-numHuman)); if(!settings.AI_TEAM) { shouldAIs += (numHuman <= settings.SP_HUMANS_COUNT)?settings.SP_NUM_AIS:settings.NUM_AIS; } if(shouldAIs > numAIs) { var AIsToAdd = (shouldAIs-numAIs); console.log(numAIs+" AIs in the game, adding "+AIsToAdd+"."); for(var x=AIsToAdd;x>0;--x) { var cycleinfo = createAIsettings(); processPlayer(engine.players.length,cycleinfo); } numAIs += AIsToAdd; } else if(numAIs != 0) { var AIsToDealWith = (numAIs-shouldAIs); console.log(numAIs+" AIs in the game, removing "+AIsToDealWith+"."); if(AIsToDealWith != 0) { for(var x=engine.players.length-1;x>=0;--x) if(engine.players[x]) { if(engine.players[x].AI) { engine.console.print(engine.players[x].getColoredName()+"0xff7f7f left the game.\n"); engine.players.splice(x,1); AIsToDealWith--; if(window.svr) { var data = JSON.stringify({type:"leave",data:x}); window.svr.clients.forEach(function(ws){ws.send(data)}); } } if(AIsToDealWith == 0) break; } } } //clean up teams / remove ghost teams for(var x=engine.teams.length-1;x>=0;--x) if(engine.teams[x]) { for(var i=engine.teams[x].members.length-1;i>=0;--i) { if(engine.players.indexOf(engine.teams[x].members[i]) == -1) { engine.teams[x].members.splice(i,1); } } if(engine.teams[x].members.length == 0) { engine.teams.splice(x,1); } else { engine.teams[x].spawn(false,false); //and finally spawn everyone } } if(!engine.dedicated && !engine.players[engine.activePlayer].alive) changeViewTarget(1); } if(window.svr) window.svr.clients.forEach(function(ws){ws.senddata(0)}); }//*/ function loadRound(dlmap) { if(typeof(dlmap) != "undefined") { engine.mapString = dlmap; engine.loadedMap = settings.MAP_FILE; } engine.mapXML = xmlify(engine.mapString); engine.console.print("Creating objects...\n",false); if(window.svr) window.svr.clients.forEach(function(ws){ws.send('{"type":"newRound"}')}); //virtual map data (used for positions, lines and stuff to calculate) engine.map = {zones:[],spawns:[],walls:[]}; engine.expl = []; engine.deaths = 0; engine.winzone = false; //GRID buildGrid();//buildObjects.js engine.scene.add(engine.grid); //WALLS buildWalls();//buildObjects engine.scene.add(engine.walls); //ZONES buildZones(); engine.scene.add(engine.zones); if(settings.SOUNDS_INTRO) playSound(bufferLoader.bufferList[bufferLoader.other+1],0.5,1,false,ctx.destination); if(settings.ROUND_CONSOLE_MESSAGE != "") { engine.console.print(settings.ROUND_CONSOLE_MESSAGE+"\n"); } loadcfg(settings.ROUND_COMMAND.replace(/\\n/g,"\n")); //GAME engine.gtime = -4000; //PLAYERS //CYCLE if(!engine.network) { ensurePlayersSane(); if(engine.round == 0) { engine.console.print("Resetting scores...\n"); for(var x=engine.players.length-1;x>=0;--x) if(engine.players[x]) { engine.players[x].score = 0; } } engine.round++; engine.console.print("Go (round "+engine.round+" of "+settings.LIMIT_ROUNDS+")!\n"); } if(!engine.camera) { var aspectRatio = (window.innerWidth / window.innerHeight); engine.camera = new THREE.PerspectiveCamera( settings.CAMERA_FOV, aspectRatio, settings.CAMERA_NEAR_RENDER, settings.CAMERA_FAR_RENDER ); engine.camera.up = new THREE.Vector3(0,0,1); //Z is up, X and Y is l+r and b+f } engine.camera.position.set(engine.logicalBox.center.x*engine.REAL_ARENA_SIZE_FACTOR,engine.logicalBox.center.y*engine.REAL_ARENA_SIZE_FACTOR,3); try{engine.camera.lookAt( new THREE.Vector3(engine.players[engine.viewTarget].position.x,engine.players[engine.viewTarget].position.y,engine.player[engine.viewTarget].position.z) );} catch(e){engine.camera.lookAt( new THREE.Vector3(engine.logicalBox.center.x*engine.REAL_ARENA_SIZE_FACTOR,engine.logicalBox.center.y*engine.REAL_ARENA_SIZE_FACTOR,0) );} updateScoreBoard(); engine.lastGameTime = engine.lastRenderTime = engine.fpsTime = engine.timeStart = performance.now(); engine.totalPauseTime = 0; engine.fastestPlayer = engine.fastestSpeed = 0; engine.timemult = 1; engine.asendtm = 0; engine.winner = undefined; engine.roundCommencing = false; getGoing(); }//end of init main function game(oneoff=false) { if(!engine.roundCommencing && !engine.paused) { if(engine.network) { var cycle = engine.players[engine.activePlayer],data={},len=0; if(cycle.braking != cycle.brakingPrev) {data.braking=cycle.braking; cycle.brakingPrev=cycle.braking; ++len;} if(cycle.boosting != cycle.boostingPrev) {data.boosting=cycle.boosting; cycle.boostingPrev=cycle.boosting; ++len;} if(len > 0) { engine.connection.send(JSON.stringify({type:"playdata",data:data})); } } if(!oneoff && settings.GAME_LOOP != 1) {setTimeout(game,1000/settings.DEDICATED_FPS); engine.gameRunning = true;} //time handlers and delta var timenow = performance.now()/settings.TIME_FACTOR; var rDelta = (timenow-engine.lastGameTime); if(rDelta > settings.TIMESTEP_MAX*1000 && engine.gtime > 0) { var more = true; rDelta = settings.TIMESTEP_MAX*1000; //engine.timeStart += rDelta; } else var more = false; var delta = rDelta*engine.timemult; var timestep = delta/1000; engine.totalPauseTime += (timenow-engine.lastGameTime)-delta; engine.lastGameTime += rDelta; engine.avgTimeStep += rDelta/1000; engine.avgTimeStep /= 2; if(!engine.network && !engine.dedicated) engine.players[0].ping = parseInt(engine.avgTimeStep*1000) //if(!engine.network && timestep > engine.avgTimeStep*10 && rDelta == delta) {engine.totalPauseTime += timestep; console.log("Compensated skip of "+delta+"ms."); timestep = engine.avgTimeStep;} engine.timemult += (engine.asendtm*timestep); if(engine.timemult > 100) engine.timemult = 100; //var timeElapsed = timenow-engine.timeStart-engine.totalPauseTime-4000; //skipping ahead at the beginning of the round is silly //engine.gtime = timeElapsed; var timeElapsed = (engine.gtime += delta); if(!engine.thread_collisiondetect && (settings.GAME_LOOP != 0.5 || !oneoff)) getCycleSensors(); var pldata = {}; for(var x=engine.players.length-1;x>=0;--x) if(engine.players[x]) { var cycle = engine.players[x]; if(cycle.alive) { if(cycle.newPos) doNetSlide(cycle,timestep); if(timeElapsed > 0) { if(x == engine.activePlayer) { if(settings.HACK_TURN_LEFT_WHEN_POSSIBLE > 0) { if(cycle.sensor.left > settings.HACK_TURN_SENSOR_DIST) { cycle.turn(-1); settings.HACK_TURN_LEFT_WHEN_POSSIBLE--; } } if(settings.HACK_TURN_RIGHT_WHEN_POSSIBLE > 0) { if(cycle.sensor.right > settings.HACK_TURN_SENSOR_DIST) { cycle.turn(1); settings.HACK_TURN_RIGHT_WHEN_POSSIBLE--; } } } //bot turning if(cycle.AI) { cycle.AI.think(timestep); } else if(x==engine.activePlayer && (cycle.chatting || settings.CHATBOT_ALWAYS_ACTIVE)) { if(timenow > cycle.lastTurnTime+(settings.CYCLE_DELAY*1000) && cycle.sensor.front < Math.min(5,cycle.sensor.left,cycle.sensor.right)) { if(cycle.sensor.right < cycle.sensor.left) cycle.turn(-1); else if(cycle.sensor.right > cycle.sensor.left) cycle.turn(1); else cycle.turn([-1,1][Math.round(Math.random()*1)]); } } //do turning //if(cycle.turnQueue.length > 0) { //if(cycle.turnQueue.length > 0 && x == 0)console.log(JSON.parse(JSON.stringify(cycle.turnQueue))); if(cycle.turnQueue.length > settings.CYCLE_TURN_MEMORY) cycle.turnQueue.splice(0,cycle.turnQueue.length-settings.CYCLE_TURN_MEMORY); var shouldTime = cycle.lastTurnTime+(settings.CYCLE_DELAY*1000); if(cycle.turnQueue.length > 0 && timeElapsed >= shouldTime/*-delta*/) { //allow the cycle to turn when it should (???) //var diff = (shouldTime-timeElapsed)/1000; //cycle.update(diff); if(settings.CYCLE_MIDAIR_TURN || cycle.position.z-cycle.sensor.bottom == cycle.model.rotation.y) { var dir = cycle.turnQueue[0],dirmult; var olddir = cdir(cycle.rotation.z); cycle.dir.front = (dirmult = cdir(cycle.rotation.z -= (pi(2)/settings.ARENA_AXES)*dir)); //cycle.rotation.z = cycle.rotation.z%(Math.PI*2); //if(cycle.rotation.z < 0) cycle.rotation.z += Math.PI*2; cycle.rotation.z = normalizeRad(cycle.rotation.z); cycle.speed *= settings.CYCLE_TURN_SPEED_FACTOR; cycle.rotation.x = Math.cos(cycle.rotation.z)*0.4*dir; //tilts the cycle cycle.rotation.y = Math.sin(cycle.rotation.z)*0.4*dir; //if(settings.GRAB_SENSORS_ON_TURN) { getCycleSensors(true); } cycle.collidetime = timeElapsed+(((cycle.sensor.front)/cycle.speed)*1000); var mult = (1-settings.CYCLE_RUBBER_MINADJUST); cycle.minDistance.front = Math.max(0,Math.min(cycle.sensor.front*mult,settings.CYCLE_RUBBER_MINDISTANCE)); cycle.lastpos = cycle.position.clone(); //redundant, should be handled by getCycleSensors if(cycle.haswall) cycle.newWallSegment(); if(engine.network) { engine.connection.send(JSON.stringify({ type:"turn",data:rad2deg(cycle.rotation.z),gtime:cycle.gameTime, position:[cycle.position.x,cycle.position.y,cycle.position.z], speed:cycle.speed, rubber:cycle.rubber, brakes:cycle.brakes })); } if(window.svr) //force a player sync { var data = JSON.stringify({type:"griddata",data:[{ position:[cycle.position.x,cycle.position.y,cycle.position.z], direction:rad2deg(cycle.rotation.z), speed:cycle.speed, rubber:cycle.rubber, alive:cycle.alive, netid:x, wall:cycle.walls.map, }],gtime:engine.gtime}); window.svr.clients.forEach(function(ws){ws.send(data)}); } } cycle.turnQueue.splice(0,1); cycle.lastTurnTime = timeElapsed; } } cycle.update(); } if(cycle.rubber > settings.CYCLE_RUBBER+0.0001) cycle.rubber = settings.CYCLE_RUBBER+0.0001; else if(cycle.rubber > 0) cycle.rubber -= (timestep/settings.CYCLE_RUBBER_TIME)*cycle.rubber; else cycle.rubber = 0; //if(timeElapsed/1000 > -3 && cycle.alive) } else if(cycle.walls.map.length != 0 && timenow-cycle.dedtime >= settings.WALLS_STAY_UP_DELAY*1000) { cycle.walls.map = []; console.log("DELETE WALLS id "+x); } else if(settings.RESPAWN_TIME >= 0 && !cycle.alive && timenow-cycle.dedtime > settings.RESPAWN_TIME*1000) { cycle.spawn({x:cycle.position.x||0,y:cycle.position.y||0,z:cycle.position.z||0,dir:cycle.rotation.z||0}); } } if(timeElapsed > -3000 && timeElapsed < 1000) { //timer var time=-timeElapsed/1000,gTime = Math.ceil(time); if(gTime < 0) gTime = 0; if(typeof(engine.timer)=="undefined" || engine.timer != gTime) { engine.timer = gTime; if(engine.hud) engine.hud.fadein = true; if(engine.dedicated) console.log(gTime); else centerMessage(gTime,(gTime-time)); //engine.console.print(gTime+"\n"); } } else if(!engine.network && typeof(engine.winner) == "undefined") { checkForWinner(); } if(!engine.network) { if(!engine.winzone && settings.WIN_ZONE_MIN_ROUND_TIME+engine.deaths*(settings.WIN_ZONE_MIN_LAST_DEATH) < timeElapsed/1000) { var zone = {expansion:settings.WIN_ZONE_EXPANSION}; if(settings.WIN_ZONE_DEATHS) { engine.console.print("Death zone activated. Avoid it!\n"); zone.type = "death"; } else { engine.console.print("Win zone activated. Enter it to win the round.\n"); zone.type = "win"; } zone.radius = Math.min(SMALL_NUM,settings.WIN_ZONE_INITIAL_SIZE)*engine.REAL_ARENA_SIZE_FACTOR; zone.x = engine.REAL_ARENA_SIZE_FACTOR*(engine.logicalBox.center.x+(settings.WIN_ZONE_RANDOMNESS*(Math.random()-0.5)*2)*engine.logicalBox.center.x); zone.y = engine.REAL_ARENA_SIZE_FACTOR*(engine.logicalBox.center.y+(settings.WIN_ZONE_RANDOMNESS*(Math.random()-0.5)*2)*engine.logicalBox.center.y); new Zone(zone).spawn(); console.log("ZONE SPAWNED: "+zone.type); engine.winzone = true; } } for(var x=engine.zones.children.length-1;x>=0;--x) { var zone = engine.zones.children[x].cfg; //zones expand if(zone.radius > 0) { engine.zones.children[x].scale.x = engine.zones.children[x].scale.y = (zone.radius += zone.expansion*timestep*engine.REAL_ARENA_SIZE_FACTOR); } else if(zone.radius < 0) engine.zones.children[x].scale.x = engine.zones.children[x].scale.y = zone.radius = 0; //zone effect var inzone = false; for(var y=engine.players.length-1;y>=0;--y) if(engine.players[y] && engine.players[y].alive) { var cycle = engine.players[y]; if(zone.type == "ball" || zone.type == "soccerball") { for(var z=engine.zones.children.length-1;z>=0;--z) { - var z2n = engine.map.zones[z]; + var z2n = engine.zones.children[z].cfg; if( ( - (zone.type == "ball" && z2n[0] == "fortress") || - (zone.type == "soccerball" && z2n[0] == "soccergoal") + (zone.type == "ball" && z2n.type == "fortress") || + (zone.type == "soccerball" && z2n.type == "soccergoal") ) && - is_in_circle(z2n[1],z2n[2],z2n[3],zone.x,zone.y,zone.radius)) + is_in_circle(z2n.x,z2n.y,z2n.radius,zone.x,zone.y,zone.radius)) { if(!engine.network && engine.winner == undefined) { centerMessage("0x00ff00Goal!"); startNewRound(); } else { zone.xdir *= 1-timestep; zone.ydir *= 1-timestep; } } } } //dont handle zones we don't need to if(!zone.netObject || zone.type.indexOf("ball") >= 0) { //var lastdist = zone.distance(cycle.lastpos); //var dist = zone.distance(cycle.position); var lastdist = pointDistance(zone.mesh.position.x,zone.mesh.position.y,cycle.lastpos.x,cycle.lastpos.y)-zone.radius; var dist = pointDistance(zone.mesh.position.x,zone.mesh.position.y,cycle.position.x,cycle.position.y)-zone.radius; var inZone = (dist <= 0), wasInZone = (lastdist <= 0); if(inZone) { var timediff = cycle.speed*dist; var hitTime = timeElapsed-timediff; if(!wasInZone) zone.onEnter(cycle,hitTime,timestep); if(cycle.alive) zone.onInside(cycle,engine.gtime,timestep); } else if(wasInZone) //left zone { zone.onLeave(cycle,engine.gtime,timestep); //TODO: figure out "precise" left time } else { zone.onOutside(cycle,engine.gtime,timestep); } } if(zone.type == "fortress") //fortress recover rate { zone.rotationSpeed += (settings.ZONE_SPIN_SPEED-zone.rotationSpeed)*timestep*settings.FORTRESS_CONQUEST_DECAY_RATE; } } if(typeof(zone.xdir)+typeof(zone.ydir) !== "undefinedundefined") { - if(zone.bounce && zone.walldist <= timestep) + if(zone.bounce && zone.mesh.walldist <= timestep) { var mindirx,mindiry,mindist=Infinity,apc=0; - var px = zone.x+(zone.walldist*zone.xdir), py = zone.y+(zone.walldist*zone.ydir); + var px = zone.mesh.position.x+(zone.mesh.walldist*zone.xdir), py = zone.mesh.position.y+(zone.mesh.walldist*zone.ydir); for(var i=359;i>0;i--) { var xdir = Math.sin(Math.PI*2*(i/360)), ydir=Math.cos(Math.PI*2*(i/360)); - var xpos = xdir*zone.radius+zone.x, ypos=ydir*zone.radius+zone.y; + var xpos = xdir*zone.radius+zone.mesh.position.x, ypos=ydir*zone.radius+zone.mesh.position.y; var dist = pointDistance(xpos,ypos,px,py); if(dist < mindist) { //mindist += dist; mindirx += xdir; mindiry += ydir; //apc++; mindist=dist;mindirx=xdir;mindiry=ydir;apc=1; } } //mindist /= apc; mindirx /= apc; mindiry /= apc; var speed = Math.sqrt((zone.xdir*zone.xdir)+(zone.ydir*zone.ydir)); if(mindist != Infinity) { var angle = Math.atan2(mindiry,mindirx); //var angle = Math.atan2(mindiry,mindirx)*2; //var angle = Math.atan2(mindiry,mindirx)+(Math.PI/2); //var angle = Math.PI-Math.atan2(mindiry,mindirx); var dir = cdir(angle); zone.xdir = dir[0]*speed; zone.ydir = dir[1]*speed; - zone.x -= dir[0]*realzone.walldist; zone.y -= dir[1]*realzone.walldist; - zone.x += dir[0]*speed*timestep; zone.y += dir[1]*speed*timestep; + zone.mesh.position.x -= dir[0]*zone.mesh.walldist; zone.mesh.position.y -= dir[1]*zone.mesh.walldist; + zone.mesh.position.x += dir[0]*speed*timestep; zone.mesh.position.y += dir[1]*speed*timestep; console.log(zone); } else { zone.xdir *= -1; zone.ydir *= -1; } } else { zone.mesh.position.x += zone.xdir*timestep; zone.mesh.position.y += zone.ydir*timestep; } } } var dc = Object.keys(engine.delayedcommands); for(var x=dc.length-1;x>=0;x--) { var cmd = engine.delayedcommands[dc[x]]; loadcfg(cmd[0]); if(dc[x] >= engine.gtime) { if(cmd[1] > 0) { engine.delayedcommands[dc[x]+cmd[1]] = cmd; } delete engine.delayedcommands[dc[x]]; } } //if(more) game(); } else { engine.gameRunning = false; } } function doDeath(cycle,escape=false) { if(escape || (cycle.sensor.nearestobj == "rim" && !cycle.sensor.lastnonselfobj)) { if(escape || ( cycle.position.x-cycle.minDistance.front > engine.logicalBox.max.x || cycle.position.y-cycle.minDistance.front > engine.logicalBox.max.y || cycle.position.x+cycle.minDistance.front < engine.logicalBox.min.x || cycle.position.y+cycle.minDistance.front < engine.logicalBox.min.y )) { engine.console.print(cycle.getColoredName()+"0xRESETT tried to escape the game grid.\n"); } else { engine.console.print(cycle.getColoredName()+"0xRESETT committed suicide.\n"); } } else { var objtoaccuse = typeof(cycle.sensor.lastnonselfobj)=="undefined"?cycle.sensor.nearestobj:cycle.sensor.lastnonselfobj; if(objtoaccuse == cycle) { engine.console.print(cycle.getColoredName()+"0xRESETT committed suicide.\n"); } else if(typeof(objtoaccuse) == "object") { engine.console.print(objtoaccuse.getColoredName()+"0xRESETT core dumped "+cycle.getColoredName()+"0xRESETT for 1 point.\n"); objtoaccuse.addScore(1); } else { engine.console.print(cycle.getColoredName()+"0xRESETT died.\n"); } } cycle.kill(); } function simulatePlayer(cycle,timestep) { console.warn("Deprecated call to simulatePlayer"); cycle.update(timestep); } function getGoing() { if(!engine.gameRunning) game(); if(!engine.renderRunning) render(); } function pauseRender() { engine.paused = true;//cuts off the loop engine.startOfPause = performance.now(); audioStop(); } function unpauseRender() { for(var ctrl in engine.controls) { engine.controls[ctrl] = []; } //renderLoop = true;//replaces cutoff if(engine.paused) { engine.paused = false; audioStart(); engine.lastGameTime = engine.lastRenderTime = engine.fpsTime = performance.now();//resets delta so we don't pretend the game should have been playing the entire time we were paused var endOfPause = performance.now(); engine.totalPauseTime += (endOfPause - engine.startOfPause); getGoing();//starts the loop again } } function changeViewTarget(a=1,forcechange=false) { if(engine.dedicated) return; if(a != 0) { if(!forcechange && engine.players[engine.activePlayer].alive) return; var first = true; //force the loop to get started var itcount = 0; /*if(alive > 0) */while(first || !engine.players[engine.viewTarget] || !engine.players[engine.viewTarget].alive) { first = false; engine.viewTarget+=a; if(engine.viewTarget >= engine.players.length) engine.viewTarget = 0; if(engine.viewTarget < 0) engine.viewTarget = engine.players.length+engine.viewTarget; itcount++; if(itcount > engine.players.length) break; //console.log(engine.viewTarget); } } if(engine.view == 'cockpit') { for(var x=0;x>engine.players.length;x++) { if(x == engine.viewTarget) engine.players[x].audio.gain.setTargetAtTime(0.2, ctx.currentTime, 0.02); else engine.players[x].audio.gain.setTargetAtTime(6, ctx.currentTime, 1); } } if(!engine.network && !engine.players[engine.activePlayer].spectating && typeof(engine.winner) == "undefined") { switch(settings.FINISH_TYPE) { case 2: engine.asendtm = 0.2; centerMessage("Time Warp!",Infinity); if(engine.hud) engine.hud.fadein = false; break; case 3: centerMessage("Please wait...",Infinity); setTimeout(function() { engine.timemult = 100; while(typeof(engine.winner) == "undefined") { game(true) } engine.timemult = 1; },100); break; } } engine.console.print("Watching "+engine.players[engine.viewTarget].name+"...\n"); } function checkForWinner() { var alivecount = aliveaicount = 0; var numPlay = 0; var alive = [], theplayer = false; var declareRoundWinner = typeof(engine.declareRoundWinner) != "undefined"; for(var x=engine.players.length-1;x>=0;--x) if(typeof(engine.players[x]) != "undefined") { if(!engine.players[x].spectating) numPlay++; if(engine.players[x].alive) { alivecount++; if(engine.players[x].AI) aliveaicount++; alive.push(engine.players[x]); } if(declareRoundWinner && engine.players[x].name == engine.declareRoundWinner) { engine.winner = engine.players[x]; engine.declareRoundWinner = undefined; } } if( (declareRoundWinner) || (settings.GAME_TYPE == 1 && numPlay > 1 && (alivecount <= 1 || (settings.FINISH_TYPE == 1 && aliveaicount == alivecount))) || (/*settings.GAME_TYPE == 0 && */(alivecount <= 0)) ) { if(!declareRoundWinner) { engine.winner = (typeof(alive[0]) == "undefined")?{name:undefined}:alive[0]; } if(settings.RIM_WALL_COLOR_MODE == 2) { if(engine.winner && settings.RIM_WALL_COLOR_MODE == 2) { var color = new THREE.Color(engine.winner.cycleColor); settings.RIM_WALL_RED = color.r; settings.RIM_WALL_GREEN = color.g; settings.RIM_WALL_BLUE = color.b; } } if(engine.asendtm > 0) {engine.asendtm = 0; engine.timemult = 1; centerMessage("Time Warp!",0);} setTimeout(function(){centerMessage("Winner: "+engine.winner.name)},1000); if(!window.svr || window.svr.clients.size != 0) startNewRound(); }//*/ /*if(aliveaicount == alivecount) { engine.console.print("Vroom!"); engine.timemult = 2; engine.asendtm = 1.1; }//*/ } function startNewRound() { if(typeof(engine.winner) == "undefined") engine.winner = null; var endin = 4000; if(engine.round >= settings.LIMIT_ROUNDS) { var highscore = -Infinity, highplayer; for(var x=engine.players.length-1;x>=0;--x) if(typeof(engine.players[x]) != "undefined") { var cycle = engine.players[x]; if(cycle.score > highscore) { highplayer = cycle; highscore = cycle.score; } else if(cycle.score == highscore) { highplayer = null; } } if(highplayer != null) { setTimeout(function(){centerMessage("Match Winner: "+highplayer.name);engine.console.print("Match Winner: "+highplayer.name+" with "+highscore+" points.\n")},4000); } engine.round = 0; endin += 4000; } if(!settings.ROUND_WAIT) engine.uRound = setTimeout(doNewRound,endin); } function updateScoreBoard() { if(window.svr) { var tmp = []; for(var x=engine.players.length-1;x>=0;--x) if(engine.players[x]) { tmp.push({netid:x,score:engine.players[x].score,ping:engine.players[x].ping,chatting:engine.players[x].chatting}); } var data = JSON.stringify({type:"scoredata",data:tmp}); window.svr.clients.forEach(function(ws){ws.send(data);}); } if(engine.network) { engine.connection.send(JSON.stringify({type:"playdata",data:{chatting:engine.players[engine.activePlayer].chatting}})); } if(engine.dedicated || scoreboard.style.display == "none") return; var scoreBoard = document.getElementById("scoreboard").children[0]; var playersSB = scoreBoard.children[1]; var tmp = ""; for(var x=0;x"+(cycle.chatting?"*":" ")+replaceColors(cycle.getColoredName())+""+replaceColors(cycle.alive?"0x00ff00Yes":"0xff0000No")+""+cycle.score+""+cycle.ping+""+(cycle.team?cycle.team.name:"")+""; } playersSB.innerHTML = tmp; } /*function updateScoreBoard() { var scoreboard = ""; for(var x=engine.players.length-1;x>=0;--x) if(typeof(engine.players[x]) != "undefined") { var cycle = engine.players[x]; scoreboard += (cycle.chatting?"*":" ")+removeColors(cycle.name)+" "+cycle.alive?"Yes":"No"+" "+cycle.score+" "+cycle.ping+" "; } }*/ diff --git a/scripts/zone.js b/scripts/zone.js index 1412cdd..3a4f403 100644 --- a/scripts/zone.js +++ b/scripts/zone.js @@ -1,321 +1,321 @@ /* * 3DCycles - A lightcycle game. * Copyright (C) 2019 Glen Harpring * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ if(typeof(THREE) == "undefined") var THREE = require('./lib/Three.js'); var flagColors = [ 0x55AAFF, 0xFFFF55, 0xFF5555, 0x55FF55, 0xFF55FF, 0x55FFFF, 0xFFFFFF, 0x888888]; class Zone { spawn() { engine.zones.add(this.mesh); return this; } destroy() { engine.zones.remove(this.mesh); return this; } constructor(prop) { this.timesEntered = 0; this.netObject = false; this.type = prop.type||"null"; this.rotationSpeed = isNaN(prop.rot)?settings.ZONE_SPIN_SPEED:prop.rot; this.value = prop.value||0; this.expansion = prop.expansion||0; this.radius = prop.radius||0; this.xdir = prop.xdir||0; this.ydir = prop.ydir||0; this.bounce = !!prop.bounce; this.team = false; var zoneHeight = prop.height||settings.ZONE_HEIGHT; if (settings.ZONE_SEGMENTS < 1) { settings.ZONE_SEGMENTS = 11; } var zoneSegments = (Math.floor(this.radius/10)*10)+1; if (zoneSegments < 11) { zoneSegments = 11; } var zoneColor = 0xFFFFFF; if(prop.color || prop.color === 0) { zoneColor = prop.color; } else { switch(this.type) { case "death": zoneColor = 0xFF0000; break; case "soccerball": zoneColor = 0xFF8888; break; case "soccergoal": zoneColor = 0xBB6666; break; case "rubber": zoneColor = 0xFFB033; break; case "rubberadjust": zoneColor = 0xFF8800; break; case "oneway": zoneColor = 0xFFFF00; break; case "win": zoneColor = 0x00FF00; break; case "target": zoneColor = 0x00DD00; break; case "teleport": zoneColor = 0x00AA00; break; case "speed": zoneColor = 0x00FF88; break; case "acceleration": zoneColor = 0x00BB66; break; case "blast": zoneColor = 0x0088FF; break; case "fortress": case "flag": var lastDist = Infinity; var closestSpawn = 0; for(var w=0;w 7) { zoneColor = 0x4488FF; } else { zoneColor = (this.type=="fortress"?teamColor:teamColor)(closestSpawn); } this.team = closestSpawn; break; case "object": zoneColor = 0xBB0066; break; case "checkpoint": zoneColor = 0xFF0088; break; case "koh": zoneColor = 0xDDDDDD; break; case "wall": case "ball": zoneColor = 0xFFFFFF; break; case "switch": zoneColor = 0x999999; break; } } var color = typeof(zoneColor)=="object"?zoneColor:new THREE.Color(zoneColor), geo = new THREE.Geometry(); switch(prop.shape) { case "polygon": var min = [Infinity,Infinity], max = [-Infinity,-Infinity]; for(var i=0;i=0;z--) { if(point[z] < min[z]) min[z] = point[z]; if(point[z] > max[z]) max[z] = point[z]; console.log(point[z]); } } for(var i=0,halfvert=(geo.vertices.length/2)-1;imin[1]?min[0]:min[1]); this.shape = "polygon"; break; default: //circle var zoneSegCoords = [];//get the coordinates for each segment vertex var zoneSegMidpoints = [];//get midpoints for each segment var trueSegments = []; for (var i = 0; i < settings.ZONE_SEGMENTS; i++) { var zpx = Math.cos(2 * Math.PI * i / settings.ZONE_SEGMENTS); var zpy = Math.sin(2 * Math.PI * i / settings.ZONE_SEGMENTS); zoneSegCoords.push({x:zpx, y:zpy}); if (i > 0 && i != settings.ZONE_SEGMENTS-1) {//all segments starting from the second zoneSegMidpoints[i] = { x:((zoneSegCoords[i-1].x+zoneSegCoords[i].x)/2), y:((zoneSegCoords[i-1].y+zoneSegCoords[i].y)/2) }; } else if (i == settings.ZONE_SEGMENTS-1) {//last segment + first zoneSegMidpoints[i] = { x:((zoneSegCoords[i-1].x+zoneSegCoords[i].x)/2), y:((zoneSegCoords[i-1].y+zoneSegCoords[i].y)/2) }; zoneSegMidpoints[0] = { x:((zoneSegCoords[0].x+zoneSegCoords[i].x)/2), y:((zoneSegCoords[0].y+zoneSegCoords[i].y)/2) }; } } //with midpoints, determine segments for (var s = 0; s < settings.ZONE_SEGMENTS; s++) { //var segmentFullLength = pointDistance( zoneSegCoords[s].x, zoneSegCoords[s].y, zoneSegCoords[s+1].x, zoneSegCoords[s+1].y ); //var adjustedSegLength = segmentFullLength * settings.ZONE_SEG_LENGTH; if (s == 0) { var np1x = (zoneSegMidpoints[0].x + (settings.ZONE_SEG_LENGTH * ( zoneSegCoords[zoneSegCoords.length-1].x - zoneSegMidpoints[0].x) ) ); var np1y = (zoneSegMidpoints[0].y + (settings.ZONE_SEG_LENGTH * ( zoneSegCoords[zoneSegCoords.length-1].y - zoneSegMidpoints[0].y) ) ); var np2x = (zoneSegMidpoints[0].x + (settings.ZONE_SEG_LENGTH * ( zoneSegCoords[s].x - zoneSegMidpoints[0].x) ) ); var np2y = (zoneSegMidpoints[0].y + (settings.ZONE_SEG_LENGTH * ( zoneSegCoords[s].y - zoneSegMidpoints[0].y) ) ); } else { var np1x = (zoneSegMidpoints[s].x + (settings.ZONE_SEG_LENGTH * ( zoneSegCoords[s-1].x - zoneSegMidpoints[s].x) ) ); var np1y = (zoneSegMidpoints[s].y + (settings.ZONE_SEG_LENGTH * ( zoneSegCoords[s-1].y - zoneSegMidpoints[s].y) ) ); var np2x = (zoneSegMidpoints[s].x + (settings.ZONE_SEG_LENGTH * ( zoneSegCoords[s].x - zoneSegMidpoints[s].x) ) ); var np2y = (zoneSegMidpoints[s].y + (settings.ZONE_SEG_LENGTH * ( zoneSegCoords[s].y - zoneSegMidpoints[s].y) ) ); } trueSegments[s] = { x1:np1x, y1:np1y, x2:np2x, y2:np2y }; } //have segment coordinates, now build it for (var n = 0; n < trueSegments.length; n++) { geo.vertices.push( new THREE.Vector3( (trueSegments[n].x1), (trueSegments[n].y1), 0) ); geo.vertices.push( new THREE.Vector3( (trueSegments[n].x2), (trueSegments[n].y2), 0) ); } for (var n = 0; n < trueSegments.length; n++) { geo.vertices.push( new THREE.Vector3( (trueSegments[n].x1), (trueSegments[n].y1), settings.ZONE_HEIGHT) ); geo.vertices.push( new THREE.Vector3( (trueSegments[n].x2), (trueSegments[n].y2), settings.ZONE_HEIGHT) ); } for (var i = 0; i < (geo.vertices.length/2)-1; i+=2) { geo.faces.push( new THREE.Face3( (i), (i+1), (i+(geo.vertices.length/2)) ), //a,b,c new THREE.Face3( (i+(geo.vertices.length/2)+1), (i+(geo.vertices.length/2)), (i+1) ) //d,c,b ); } this.shape = "circle"; break; } //var alpha = Math.max(color.r,color.g,color.b); //color.r /= alpha; color.g /= alpha; color.b /= alpha; if(!this.mat) this.mat = new THREE.MeshBasicMaterial( { color: color, transparent: settings.ALPHA_BLEND, opacity: settings.ZONE_ALPHA/**alpha*/, side: THREE.DoubleSide } ); if(!this.mesh) { this.mesh = new THREE.Mesh(geo,this.mat); this.mesh.position.set(prop.x||0,prop.y||0,prop.z||0); this.mesh.scale.set(this.radius||1,this.radius||1,1); this.mesh.cfg = this; } } distance(position) { switch(this.shape) { case "circle": return pointDistance(this.mesh.position.x,this.mesh.position.y,position.x,position.y); break; case "polygon": var min = Infinity, x, tmp, coords = this.mesh.geometry.vertices; for(var i=(coords.length/2)-1;i>=0;x=(--i)-1) { if(coords[x] !== undefined) { tmp = distanceoflines( coords[i].x,coords[i].y, coords[x].x,coords[x].y, position.x,position.y, position.x,position.y ); if(min > tmp) { min = tmp; } } } return min; break; } return Infinity; } onEnter(cycle,time) { switch(this.type) { case "wall": cycle.position.x -= cycle.dir.front[0]*(engine.gtime-time); cycle.position.y -= cycle.dir.front[1]*(engine.gtime-time); break; case "death": cycle.kill(); engine.console.print(cycle.getColoredName()+"0xRESETT exploded on a deathzone.\n"); break; case "win": if(engine.winner == undefined && engine.declareRoundWinner == undefined) { //engine.console.print(cycle.getColoredName()+"0xRESETT "); this.expansion = -1; engine.declareRoundWinner = cycle.name; } break; case "target": loadcfg(settings.DEFAULT_TARGET_COMMAND.replace(/\\n/g,"\n")); cycle.addScore(settings.TARGET_INITIAL_SCORE); break; } } onInside(cycle,time,timestep) { switch(this.type) { case "rubber": cycle.rubber += timestep*this.value; if(cycle.rubber >= settings.CYCLE_RUBBER) { cycle.kill(); engine.console.print(cycle.getColoredName()+"0xRESETT exploded on a rubberzone.\n"); } break; case "fortress": if(engine.gtime > 0) { - this.rotationSpeed += timestep*0.5; + this.rotationSpeed += timestep*settings.FORTRESS_CONQUEST_RATE; if(this.rotationSpeed > settings.ZONE_SPIN_SPEED*16) { engine.console.print(cycle.getColoredName()+"0xRESETT conquered a fortress zone.\n"); this.type = "null"; this.expansion = -10; engine.declareRoundWinner = cycle.name; } } break; case "ball": case "soccerball": var mindirx=0,mindiry=0,mindist=Infinity,apc=0; for(var i=359;i>0;i--) { var xdir = Math.cos(Math.PI*2*(i/360)), ydir=Math.sin(Math.PI*2*(i/360)); - var xpos = xdir*this.radius+this.x, ypos=ydir*this.radius+this.y; + var xpos = xdir*this.radius+this.mesh.position.x, ypos=ydir*this.radius+this.mesh.position.y; var dist = pointDistance(xpos,ypos,cycle.position.x,cycle.position.y); if(dist < mindist) { /*if(mindist == Infinity)mindist = dist; else mindist += dist; mindirx -= xdir; mindiry -= ydir; apc++;*/ mindist=dist;mindirx=xdir;mindiry=ydir;apc=1; } } //mindist /= apc; mindirx /= apc; mindiry /= apc; if(mindist != Infinity) { this.xdir = -mindirx*cycle.speed; this.ydir = -mindiry*cycle.speed; if(!this.bounce) this.bounce = true; } break; case "speed": cycle.speed = this.value||0; break; case "acceleration": accel = (this.value||0); cycle.accel += accel; cycle.speed += cycle.speed*accel; break; } } onLeave(cycle,time) { } onOutside(cycle,time) { } } if(typeof(module) != "undefined") module.exports = Zone;