diff --git a/scripts/ai.js b/scripts/ai.js index 84f87e8..ce960e1 100644 --- a/scripts/ai.js +++ b/scripts/ai.js @@ -1,155 +1,222 @@ /* * 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. */ class AI { think(timestep) { var shouldTurn = this.cycle.sensor.front < Math.min(5,Math.max(this.cycle.sensor.leftTurn,this.cycle.sensor.rightTurn)), dangerouslyNearWall = this.cycle.sensor.front <= settings.CYCLE_RUBBER_MINDISTANCE+1, usingRubber = this.cycle.rubber > this.lastRubber; if(engine.gtime > this.cycle.lastTurnTime+(settings.CYCLE_DELAY*1000)) { switch(this.state) { case 0: if(shouldTurn) return this.basicDecision(); break; case 2: //practically state 0 but theoretically better! var nearestPlayer = false, nearestPlayerDist = Infinity; for(var x=engine.players.length-1;x>=0;--x) if(engine.players[x]) { if(engine.players[x] != this.cycle) { var dist = pointDistance(engine.players[x].position.x,engine.players[x].position.y, this.cycle.position.x,this.cycle.position.y); - if(dist > nearestPlayerDist) + if(dist < nearestPlayerDist) { nearestPlayerDist = dist; nearestPlayer = engine.players[x]; } } } this.nearestPlayer = nearestPlayer; - if(shouldTurn) + if(shouldTurn || (usingRubber && this.cycle.rubber >= settings.CYCLE_RUBBER*0.8)) { + if(this.sameTurnsUsed > 3 && + this.cycle.sensor.objrear == this.cycle && + this.cycle.sensor.nearestobj == this.cycle && + this.cycle.sensor.objleft == this.cycle && + this.cycle.sensor.objright == this.cycle) + { + //this.basicDecision(); + if(-this.lastTurn == -1) + var d = this.cycle.sensor.leftTurn; + else + var d = this.cycle.sensor.rightTurn; + //if(d < 0.1) + { + this.turn(-this.lastTurn); + this.turn(this.lastTurn); + console.log("[DEBUG] Camping"); + this.state = 4; + return true; + } + /*else + { + this.cycle.turn(this.lastTurn); + this.cycle.turn(this.lastTurn); + this.cycle.turn(this.lastTurn); + this.cycle.turn(-this.lastTurn); + return true; + }*/ + //this.basicDecision(); + //this.sameTurnsUsed = -4; + } return this.basicDecision(); } else if(nearestPlayer) { + //engine.console.print("target: "+removeColors(nearestPlayer.name)+"\n"); + if(nearestPlayer == this.cycle.sensor.objrear && (nearestPlayer != this.cycle.sensor.objleft && nearestPlayer != this.cycle.sensor.objright)) { - this.cycle.turn(this.getRelDirToPoint(nearestPlayer.position.x,nearestPlayer.position.y)); //turn in front of the player + this.turn(this.getRelDirToPoint(nearestPlayer.position.x,nearestPlayer.position.y)); //turn in front of the player } - else if(nearestPlayer.sensor.objfront == nearestPlayer) //we're in front of our nearest cycle + /*else if(this.cycle.sensor.nearestobj == nearestPlayer + || this.cycle == nearestPlayer.sensor.objrear + ) + //we're in front of our nearest cycle { - this.cycle.turn(this.getRelDirToPoint(nearestPlayer.position.x,nearestPlayer.position.y)); //turn back to the player - } - return; + this.turn(this.getRelDirToPoint(nearestPlayer.position.x,nearestPlayer.position.y)); //turn back to the player + }*/ } break; case 1: - if(this.target === false) this.target = engine.players[Math.round(Math.random()*engine.players.length)]; - if(this.target == this || typeof(this.target) == "undefined" || !this.target.alive) + if(this.target === false) + { + this.target = engine.players[Math.round(Math.random()*engine.players.length)]; + if(this.target) engine.console.print("target: "+removeColors(this.target.name)+"\n"); + } + if(this.target == this.cycle || typeof(this.target) == "undefined" || !this.target.alive) { this.target = false; } else { this.huntDownTarget(); } if(usingRubber) this.basicDecision(); break; case 3: + break; + case 4: //! temp state: wait until we're out of our camp. + if(this.cycle.sensor.objrear == this.cycle && + this.cycle.sensor.nearestobj == this.cycle && + this.cycle.sensor.objleft == this.cycle && + this.cycle.sensor.objright == this.cycle) + { + //if(usingRubber) return this.basicDecision(); + if(this.cycle.sensor.front <= this.cycle.minDistance.front+0.01) + return this.basicDecision(); + } + else + { + console.log("[DEBUG] Normal"); + this.state = 2; + return true; + } break; default: console.error("Invalid state "+this.state+"!"); this.state = 0; break; } } if(this.destPoints.length > 0 && engine.gtime > this.cycle.lastTurnTime+(settings.CYCLE_DELAY*1000)) { var pt = this.destPoints[0]; - this.cycle.turn(this.getRelDirToPoint(pt[0],pt[1])); + this.turn(this.getRelDirToPoint(pt[0],pt[1])); } this.cycle.braking = settings.AI_FORCE_BRAKE||(settings.CYCLE_BRAKE > 0 && dangerouslyNearWall && usingRubber); this.lastRubber = this.cycle.rubber; } basicDecision() { if(this.cycle.sensor.rightTurn < this.cycle.sensor.leftTurn) //if(this.cycle.sensor.left > this.cycle.sensor.front) - this.cycle.turn(-1); + this.turn(-1); else if(this.cycle.sensor.rightTurn > this.cycle.sensor.leftTurn) //if(this.cycle.sensor.right > this.cycle.sensor.front) - this.cycle.turn(1); + this.turn(1); else - this.cycle.turn([-1,1][Math.round(Math.random()*1)]); + this.turn([-1,1][Math.round(Math.random()*1)]); } huntDownTarget() { var nearX = this.target.position.x, nearY = this.target.position.y, nearDist = pointDistance(this.target.position.x,this.target.position.y, this.cycle.position.x,this.cycle.position.y); var playerDist = nearDist; for(var i=this.target.walls.length;i>=0;--i) { var wall = this.target.walls[i]; var dist = pointDistance(wall[0],wall[1], this.cycle.position.x,this.cycle.position.y); if(dist < nearDist) { nearDist = dist; nearX = wall[0]; nearY = wall[1]; } } + this.turn(this.getRelDirToPoint(nearX,nearY)); //turn back to the player } getRelDirToPoint(x,y) { //var dist = pointDistance(x,y,this.cycle.position.x,this.cycle.position.y); var dir = [(this.cycle.position.x-x),(this.cycle.position.y-y)]; var ang = Math.atan2(dir[1],dir[0]); //if(Math.round((this.cycle.rotation.z)/8) != Math.round(ang/8)) //point is not in front { var angdiff = normalizeRad(this.cycle.rotation.z-ang); if(angdiff < Math.PI) { return -1; } else if(angdiff > Math.PI) { return 1; } //centerMessage(angdiff); } } + turn(dir) + { + this.cycle.turn(dir); + if(dir == this.lastTurn) + this.sameTurnsUsed++; + else + this.sameTurnsUsed = 0; + this.lastTurn = dir; + } constructor(cycle) { this.cycle = cycle; this.lastRubber = 0; this.state = 2; //theoretical states: 0: survive, 1: trace, 2: closecombat, 3: pathfind + this.lastTurn = 0; + this.sameTurnsUsed = 0; this.target = false; this.targetX = NaN; this.targetY = NaN; this.destPoints = []; } } if(typeof(module) != "undefined") module.exports = AI;