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; } }