JavaRTS/entity/rocketTank.java
Pan 132fa5ebc0 Upgrade the screen resolution of considerably, it gives the user wider
view of the back ground. Also the screen resolution and the shadowmap
resolution are no longer hard coded everywhere. They are defined in
mainThread.java.
2021-08-16 09:33:33 +12:00

1120 lines
35 KiB
Java

package entity;
import java.awt.Rectangle;
import core.*;
import enemyAI.enemyCommander;
//rocket tank 3D model
public class rocketTank extends solidObject{
public vector iDirectionBody, jDirectionBody, kDirectionBody, iDirectionTurret, jDirectionTurret, kDirectionTurret;
public vector bodyCenter, turretCenter, turretCenterClone;
public polygon3D[] body, turret, turretClone;
public static int maxHP = 70;
// a screen space boundary which is used to test if the harvester object is
// visible from camera point of view
public final static Rectangle visibleBoundary = new Rectangle(-70, -25,screen_width+140, screen_height+85);
// a screen space boundary which is used to test if the entire harvester
// object is within the screen
public final static Rectangle screenBoundary = new Rectangle(40, 40, screen_width-90,screen_height-80);
// a screen space boundary which is used to test if the vision polygon of
// the object is visible.
public final static Rectangle visionBoundary = new Rectangle(0, 0, 1400+(screen_width-768),1300+(screen_height-512));
public final static int visionW = 500 + (screen_width-768);
public final static int visionH = 650 + (screen_height-512);
//a bitmap representation of the vision of the tank for enemy commander
public static boolean[] bitmapVisionForEnemy;
public static boolean[] bitmapVisionGainFromAttackingUnit;
//the oreintation of the tank
public int bodyAngle, turretAngle, turretAngleClone;
//the angle that the tank have rotated between current frame and previous frame
public int bodyAngleSum;
//destination angle
public int destinationAngle;
//whether light tank has ling of sight to its target
public boolean hasLineOfSightToTarget;
//attack range
public int attackCoolDown;
public vector firingPosition;
//the offsreen angles/movement are the accumulated changes that the object made during offscreen.
public int bodyAngleDelta_offscreen, turretAngleDelta_offscreen;
public vector movement_offscreen;
//whether the geometry of the object in world coordinate neesd to be updated in the current frame
public boolean geometryNeedModify;
public int bodyTurnRate = 6;
public int turretTurnRate = 8;
public int myAttackCooldown= 200;
//once the tank starts attacking, it exposed itself to the enemy
public int exposedCountDown;
//index of the tiles to check when the tank is idle
public static int[] tileCheckList;
public int damageMultiplier = 1;
public final static float damageAginstBuildingMulitplier = 1.25f;
public rocketTank(vector origin, int bodyAngle, int teamNo){
speed = 0.01f;
attackRange = 2.86f;
groupAttackRange = 2.6f;
start = origin.myClone();
centre = origin.myClone();
tempCentre = origin.myClone();
bodyCenter = origin.myClone();
this.bodyAngle = bodyAngle;
this.immediateDestinationAngle = bodyAngle;
turretAngle = bodyAngle;
turretAngleClone = bodyAngle;
destinationAngle = bodyAngle;
bodyAngleSum = bodyAngle;
this.teamNo = teamNo;
currentHP = maxHP;
type = 1;
myDamage = 27;
if(bitmapVisionForEnemy == null){
bitmapVisionForEnemy = createBitmapVision(6);
bitmapVisionGainFromAttackingUnit = createBitmapVision(2);
}
ID = globalUniqID++;
randomNumber = gameData.getRandom();
height = centre.y + 0.5f; //?
theAssetManager = mainThread.theAssetManager;
boundary2D = new Rect((int)(origin.x*64) - 8, (int)(origin.z*64) + 8, 16, 16);
movement = new vector(0,0,0);
updateOccupiedTiles(boundary2D.x1, boundary2D.y1);
boundary2D.owner = this;
destinationBlock = new Rect((int)(origin.x*64) - 8, (int)(origin.z*64) + 8, 16, 16);
probeBlock = new Rect((int)(origin.x*64) - 6, (int)(origin.z*64) + 6, 12, 12);
firingPosition = new vector(0,-0.1f,0); //??
//create main axis in object space
iDirection = new vector(0.92f,0,0);
jDirection = new vector(0,0.92f,0);
kDirection = new vector(0,0,0.92f);
//create axis for body and turret
iDirectionBody = iDirection.myClone();
jDirectionBody = jDirection.myClone();
kDirectionBody = kDirection.myClone();
iDirectionBody.rotate_XZ(360-bodyAngle);
kDirectionBody.rotate_XZ(360-bodyAngle);
iDirectionBody.scale(0.85f);
jDirectionBody.scale(0.6f);
kDirectionBody.scale(0.95f);
//create axis for turret
iDirectionTurret = iDirection.myClone();
jDirectionTurret = jDirection.myClone();
kDirectionTurret = kDirection.myClone();
jDirectionTurret.rotate_YZ(340);
kDirectionTurret.rotate_YZ(340);
iDirectionTurret.rotate_XZ(360-bodyAngle);
jDirectionTurret.rotate_XZ(360-bodyAngle);
kDirectionTurret.rotate_XZ(360-bodyAngle);
iDirectionTurret.scale(0.9f);
jDirectionTurret.scale(0.75f);
kDirectionTurret.scale(0.95f);
//create polygons
makePolygons();
movement_offscreen = new vector(0,0,0);
if(tileCheckList == null){
tileCheckList = generateTileCheckList(12f); //?
}
}
public void makePolygons(){
start.set(bodyCenter);
start.y-=0.18f;
iDirection.set(iDirectionBody);
jDirection.set(jDirectionBody);
kDirection.set(kDirectionBody);
int skinTextureIndex = 18;
if(teamNo != 0)
skinTextureIndex = 10;
body = new polygon3D[14];
v = new vector[]{put(-0.07, 0.055, 0.07), put(0.07, 0.055, 0.07), put(0.07, 0.055, -0.13), put(-0.07, 0.055, -0.13)};
body[0] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1,1,1);
v = new vector[]{put(-0.069, 0.055, 0.13), put(-0.069, 0.055, -0.13), put(-0.069, 0.02, -0.13), put(-0.069, 0.02, 0.13)};
body[1] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1,0.1f,1);
v = new vector[]{put(0.069, 0.02, 0.13), put(0.069, 0.02, -0.13), put(0.069, 0.055, -0.13), put(0.069, 0.055, 0.13)};
body[2] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1,0.1f,1);
v = new vector[]{put(0.07, 0.1, 0.13), put(-0.07, 0.1, 0.13), put(-0.07, 0.02, 0.13), put(0.07, 0.02, 0.13)};
body[3] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1,0.3f,1);
v = new vector[]{put(0.07, 0.14, 0.11), put(-0.07, 0.14, 0.11), put(-0.07, 0.1, 0.13), put(0.07, 0.1, 0.13)};
body[4] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[21], 1,0.3f,1);
v = new vector[]{put(0.07, 0.14, 0.07), put(0.07, 0.14, 0.11), put(0.07, 0.1, 0.13), put(0.07, 0.055, 0.13), put(0.07, 0.055, 0.07)};
body[5] = new polygon3D(v, v[0], v[1], v[4], mainThread.textures[skinTextureIndex], 0.4f,0.3f,1);
v = new vector[]{put(-0.07, 0.055, 0.07), put(-0.07, 0.055, 0.13), put(-0.07, 0.1, 0.13),put(-0.07, 0.14, 0.11), put(-0.07, 0.14, 0.07), };
body[6] = new polygon3D(v, v[0], v[1], v[4], mainThread.textures[skinTextureIndex], 0.4f,0.3f,1);
v = new vector[]{put(-0.07, 0.14, 0.11), put(0.07, 0.14, 0.11), put(0.07, 0.14, 0.07), put(-0.07, 0.14, 0.07)};
body[7] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1,0.3f,1);
v = new vector[]{put(-0.07, 0.14, 0.07), put(0.07, 0.14, 0.07), put(0.07, 0.055, 0.07), put(-0.07, 0.055, 0.07)};
body[8] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1,0.3f,1);
v = new vector[]{put(-0.07, 0.055, -0.13), put(0.07, 0.055, -0.13), put(0.07, 0.02, -0.13), put(-0.07, 0.02, -0.13)};
body[9] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1,0.3f,1);
v = new vector[]{put(-0.068, 0.021, 0.13), put(-0.068, 0.021, -0.13), put(-0.068, -0.03, -0.11), put(-0.068, -0.03, 0.11)};
body[10] = new polygon3D(v, put(-0.068, 0.021, 0.13), put(-0.068, 0.021, -0.13), put(-0.068, -0.03, 0.13), mainThread.textures[3], 1,1,1);
v = new vector[]{put(0.068, -0.03, 0.11), put(0.068, -0.03, -0.11), put(0.068, 0.021, -0.13), put(0.068, 0.021, 0.13)};
body[11] = new polygon3D(v, put(0.068, 0.021, -0.13), put(0.068, 0.021, 0.13), put(0.068, -0.03, -0.13), mainThread.textures[3], 1,1,1);
v = new vector[]{put(0.068, 0.021, 0.13), put(0.04, 0.021, 0.13), put(0.04, -0.03, 0.11), put(0.068, -0.03, 0.11)};
body[12] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[3], 1,1,1);
v = new vector[]{put(-0.04, 0.021, 0.13), put(-0.068, 0.021, 0.13), put(-0.068, -0.03, 0.11), put(-0.04, -0.03, 0.11)};
body[13] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[3], 1,1,1);
turretCenter = put(0, 0.08, -0.05);
start.set(turretCenter);
iDirection.set(iDirectionTurret);
jDirection.set(jDirectionTurret);
kDirection.set(kDirectionTurret);
turret = new polygon3D[5];
v = new vector[]{put(-0.06, 0.065, 0.09), put(0.06, 0.065, 0.09), put(0.06, 0.065, -0.08), put(-0.06, 0.065, -0.08)};
turret[0] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1,1,1);
v = new vector[]{put(-0.06, 0.065, 0.09), put(-0.06, 0.065, -0.08), put(-0.06, 0.01, -0.08), put(-0.06, 0.01, 0.09)};
turret[1] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1,0.3f,1);
v = new vector[]{put(0.06, 0.01, 0.09), put(0.06, 0.01, -0.08), put(0.06, 0.065, -0.08), put(0.06, 0.065, 0.09)};
turret[2] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1,0.3f,1);
v = new vector[]{put(0.06, 0.065, 0.09), put(-0.06, 0.065, 0.09), put(-0.06, 0.01, 0.09), put(0.06, 0.01, 0.09)};
turret[3] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[22], 1,0.5f,1);
turret[3].shadowBias = 80000;
v = new vector[]{put(0.06, 0.01, -0.08), put(-0.06, 0.01, -0.08), put(-0.06, 0.065, -0.08) , put(0.06, 0.065, -0.08)};
turret[4] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1,0.5f,1);
turretCenterClone = turretCenter.myClone();
turretClone = new polygon3D[5];
v = new vector[]{put(-0.06, 0.065, 0.09), put(0.06, 0.065, 0.09), put(0.06, 0.065, -0.08), put(-0.06, 0.065, -0.08)};
turretClone[0] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1,1,1);
v = new vector[]{put(-0.06, 0.065, 0.09), put(-0.06, 0.065, -0.08), put(-0.06, 0.01, -0.08), put(-0.06, 0.01, 0.09)};
turretClone[1] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1,0.3f,1);
v = new vector[]{put(0.06, 0.01, 0.09), put(0.06, 0.01, -0.08), put(0.06, 0.065, -0.08), put(0.06, 0.065, 0.09)};
turretClone[2] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1,0.3f,1);
v = new vector[]{put(0.06, 0.065, 0.09), put(-0.06, 0.065, 0.09), put(-0.06, 0.01, 0.09), put(0.06, 0.01, 0.09)};
turretClone[3] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[22], 1,0.5f,1);
v = new vector[]{put(0.06, 0.01, -0.08), put(-0.06, 0.01, -0.08), put(-0.06, 0.065, -0.08) , put(0.06, 0.065, -0.08)};
turretClone[4] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1,0.5f,1);
}
//update and draw model
public void update(){
//check if tank has been destroyed
if(currentHP <= 0){
//spawn an explosion when the tank is destroyed
float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount];
tempFloat[0] = centre.x;
tempFloat[1] = centre.y - 0.05f;
tempFloat[2] = centre.z;
tempFloat[3] = 2.5f;
tempFloat[4] = 1;
tempFloat[5] = 0;
tempFloat[6] = 7;
tempFloat[7] = this.height;
theAssetManager.explosionCount++;
theAssetManager.removeObject(this);
removeFromGridMap();
if(attacker.teamNo != teamNo)
attacker.experience+=15;
return;
}
if(experience >= 50){
myDamage = 33;
level = 1;
if(experience >= 100){
level = 2;
myDamage = 44;
if(currentHP < maxHP && mainThread.gameFrame%16==0)
currentHP++;
}
}
//carry out commands given by the player or AI
if(!disableUnitLevelAI)
carryOutCommands();
if(attackCoolDown > 0)
attackCoolDown--;
if(exposedCountDown > 0)
exposedCountDown --;
if(tightSpaceManeuverCountDown > 0)
tightSpaceManeuverCountDown--;
if(underAttackCountDown > 0)
underAttackCountDown--;
//find out if the geometry of the object need to be modified
geometryNeedModify = true;
if(movement.x == 0 && movement.z == 0){
if(turretAngleDelta == 0 && bodyAngleDelta == 0){
geometryNeedModify = false;
}
if(occupiedTile0 != -1)
mainThread.gridMap.currentObstacleMap[occupiedTile0] = false;
if(occupiedTile1 != -1)
mainThread.gridMap.currentObstacleMap[occupiedTile1] = false;
if(occupiedTile2 != -1)
mainThread.gridMap.currentObstacleMap[occupiedTile2] = false;
if(occupiedTile3 != -1)
mainThread.gridMap.currentObstacleMap[occupiedTile3] = false;
}else{
//update centre
if (Math.abs(movement.x) + Math.abs(movement.z) < 0.25f) {
centre.add(movement);
boundary2D.setOrigin((int)(centre.x*64) - 8, (int)(centre.z*64) + 8);
updateOccupiedTiles(boundary2D.x1, boundary2D.y1);
}else{
movement.reset();
if(occupiedTile0 != -1)
mainThread.gridMap.currentObstacleMap[occupiedTile0] = false;
if(occupiedTile1 != -1)
mainThread.gridMap.currentObstacleMap[occupiedTile1] = false;
if(occupiedTile2 != -1)
mainThread.gridMap.currentObstacleMap[occupiedTile2] = false;
if(occupiedTile3 != -1)
mainThread.gridMap.currentObstacleMap[occupiedTile3] = false;
}
}
//update center in camera coordinate
tempCentre.set(centre);
tempCentre.y -= 0.2f;
tempCentre.subtract(camera.position);
tempCentre.rotate_XZ(camera.XZ_angle);
tempCentre.rotate_YZ(camera.YZ_angle);
tempCentre.updateLocation();
visionBoundary.x = (int) (tempCentre.screenX - visionW);
visionBoundary.y = (int) (tempCentre.screenY - visionH);
visionInsideScreen = camera.screen.intersects(visionBoundary);
if(attackStatus == isAttacking && targetObject != null && targetObject.teamNo != teamNo)
exposedCountDown = 64;
//create vision for enemy commander
if(teamNo == 1){
xPos = boundary2D.x1/16 - 6 + 10;
yPos = 127 - boundary2D.y1/16 - 6 + 10;
for(int y = 0; y < 13; y++){
for(int x = 0; x < 13; x++){
if(bitmapVisionForEnemy[x+ y*13])
enemyCommander.tempBitmap[xPos + x + (yPos+y)*148] =true;
}
}
}else if(exposedCountDown > 0){
xPos = boundary2D.x1/16 - 2 + 10;
yPos = 127 - boundary2D.y1/16 - 2 + 10;
for(int y = 0; y < 5; y++){
for(int x = 0; x < 5; x++){
if(bitmapVisionGainFromAttackingUnit[x+ y*5])
enemyCommander.tempBitmap[xPos + x + (yPos+y)*148] =true;
}
}
}
if(visionInsideScreen){
if(teamNo != 0){
if(attackStatus == isAttacking || exposedCountDown > 0){
tempFloat = theAssetManager.visionPolygonInfo[theAssetManager.visionPolygonCount];
tempFloat[0] = teamNo;
tempFloat[1] = centre.x;
tempFloat[2] = -0.4f;
tempFloat[3] = centre.z;
tempFloat[4] = 1;
theAssetManager.visionPolygonCount++;
}
}else{
tempFloat = theAssetManager.visionPolygonInfo[theAssetManager.visionPolygonCount];
tempFloat[0] = teamNo;
tempFloat[1] = centre.x;
tempFloat[2] = -0.4f;
tempFloat[3] = centre.z;
tempFloat[4] = 0;
theAssetManager.visionPolygonCount++;
}
}
//check if the tank object is visible in mini map
visible_minimap = theAssetManager.minimapBitmap[boundary2D.x1/16 + (127 - (boundary2D.y1-1)/16)*128];
if(teamNo == 0 || attackStatus == isAttacking || exposedCountDown > 0 || visible_minimap){
tempInt = theAssetManager.unitsForMiniMap[theAssetManager.unitsForMiniMapCount];
tempInt[0] = teamNo;
tempInt[1] = boundary2D.x1/16;
tempInt[2] = 127 - boundary2D.y1/16;
tempInt[3] = 0;
if(teamNo == 0 && underAttackCountDown > 0)
tempInt[4] = 10001;
else
tempInt[4] = exposedCountDown;
theAssetManager.unitsForMiniMapCount++;
}
//test if the tank object is visible in camera point of view
if(visible_minimap){
if(currentHP <= maxHP/2 && (mainThread.gameFrame + ID) % 3 ==0){
//spawn smoke particle if the tank is badly damaged
float[] tempFloat = theAssetManager.smokeEmmiterList[theAssetManager.smokeEmmiterCount];
tempFloat[0] = centre.x + (float)(Math.random()/20) - 0.025f;
tempFloat[1] = centre.y - 0.06f;
tempFloat[2] = centre.z + (float)(Math.random()/20) - 0.025f;
tempFloat[3] = 0.7f;
tempFloat[4] = 1;
tempFloat[5] = 11;
tempFloat[6] = this.height;
theAssetManager.smokeEmmiterCount++;
}
if(visibleBoundary.contains(tempCentre.screenX, tempCentre.screenY)){
visible = true;
if(screenBoundary.contains(tempCentre.screenX, tempCentre.screenY))
withinViewScreen = true;
else
withinViewScreen = false;
}else{
visible = false;
}
}else{
mainThread.pc.deSelect(this);
visible = false;
}
if(visible){
if(movement_offscreen.x != 0 || movement_offscreen.z!= 0 || turretAngleDelta_offscreen != 0 || bodyAngleDelta_offscreen != 0){
geometryNeedModify = true;
}
if(geometryNeedModify){
movement.add(movement_offscreen);
turretAngleDelta= (turretAngleDelta +turretAngleDelta_offscreen)%360;
turretAngleDelta_offscreen = 0;
bodyAngleDelta = (bodyAngleDelta + bodyAngleDelta_offscreen)%360;
bodyAngleDelta_offscreen = 0;
updateGeometry();
bodyAngleDelta = 0;
turretAngleDelta = 0;
movement.subtract(movement_offscreen);
movement_offscreen.set(0,0,0);
}
//if the tank object is visible then draw it on the shadow buffer from light point of view
for(int i = 0; i < turret.length; i++){
turret[i].update_lightspace();
}
for(int i = 0; i < body.length; i++){
body[i].update_lightspace();
}
theAssetManager.visibleUnit[theAssetManager.visibleUnitCount] = this;
theAssetManager.visibleUnitCount++;
}else if(geometryNeedModify){
movement_offscreen.add(movement);
turretAngleDelta_offscreen += turretAngleDelta;
turretAngleDelta_offscreen = (turretAngleDelta_offscreen + 360)%360;
bodyAngleDelta_offscreen += bodyAngleDelta;
bodyAngleDelta_offscreen = (bodyAngleDelta_offscreen + 360)%360;
}
}
public void updateGeometry(){
//correct body angle if the visual body angle differs from the logical one
bodyAngleSum = (360 + bodyAngleSum - bodyAngleDelta)%360;
int angle = bodyAngleDelta;
if(bodyAngleSum != bodyAngle){
angle = (360 + bodyAngleDelta - (360 + bodyAngle - bodyAngleSum) % 360)%360;
bodyAngleSum = bodyAngle;
}
//update body polygons
for(int i = 0; i < body.length; i++){
if(body[i].textureFitPolygon == false){
//perform vertex updates in world coordinate
body[i].origin.add(movement);
body[i].origin.subtract(centre);
body[i].origin.rotate_XZ(angle);
body[i].origin.add(centre);
body[i].bottomEnd.add(movement);
body[i].bottomEnd.subtract(centre);
body[i].bottomEnd.rotate_XZ(angle);
body[i].bottomEnd.add(centre);
body[i].rightEnd.add(movement);
body[i].rightEnd.subtract(centre);
body[i].rightEnd.rotate_XZ(angle);
body[i].rightEnd.add(centre);
}
for(int j = 0; j < body[i].vertex3D.length; j++){
body[i].vertex3D[j].add(movement);
body[i].vertex3D[j].subtract(centre);
body[i].vertex3D[j].rotate_XZ(angle);
body[i].vertex3D[j].add(centre);
}
body[i].normal.rotate_XZ(angle);
body[i].findDiffuse();
}
//update turret center
turretCenter.add(movement);
turretCenter.subtract(centre);
turretCenter.rotate_XZ(angle);
turretCenter.add(centre);
tempVector.set(turretCenter);
tempVector.subtract(turretCenterClone);
//update turret polygons
for(int i = 0; i < turret.length; i++){
if(turret[i].textureFitPolygon == false){
//perform vertex updates in world coordinate
turret[i].origin.set(turretClone[i].origin);
turret[i].origin.subtract(turretCenterClone);
turret[i].origin.rotate_XZ(turretAngleClone);
turret[i].origin.rotate_XZ(360-turretAngle);
turret[i].origin.add(turretCenter);
turret[i].bottomEnd.set(turretClone[i].bottomEnd);
turret[i].bottomEnd.subtract(turretCenterClone);
turret[i].bottomEnd.rotate_XZ(turretAngleClone);
turret[i].bottomEnd.rotate_XZ(360-turretAngle);
turret[i].bottomEnd.add(turretCenter);
turret[i].rightEnd.set(turretClone[i].rightEnd);
turret[i].rightEnd.subtract(turretCenterClone);
turret[i].rightEnd.rotate_XZ(turretAngleClone);
turret[i].rightEnd.rotate_XZ(360-turretAngle);
turret[i].rightEnd.add(turretCenter);
}
for(int j = 0; j < turret[i].vertex3D.length; j++){
turret[i].vertex3D[j].set(turretClone[i].vertex3D[j]);
turret[i].vertex3D[j].subtract(turretCenterClone);
turret[i].vertex3D[j].rotate_XZ(turretAngleClone);
turret[i].vertex3D[j].rotate_XZ(360-turretAngle);
turret[i].vertex3D[j].add(turretCenter);
}
turret[i].normal.set(turretClone[i].normal);
turret[i].normal.rotate_XZ(turretAngleClone);
turret[i].normal.rotate_XZ(360-turretAngle);
turret[i].findDiffuse();
}
}
//carry out commands given by player or AI commander
public void carryOutCommands(){
if(currentCommand == StandBy){
resetLogicStatus();
performStandByLogic();
}else if(currentCommand == move){
performMovementLogic();
avoidGettingStucked();
}else if(currentCommand == attackInNumbers || currentCommand == attackCautiously){
performAttackLogic();
avoidGettingStucked();
}else if(currentCommand == follow){
}else if(currentCommand == attackMove){
performAttackMoveLogic();
avoidGettingStucked();
}
}
//the tank will attack with any hostile unit that moved into its firing range
public void performStandByLogic(){
//scan for hostile unit
boolean[] bitmapVision;
if(teamNo == 0)
bitmapVision = theAssetManager.minimapBitmap;
else
bitmapVision = enemyCommander.visionMap;
if((ID + mainThread.gameFrame)%32 == 0){
currentOccupiedTile = (int)(centre.x*64)/16 + (127 - (int)(centre.z*64)/16)*128;
for(int i = 0; i < tileCheckList.length; i++){
if(tileCheckList[i] != Integer.MAX_VALUE){
int index = currentOccupiedTile + tileCheckList[i];
if(index < 0 || index >= 16384 || Math.abs(index%128 - currentOccupiedTile%128) > 20)
continue;
tile = mainThread.gridMap.tiles[index];
if(!bitmapVision[index]){
boolean isRevealedBuilding = false;
if(tile[4] != null)
if(tile[4].type > 100 && tile[4].ID != -1)
if((tile[4].isRevealed == true && teamNo == 0) || (mainThread.ec.theMapAwarenessAI.mapAsset[tile[4].ID] != null && teamNo != 0) )
isRevealedBuilding = true;
if(!isRevealedBuilding)
continue;
}
for(int j = 0; j < 4; j++){
if(tile[j] != null){
if(tile[j].teamNo != teamNo && tile[j].teamNo != -1 && tile[j].currentHP > 0 && !tile[j].isCloaked){
attack(tile[j]);
currentCommand = solidObject.attackCautiously;
secondaryCommand = solidObject.StandBy;
/*
attackMoveTo((tile[j].centre.x + centre.x)/2, (tile[j].centre.z+centre.z)/2);
currentCommand = solidObject.attackMove;
secondaryCommand = solidObject.attackMove;
*/
return;
}
}
}
}
}
}
}
//attack a single unit, ignore any hostile units it encounters
public void performAttackLogic(){
if(targetObject == null)
return;
destinationX = targetObject.getRealCentre().x;
destinationY = targetObject.getRealCentre().z;
//clear things a bit
unStableObstacle = null;
distanceToDesination = (float)Math.sqrt((destinationX - centre.x) * (destinationX - centre.x) + (destinationY - centre.z) * (destinationY - centre.z));
if(currentMovementStatus != hugRight && currentMovementStatus != hugLeft){
calculateMovement();
destinationAngle = geometry.findAngle(centre.x, centre.z, destinationX, destinationY);
immediateDestinationAngle = destinationAngle;
}
if((currentCommand == attackInNumbers && distanceToDesination <= groupAttackRange) || (currentCommand == attackCautiously && distanceToDesination < attackRange)){
movement.reset();
currentMovementStatus = freeToMove;
obstacle = null;
}
if(distanceToDesination <= attackRange){
attackStatus = isAttacking;
}else{
attackStatus = notInRange;
if(secondaryCommand == attackMove){
resetLogicStatus();
destinationX = secondaryDestinationX;
destinationY = secondaryDestinationY;
currentCommand = attackMove;
newDestinationisGiven = true;
return;
}
}
if(attackStatus == isAttacking){
int attackAngle = geometry.findAngle(centre.x, centre.z, destinationX, destinationY);
if(turretAngle != attackAngle){
turretAngleDelta = 360 - (geometry.findAngleDelta(turretAngle, attackAngle, turretTurnRate) + 360)%360;
turretAngle= (turretAngle - turretAngleDelta + 360)%360;
if(Math.abs(turretAngle - attackAngle) < 10)
fireRocket(attackAngle);
}else{
fireRocket(attackAngle);
turretAngleDelta = 0;
}
}else{
if(turretAngle != immediateDestinationAngle){
turretAngleDelta = 360 - (geometry.findAngleDelta(turretAngle, immediateDestinationAngle, turretTurnRate) + 360)%360;
turretAngle= (turretAngle - turretAngleDelta + 360)%360;
}else{
turretAngleDelta = 0;
}
}
if(Math.abs(bodyAngle - immediateDestinationAngle) > 45 && Math.abs(bodyAngle - immediateDestinationAngle) < 315){
if(!(distanceToDesination < attackRange && movement.x ==0 && movement.z ==0)){
bodyAngleDelta = 360 - (geometry.findAngleDelta(bodyAngle, immediateDestinationAngle, bodyTurnRate) + 360)%360;
bodyAngle= (bodyAngle - bodyAngleDelta + 360)%360;
movement.reset();
}else{
bodyAngleDelta = 0;
}
}else{
if(bodyAngle != immediateDestinationAngle){
if(!(distanceToDesination < attackRange && movement.x ==0 && movement.z ==0)){
bodyAngleDelta = 360 - (geometry.findAngleDelta(bodyAngle, immediateDestinationAngle, bodyTurnRate) + 360)%360;
bodyAngle= (bodyAngle - bodyAngleDelta + 360)%360;
}
}else{
bodyAngleDelta = 0;
}
if(currentMovementStatus == hugRight || currentMovementStatus == hugLeft){
hugWalls();
if(distanceToDesination <= attackRange){
attackStatus = isAttacking;
if(currentCommand == attackInNumbers && distanceToDesination > groupAttackRange){
if(movement.x != 0 || movement.z !=0){
if(Math.sqrt((destinationX - centre.x - movement.x) * (destinationX - centre.x - movement.x) + (destinationY - centre.z - movement.z) * (destinationY - centre.z - movement.z)) > attackRange){
currentMovementStatus = freeToMove;
movement.reset();
currentCommand = attackCautiously;
}
}
}else{
movement.reset();
currentMovementStatus = freeToMove;
}
}
return;
}
if(movement.x == 0 && movement.z == 0)
calculateMovement();
if(distanceToDesination <= attackRange){
attackStatus = isAttacking;
if(currentCommand == attackInNumbers && distanceToDesination > groupAttackRange){
currentMovementStatus = validateMovement();
if(currentMovementStatus == freeToMove){
distanceToDesination -= speed;
}else{
hugWalls();
if(movement.x != 0 || movement.z !=0){
if(Math.sqrt((destinationX - centre.x - movement.x) * (destinationX - centre.x - movement.x) + (destinationY - centre.z - movement.z) * (destinationY - centre.z - movement.z)) > attackRange){
currentMovementStatus = freeToMove;
movement.reset();
currentCommand = attackCautiously;
}
}
}
}else{
currentMovementStatus = freeToMove;
movement.reset();
}
}else {
//validate movement
currentMovementStatus = validateMovement();
if(currentMovementStatus == freeToMove){
distanceToDesination -= speed;
}else{
movement.reset();
}
}
}
if(targetObject.currentHP <=0 || (targetObject.isCloaked && teamNo != targetObject.teamNo)){
currentCommand = StandBy;
targetObject = null;
if(secondaryCommand == attackMove){
destinationX = secondaryDestinationX;
destinationY = secondaryDestinationY;
currentCommand = attackMove;
newDestinationisGiven = true;
}
return;
}
}
//move to a destination position, engage with any hostile units (moving units first, then buildings) in its path
public void performAttackMoveLogic(){
currentOccupiedTile = (int)(centre.x*64)/16 + (127 - (int)(centre.z*64)/16)*128;
boolean[] bitmapVision;
if(teamNo == 0)
bitmapVision = theAssetManager.minimapBitmap;
else
bitmapVision = enemyCommander.visionMap;
solidObject target = null;
for(int i = 0; i < tileCheckList.length; i++){
if(tileCheckList[i] != Integer.MAX_VALUE){
int index = currentOccupiedTile + tileCheckList[i];
if(index < 0 || index >= 16384 || Math.abs(index%128 - currentOccupiedTile%128) > 20)
continue;
tile = mainThread.gridMap.tiles[index];
//ignore unrevealed buildings
if(!bitmapVision[index]){
boolean isRevealedBuilding = false;
if(tile[4] != null)
if(tile[4].type > 100 && tile[4].ID != -1)
if((tile[4].isRevealed == true && teamNo == 0) || (mainThread.ec.theMapAwarenessAI.mapAsset[tile[4].ID] != null && teamNo != 0))
isRevealedBuilding = true;
if(!isRevealedBuilding)
continue;
}
//target hostile static defense first, then hostile units, and finally hostile buildings
for(int j = 0; j < 4; j++){
if(tile[j] != null){
if(tile[j].teamNo != teamNo && tile[j].teamNo != -1 && tile[j].currentHP > 0 && !tile[j].isCloaked){
distanceToDesination = (float)Math.sqrt((tile[j].centre.x - centre.x) * (tile[j].centre.x - centre.x) + (tile[j].centre.z - centre.z) * (tile[j].centre.z - centre.z));
if(distanceToDesination <= attackRange){
if((tile[j].type == 199 || tile[j].type == 200) && (tile[j].visible_minimap || (teamNo !=0 && tile[j].isRevealed_AI) )){
attack(tile[j]);
currentCommand = solidObject.attackInNumbers;
return;
}else{
if(target == null){
target = tile[j];
}else if(target.type >= 100 && tile[j].type < 100){
target = tile[j];
}
}
}
}
}
}
}
}
if(target != null && (target.visible_minimap || teamNo != 0)){
attack(target);
currentCommand = solidObject.attackInNumbers;
return;
}
performMovementLogic();
}
//move to a destination position, ignore any hostile units it encounters
public void performMovementLogic(){
attackStatus = solidObject.noTarget;
//clear things a bit
unStableObstacle = null;
if(newDestinationisGiven){
newDestinationisGiven = false;
distanceToDesination = (float)Math.sqrt((destinationX - centre.x) * (destinationX - centre.x) + (destinationY - centre.z) * (destinationY - centre.z));
calculateMovement();
destinationAngle = geometry.findAngle(centre.x, centre.z, destinationX, destinationY);
immediateDestinationAngle = destinationAngle;
//currentMovementStatus = validateMovement();
}
if(turretAngle != immediateDestinationAngle){
turretAngleDelta = 360 - (geometry.findAngleDelta(turretAngle, immediateDestinationAngle, turretTurnRate) + 360)%360;
turretAngle= (turretAngle - turretAngleDelta + 360)%360;
}else{
turretAngleDelta = 0;
}
if(Math.abs(bodyAngle - immediateDestinationAngle) > 45 && Math.abs(bodyAngle - immediateDestinationAngle) < 315){
bodyAngleDelta = 360 - (geometry.findAngleDelta(bodyAngle, immediateDestinationAngle, bodyTurnRate) + 360)%360;
bodyAngle= (bodyAngle - bodyAngleDelta + 360)%360;
movement.reset();
}else{
if(bodyAngle != immediateDestinationAngle){
bodyAngleDelta = 360 - (geometry.findAngleDelta(bodyAngle, immediateDestinationAngle, bodyTurnRate) + 360)%360;
bodyAngle= (bodyAngle - bodyAngleDelta + 360)%360;
}else{
bodyAngleDelta = 0;
}
if(currentMovementStatus == hugRight || currentMovementStatus == hugLeft){
if(checkIfDestinationReached() == true){
movement.reset();
currentCommand = StandBy;
secondaryCommand = StandBy;
return;
}
hugWalls();
return;
}
if(movement.x == 0 && movement.z == 0)
calculateMovement();
if(distanceToDesination - speed <= 0){
movement.scale(speed - distanceToDesination);
//validate movement
currentMovementStatus = validateMovement();
if(currentMovementStatus == freeToMove){
resetLogicStatus();
currentCommand = StandBy;
secondaryCommand = StandBy;
}else{
movement.reset();
}
}else {
//validate movement
currentMovementStatus = validateMovement();
if(currentMovementStatus == freeToMove){
distanceToDesination -= speed;
}else{
movement.reset();
}
}
}
}
public void calculateMovement_unit(){
movement.set(destinationX - centre.x, 0, destinationY - centre.z);
movement.unit();
}
public void fireRocket(int attackAngle){
if(visible)
tempVector.set(turretCenter);
else{
tempVector.set(centre);
}
float multiplier = 1;
if(targetObject.type > 100){
multiplier = damageMultiplier;
multiplier*=damageAginstBuildingMulitplier;
}else if(targetObject.type == 6) {
multiplier = 0.7f;
}
if(attackCoolDown == 0 && targetObject.currentHP >0 ){
firingPosition.set(-0.03f, -0.3f, 0.12f);
firingPosition.rotate_XZ(360 - attackAngle);
firingPosition.add(tempVector.x, 0, tempVector.z);
theAssetManager.spawnRocket(attackAngle, (int)(myDamage*multiplier), targetObject, firingPosition, this);
attackCoolDown = myAttackCooldown;
//spawn a mini explosion
firingPosition.set(-0.03f, -0.35f, 0.08f);
firingPosition.rotate_XZ(360 - attackAngle);
firingPosition.add(tempVector.x, 0, tempVector.z);
float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount];
tempFloat[0] = firingPosition.x;
tempFloat[1] = firingPosition.y;
tempFloat[2] = firingPosition.z;
tempFloat[3] = 0.5f;
tempFloat[4] = 2;
tempFloat[5] = 0;
tempFloat[6] = 6 + (gameData.getRandom()%4);
tempFloat[7] = centre.y;
theAssetManager.explosionCount++;
}
if(attackCoolDown == myAttackCooldown - 10 && targetObject.currentHP >0 ){
firingPosition.set(0.03f, -0.3f, 0.12f);
firingPosition.rotate_XZ(360 - attackAngle);
firingPosition.add(tempVector.x, 0, tempVector.z);
theAssetManager.spawnRocket(attackAngle, (int)(myDamage*multiplier), targetObject, firingPosition, this);
//spawn a mini explosion
firingPosition.set(0.03f, -0.35f, 0.08f);
firingPosition.rotate_XZ(360 - attackAngle);
firingPosition.add(tempVector.x, 0, tempVector.z);
float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount];
tempFloat[0] = firingPosition.x;
tempFloat[1] = firingPosition.y;
tempFloat[2] = firingPosition.z;
tempFloat[3] = 0.5f;
tempFloat[4] = 2;
tempFloat[5] = 0;
tempFloat[6] = 6 + (gameData.getRandom()%4);
tempFloat[7] = centre.y;
theAssetManager.explosionCount++;
}
}
public void draw(){
if(!visible)
return;
for(int i = 0; i < turret.length; i++){
turret[i].update();
turret[i].draw();
}
for(int i = 0; i < body.length; i++){
body[i].update();
body[i].draw();
}
}
public int getMaxHp(){return maxHP;}
}