238 lines
7.9 KiB
Java
238 lines
7.9 KiB
Java
package enemyAI;
|
|
|
|
import core.baseInfo;
|
|
import core.mainThread;
|
|
import entity.solidObject;
|
|
import entity.techCenter;
|
|
import entity.rocketTank;
|
|
|
|
//micro manage the units on the battle field to trade units better against player
|
|
|
|
public class microManagementAI {
|
|
|
|
public baseInfo theBaseInfo;
|
|
|
|
|
|
public int currentState;
|
|
public final int booming = 0;
|
|
public final int aggressing = 1;
|
|
public final int defending = 2;
|
|
|
|
public solidObject[] playerUnitInMinimap;
|
|
public solidObject[] unitInCombatRadius;
|
|
public solidObject[] playerStaticDefenceInMinimap;
|
|
|
|
public float combatCenterX;
|
|
public float combatCenterZ;
|
|
|
|
public int numberOfPlayerUnitsOnMinimap;
|
|
|
|
public microManagementAI(){
|
|
this.theBaseInfo = mainThread.ec.theBaseInfo;
|
|
}
|
|
|
|
public void processAI(){
|
|
|
|
unitInCombatRadius = mainThread.ec.theUnitProductionAI.unitInCombatRadius;
|
|
playerUnitInMinimap = mainThread.ec.theMapAwarenessAI.playerUnitInMinimap;
|
|
playerStaticDefenceInMinimap = mainThread.ec.theMapAwarenessAI.playerStaticDefenceInMinimap;
|
|
|
|
currentState = mainThread.ec.theCombatManagerAI.currentState;
|
|
|
|
combatCenterX = mainThread.ec.theUnitProductionAI.combatAICenterX;
|
|
combatCenterZ = mainThread.ec.theUnitProductionAI.combatAICenterZ;
|
|
|
|
numberOfPlayerUnitsOnMinimap = mainThread.ec.theMapAwarenessAI.numberOfPlayerUnitsOnMinimap;
|
|
|
|
float x1 = 0;
|
|
float x2 = 0;
|
|
float z1 = 0;
|
|
float z2 = 0;
|
|
|
|
|
|
|
|
|
|
//focus fire on the player unit with the least hit points
|
|
for(int i = 0; i < unitInCombatRadius.length; i ++){
|
|
|
|
if(unitInCombatRadius[i] == null || unitInCombatRadius[i].currentHP <=0)
|
|
continue;
|
|
|
|
//micro rocket tanks, so they don't overkill targets,
|
|
if(unitInCombatRadius[i].type == 1) {
|
|
|
|
float myRange= (unitInCombatRadius[i].attackRange) * (unitInCombatRadius[i].attackRange);
|
|
float scanRange = (unitInCombatRadius[i].attackRange + 1.5f) * (unitInCombatRadius[i].attackRange+1.5f);
|
|
|
|
//Prioritize searching for targets among static defenses
|
|
boolean suitableTargertFound = false;
|
|
float distanceToDesination = 999;
|
|
solidObject target = null;
|
|
for(int j = 0; j < playerStaticDefenceInMinimap.length; j++) {
|
|
if(playerStaticDefenceInMinimap[j] != null && !playerStaticDefenceInMinimap[j].willDieFromIncomingAttack()){
|
|
x1 = playerStaticDefenceInMinimap[j].centre.x;
|
|
x2 = unitInCombatRadius[i].centre.x;
|
|
z1 = playerStaticDefenceInMinimap[j].centre.z;
|
|
z2 = unitInCombatRadius[i].centre.z;
|
|
float d = (x1 - x2)*(x1 - x2) + (z1 - z2)*(z1 - z2);
|
|
if(d < scanRange && d < distanceToDesination){
|
|
distanceToDesination = d;
|
|
target = playerStaticDefenceInMinimap[j];
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if(target != null) {
|
|
unitInCombatRadius[i].attack(target);
|
|
|
|
unitInCombatRadius[i].currentCommand = solidObject.attackCautiously;
|
|
unitInCombatRadius[i].secondaryCommand = solidObject.StandBy;
|
|
|
|
suitableTargertFound = true;
|
|
|
|
if(distanceToDesination < myRange) {
|
|
int myDamage = unitInCombatRadius[i].myDamage;
|
|
if(techCenter.rocketTankResearched_enemy) {
|
|
myDamage*=2;
|
|
}
|
|
myDamage = (int)(myDamage*rocketTank.damageAginstBuildingMulitplier);
|
|
|
|
target.incomingDamage+=myDamage*2;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if(suitableTargertFound)
|
|
continue;
|
|
|
|
|
|
//if rocket tank has no target or the target will die from incoming attack, find a new target
|
|
if(unitInCombatRadius[i].targetObject != null && !unitInCombatRadius[i].targetObject.willDieFromIncomingAttack()) {
|
|
|
|
int myDamage = unitInCombatRadius[i].myDamage;
|
|
if(unitInCombatRadius[i].targetObject .type > 100) {
|
|
if(techCenter.rocketTankResearched_enemy) {
|
|
myDamage*=2;
|
|
}
|
|
myDamage = (int)(myDamage*rocketTank.damageAginstBuildingMulitplier);
|
|
}
|
|
|
|
unitInCombatRadius[i].targetObject.incomingDamage+=myDamage*2;
|
|
|
|
}else {
|
|
|
|
//find targets among moving unites
|
|
for(int j=0; j < numberOfPlayerUnitsOnMinimap; j++){
|
|
if(playerUnitInMinimap[j] != null && !playerUnitInMinimap[j].willDieFromIncomingAttack()){
|
|
x1 = playerUnitInMinimap[j].centre.x;
|
|
x2 = unitInCombatRadius[i].centre.x;
|
|
z1 = playerUnitInMinimap[j].centre.z;
|
|
z2 = unitInCombatRadius[i].centre.z;
|
|
distanceToDesination = (x1 - x2)*(x1 - x2) + (z1 - z2)*(z1 - z2);
|
|
|
|
if(distanceToDesination < myRange){
|
|
unitInCombatRadius[i].attack(playerUnitInMinimap[j]);
|
|
playerUnitInMinimap[j].incomingDamage+=unitInCombatRadius[i].myDamage*2;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
|
|
//if(unitInCombatRadius[i].type == 0)
|
|
// unitInCombatRadius[i].groupAttackRange = 1.35f;
|
|
|
|
//if(unitInCombatRadius[i].level > 0)
|
|
// unitInCombatRadius[i].groupAttackRange = unitInCombatRadius[i].attackRange;
|
|
|
|
float myRange= unitInCombatRadius[i].attackRange * unitInCombatRadius[i].attackRange;
|
|
|
|
solidObject target = null;
|
|
solidObject currentTarget = unitInCombatRadius[i].targetObject;
|
|
int targetHP = 99999;
|
|
int level = 0;
|
|
float distanceToDesination = 99999;
|
|
|
|
|
|
for(int j=0; j < numberOfPlayerUnitsOnMinimap; j++){
|
|
if(playerUnitInMinimap[j] != null && playerUnitInMinimap[j].currentHP > 0){
|
|
|
|
if((playerUnitInMinimap[j].getMaxHp() / playerUnitInMinimap[j].currentHP > 4 && !(currentTarget != null && currentTarget.currentHP < playerUnitInMinimap[j].currentHP)) || playerUnitInMinimap[j].level > level){
|
|
x1 = playerUnitInMinimap[j].centre.x;
|
|
x2 = unitInCombatRadius[i].centre.x;
|
|
z1 = playerUnitInMinimap[j].centre.z;
|
|
z2 = unitInCombatRadius[i].centre.z;
|
|
distanceToDesination = (x1 - x2)*(x1 - x2) + (z1 - z2)*(z1 - z2);
|
|
if(distanceToDesination < myRange){
|
|
if(hasLineOfSight(distanceToDesination, x1, x2, z1, z2, playerUnitInMinimap[j])){
|
|
target = playerUnitInMinimap[j];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if(targetHP >= playerUnitInMinimap[j].currentHP || (targetHP == playerUnitInMinimap[j].currentHP && playerUnitInMinimap[j].ID%5 == 0)){
|
|
x1 = playerUnitInMinimap[j].centre.x;
|
|
x2 = unitInCombatRadius[i].centre.x;
|
|
z1 = playerUnitInMinimap[j].centre.z;
|
|
z2 = unitInCombatRadius[i].centre.z;
|
|
distanceToDesination = (x1 - x2)*(x1 - x2) + (z1 - z2)*(z1 - z2);
|
|
if( distanceToDesination < myRange){
|
|
if(hasLineOfSight(distanceToDesination, x1, x2, z1, z2, playerUnitInMinimap[j])){
|
|
target = playerUnitInMinimap[j];
|
|
targetHP = playerUnitInMinimap[j].currentHP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(target !=null ){
|
|
unitInCombatRadius[i].attack(target);
|
|
unitInCombatRadius[i].currentCommand = solidObject.attackCautiously;
|
|
unitInCombatRadius[i].attackStatus = solidObject.isAttacking;
|
|
unitInCombatRadius[i].closeToDestination = true;
|
|
}
|
|
|
|
}
|
|
|
|
//reset incoming damage for all units
|
|
for(int i = 0; i < mainThread.ec.theMapAwarenessAI.mapAsset.length; i++) {
|
|
if(mainThread.ec.theMapAwarenessAI.mapAsset[i] != null)
|
|
mainThread.ec.theMapAwarenessAI.mapAsset[i].incomingDamage = 0;
|
|
}
|
|
|
|
}
|
|
|
|
public boolean hasLineOfSight(float distanceToDesination, float x1, float x2, float z1, float z2, solidObject targetObject){
|
|
boolean hasLineOfSight = true;
|
|
int numberOfIterations = (int)(Math.sqrt(distanceToDesination) * 8);
|
|
float dx = (x1 - x2)/numberOfIterations;
|
|
float dy = (z1 - z2)/numberOfIterations;
|
|
float xStart = x2;
|
|
float yStart = z2;
|
|
|
|
for(int i = 0; i < numberOfIterations; i++){
|
|
xStart+=dx;
|
|
yStart+=dy;
|
|
solidObject s = mainThread.gridMap.tiles[(int)(xStart*4) + (127 - (int)(yStart*4))*128][0];
|
|
if(s != null){
|
|
if(s.type > 100 && s.type < 200 && s != targetObject){
|
|
hasLineOfSight = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hasLineOfSight;
|
|
}
|
|
|
|
}
|