365 lines
11 KiB
Java
365 lines
11 KiB
Java
package enemyAI;
|
|
|
|
import core.Rect;
|
|
import core.baseInfo;
|
|
import core.mainThread;
|
|
import core.vector;
|
|
import entity.lightTank;
|
|
import entity.solidObject;
|
|
|
|
public class scoutingManagerAI {
|
|
|
|
public baseInfo theBaseInfo;
|
|
|
|
public int frameAI;
|
|
|
|
public int scoutingMode;
|
|
|
|
public final int patrolling = 0;
|
|
public final int exploring = 1;
|
|
|
|
public float[][] patrolNodes;
|
|
public float[][] exploringNodes;
|
|
|
|
public int destinationNode;
|
|
|
|
public boolean movementOrderIssued;
|
|
|
|
public vector tempVector1, tempVector2, tempVector3;
|
|
|
|
public int avoidingIncomingPlayerUnitCooldown;
|
|
|
|
//scout unit consists a sole light tank
|
|
public solidObject scout;
|
|
|
|
public scoutingManagerAI(){
|
|
this.theBaseInfo = mainThread.ec.theBaseInfo;
|
|
|
|
patrolNodes = new float[][]{
|
|
{16, 30}, {2, 29}, {15, 17}, {16, 14}, {27f, 1}, {30, 16}, {16, 14}, {15, 17}
|
|
};
|
|
|
|
exploringNodes = new float[][]{
|
|
{8f, 3f}, {2,2}, {3, 6},{11.5f, 7.5f}
|
|
|
|
|
|
};
|
|
|
|
destinationNode = 0;
|
|
|
|
tempVector1 = new vector(0,0,0);
|
|
tempVector2 = new vector(0,1,0);
|
|
tempVector3 = new vector(0,0,0);
|
|
|
|
}
|
|
|
|
public void processAI(){
|
|
|
|
frameAI = mainThread.ec.frameAI;
|
|
|
|
if(avoidingIncomingPlayerUnitCooldown > 0)
|
|
avoidingIncomingPlayerUnitCooldown--;
|
|
|
|
boolean scoutIsLightTank = scout != null && scout.type == 0;
|
|
if((frameAI%275 > 235 && frameAI%275 < 275 && !scoutIsLightTank) && frameAI < 900 && scoutingMode == patrolling || (scoutIsLightTank && frameAI < 240)){
|
|
scoutingMode = exploring;
|
|
destinationNode = 0;
|
|
movementOrderIssued = false;
|
|
}
|
|
|
|
//produce a scout unit if there is no scout unit on the map or the scout unit has been destroyed
|
|
|
|
int numberOfLightTankOnQueue = 0;
|
|
for(int i = 0; i < mainThread.theAssetManager.factories.length; i++){
|
|
if(mainThread.theAssetManager.factories[i] != null && mainThread.theAssetManager.factories[i].teamNo != 0){
|
|
numberOfLightTankOnQueue += mainThread.theAssetManager.factories[i].numOfLightTankOnQueue;
|
|
}
|
|
}
|
|
if(numberOfLightTankOnQueue == 0 && needLightTank()){
|
|
for(int i = 0; i < mainThread.theAssetManager.factories.length; i++){
|
|
if(mainThread.theAssetManager.factories[i] != null && mainThread.theAssetManager.factories[i].teamNo != 0){
|
|
if(mainThread.theAssetManager.factories[i].isIdle()){
|
|
mainThread.theAssetManager.factories[i].buildLightTank();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int numberOfStealthTankOnQueue = 0;
|
|
for(int i = 0; i < mainThread.theAssetManager.factories.length; i++){
|
|
if(mainThread.theAssetManager.factories[i] != null && mainThread.theAssetManager.factories[i].teamNo != 0){
|
|
numberOfStealthTankOnQueue += mainThread.theAssetManager.factories[i].numOfStealthTankOnQueue;
|
|
}
|
|
}
|
|
if(numberOfStealthTankOnQueue == 0 && needStealthTank()){
|
|
for(int i = 0; i < mainThread.theAssetManager.factories.length; i++){
|
|
if(mainThread.theAssetManager.factories[i] != null && mainThread.theAssetManager.factories[i].teamNo != 0){
|
|
if(mainThread.theAssetManager.factories[i].isIdle()){
|
|
mainThread.theAssetManager.factories[i].buildStealthTank();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(scout == null || scout.currentHP <=0){
|
|
scout = null;
|
|
movementOrderIssued= false;
|
|
scoutingMode = patrolling;
|
|
destinationNode = (int)(Math.random()*patrolNodes.length);
|
|
}
|
|
|
|
if(scout != null){
|
|
|
|
|
|
|
|
if(avoidingIncomingPlayerUnitCooldown == 0){
|
|
|
|
if(scoutingMode == patrolling){
|
|
destinationNode = destinationNode%patrolNodes.length;
|
|
if(!scountReachedDestination(scout, patrolNodes, destinationNode)){
|
|
|
|
if(!movementOrderIssued){
|
|
|
|
scout.moveTo(patrolNodes[destinationNode][0], patrolNodes[destinationNode][1]);
|
|
scout.currentCommand = solidObject.move;
|
|
scout.secondaryCommand = solidObject.StandBy;
|
|
|
|
if(scout.leftFactory)
|
|
movementOrderIssued = true;
|
|
|
|
}
|
|
|
|
}else{
|
|
destinationNode++;
|
|
movementOrderIssued = false;
|
|
|
|
}
|
|
}
|
|
|
|
if(scoutingMode == exploring){
|
|
|
|
|
|
if(!scountReachedDestination(scout, exploringNodes, destinationNode)){
|
|
|
|
if(!movementOrderIssued){
|
|
|
|
scout.moveTo(exploringNodes[destinationNode][0], exploringNodes[destinationNode][1]);
|
|
scout.currentCommand = solidObject.move;
|
|
scout.secondaryCommand = solidObject.StandBy;
|
|
|
|
|
|
if(scout.leftFactory)
|
|
movementOrderIssued = true;
|
|
}
|
|
|
|
}else{
|
|
destinationNode++;
|
|
movementOrderIssued = false;
|
|
}
|
|
|
|
if(destinationNode >0 && destinationNode %exploringNodes.length == 0){
|
|
scoutingMode = patrolling;
|
|
destinationNode = 0;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if(scout.type == 0) {
|
|
|
|
|
|
|
|
|
|
if(mainThread.ec.theDefenseManagerAI.minorThreatLocation.x != 0 || mainThread.ec.theDefenseManagerAI.majorThreatLocation.x != 0 || (!mainThread.ec.theMapAwarenessAI.canRushPlayer && frameAI > 240)) {
|
|
if(scout.currentHP > 0) {
|
|
scout.moveTo(mainThread.ec.theUnitProductionAI.rallyPoint.x, mainThread.ec.theUnitProductionAI.rallyPoint.z);
|
|
scout.currentCommand = solidObject.attackMove;
|
|
scout.secondaryCommand = solidObject.attackMove;
|
|
|
|
if(frameAI > 310) {
|
|
mainThread.ec.theUnitProductionAI.addLightTank((lightTank)scout);
|
|
scout = null;
|
|
}
|
|
}
|
|
}else if(mainThread.ec.theMapAwarenessAI.canRushPlayer && frameAI > 290) {
|
|
mainThread.ec.theUnitProductionAI.addLightTank((lightTank)scout);
|
|
|
|
scout.moveTo(mainThread.ec.theUnitProductionAI.rallyPoint.x, mainThread.ec.theUnitProductionAI.rallyPoint.z);
|
|
scout.currentCommand = solidObject.attackMove;
|
|
scout.secondaryCommand = solidObject.attackMove;
|
|
scout = null;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//try to avoid collision with player units
|
|
int xPos_old = scout.boundary2D.x1;
|
|
int yPos_old = scout.boundary2D.y1;
|
|
|
|
int xPos = xPos_old;
|
|
int yPos = yPos_old;
|
|
|
|
if(scout.movement.x != 0 || scout.movement.z != 0){
|
|
tempVector1.set(scout.movement);
|
|
tempVector1.unit();
|
|
tempVector1.scale(0.1f);
|
|
|
|
for(int i = 1; i < 20; i ++){
|
|
xPos = (int)((scout.centre.x + tempVector1.x*i)*64) - 8;
|
|
yPos = (int)((scout.centre.z + tempVector1.z*i)*64) + 8;
|
|
|
|
scout.boundary2D.setOrigin(xPos, yPos);
|
|
|
|
//increased size of the 2D boundary of the scount for better collision detection.
|
|
scout.boundary2D.expand(8);
|
|
|
|
solidObject obstacle = checkForCollision(scout.boundary2D);
|
|
|
|
scout.boundary2D.shrink(8);
|
|
|
|
|
|
//ignore harvesters
|
|
if(obstacle != null && obstacle.type == 2)
|
|
continue;
|
|
|
|
|
|
if(obstacle != null && !(i > 10 && ((obstacle.movement.x == 0 && obstacle.movement.z == 0) || (tempVector1.dot(obstacle.movement) > 0)))){
|
|
|
|
tempVector3.cross(tempVector1, tempVector2);
|
|
tempVector3.unit();
|
|
tempVector3.scale(2);
|
|
|
|
if(tempVector3.dot(obstacle.movement) > 0)
|
|
tempVector3.scale(-1);
|
|
|
|
avoidingIncomingPlayerUnitCooldown = 2;
|
|
|
|
scout.moveTo(scout.centre.x + tempVector3.x, scout.centre.z + tempVector3.z);
|
|
scout.currentCommand = solidObject.move;
|
|
scout.secondaryCommand = solidObject.StandBy;
|
|
movementOrderIssued = false;
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
scout.boundary2D.setOrigin(xPos_old, yPos_old);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
public solidObject checkForCollision(Rect myRect){
|
|
|
|
//check if the tank collide with the border
|
|
if(myRect.x1 < 0 || myRect.x2 > 2047 || myRect.y2 < 1 || myRect.y1 > 2048){
|
|
return null;
|
|
}
|
|
|
|
|
|
int newOccupiedTile0= myRect.x1/16 + (127 - myRect.y1/16)*128;
|
|
int newOccupiedTile1 = newOccupiedTile0 + 1;
|
|
int newOccupiedTile2 = newOccupiedTile0 + 128;
|
|
int newOccupiedTile3 = newOccupiedTile0 + 129;
|
|
|
|
solidObject tempObstacle = null;
|
|
solidObject[] tile;
|
|
|
|
if(newOccupiedTile0 >= 0 && newOccupiedTile0 < 16384){
|
|
tile = mainThread.gridMap.tiles[newOccupiedTile0];
|
|
for(int i = 0; i < 5; i++){
|
|
if(tile[i] != null){
|
|
if(tile[i].boundary2D.intersect(myRect) && tile[i].teamNo == 0 && tile[i].type < 100 && !tile[i].isCloaked)
|
|
return tile[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
if(newOccupiedTile1 >= 0 && newOccupiedTile1 < 16384){
|
|
tile = mainThread.gridMap.tiles[newOccupiedTile1];
|
|
for(int i = 0; i < 5; i++){
|
|
if(tile[i] != null){
|
|
if(tile[i].boundary2D.intersect(myRect) && tile[i].teamNo == 0 && tile[i].type < 100 && !tile[i].isCloaked)
|
|
return tile[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
if(newOccupiedTile2 >= 0 && newOccupiedTile2 < 16384){
|
|
tile = mainThread.gridMap.tiles[newOccupiedTile2];
|
|
for(int i = 0; i < 5; i++){
|
|
if(tile[i] != null){
|
|
if(tile[i].boundary2D.intersect(myRect) && tile[i].teamNo == 0 && tile[i].type < 100 && !tile[i].isCloaked)
|
|
return tile[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
if(newOccupiedTile3 >= 0 && newOccupiedTile3 < 16384){
|
|
tile = mainThread.gridMap.tiles[newOccupiedTile3];
|
|
for(int i = 0; i < 5; i++){
|
|
if(tile[i] != null){
|
|
if(tile[i].boundary2D.intersect(myRect) && tile[i].teamNo == 0 && tile[i].type < 100 && !tile[i].isCloaked)
|
|
return tile[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
return tempObstacle;
|
|
}
|
|
|
|
public boolean scountReachedDestination(solidObject o, float[][] nodes, int nodeIndex){
|
|
float distanceToDestination = (float)Math.sqrt((o.centre.x - nodes[nodeIndex][0]) * (o.centre.x - nodes[nodeIndex][0]) + (o.centre.z - nodes[nodeIndex][1]) * (o.centre.z - nodes[nodeIndex][1]));
|
|
|
|
|
|
if(distanceToDestination <= 0.1f)
|
|
return true;
|
|
|
|
if(distanceToDestination <= 1.5f && (o.currentMovementStatus == o.hugLeft || o.currentMovementStatus == o.hugRight))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//build light tank as scout when stealth tank tech is locked
|
|
public boolean needLightTank(){
|
|
if(frameAI < 200 && scout == null && !theBaseInfo.canBuildStealthTank && mainThread.ec.theDefenseManagerAI.minorThreatLocation.x == 0 && mainThread.ec.theDefenseManagerAI.majorThreatLocation.x == 0){
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public boolean needStealthTank(){
|
|
if(theBaseInfo.canBuildStealthTank){
|
|
if((scout == null || scout.currentHP <= 0 || scout.type != 6) && frameAI > 380){
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void addLightTank(solidObject o){
|
|
scout = o;
|
|
}
|
|
|
|
public void addStealthTank(solidObject o){
|
|
if(scout != null && scout.currentHP > 0 && scout.type == 0){
|
|
mainThread.ec.theUnitProductionAI.addLightTank((lightTank)scout);
|
|
scout.moveTo(mainThread.ec.theUnitProductionAI.rallyPoint.x, mainThread.ec.theUnitProductionAI.rallyPoint.z);
|
|
scout.currentCommand = solidObject.move;
|
|
scout.secondaryCommand = solidObject.StandBy;
|
|
}
|
|
destinationNode = 0;
|
|
scout = o;
|
|
movementOrderIssued = false;
|
|
}
|
|
}
|