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.
1370 lines
47 KiB
Java
1370 lines
47 KiB
Java
package entity;
|
|
|
|
import java.awt.Rectangle;
|
|
|
|
import core.*;
|
|
import enemyAI.enemyCommander;
|
|
|
|
public class stealthTank extends solidObject{
|
|
|
|
public vector iDirectionBody, jDirectionBody, kDirectionBody, iDirectionTurret, jDirectionTurret, kDirectionTurret;
|
|
|
|
public vector bodyCenter, turretCenter;
|
|
|
|
public polygon3D[] body, turret;
|
|
|
|
public static int maxHP = 80;
|
|
|
|
//a screen space boundary which is used to test if the tank 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 tank 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,1000, 1500);
|
|
|
|
//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;
|
|
|
|
//the angle that the tank have rotated between current frame and previous frame
|
|
public int bodyAngleSum;
|
|
|
|
//destination angle
|
|
public int destinationAngle;
|
|
|
|
//whether the 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 = 10;
|
|
public int turretTurnRate = 12;
|
|
public int myAttackCooldown= 75;
|
|
|
|
//once the tank starts attacking, it exposed itself to the enemy
|
|
public int exposedCountDown;
|
|
|
|
//the time left for stealth tank to become invisible again
|
|
//public int stealthCountDown;
|
|
|
|
//index of the tiles to check when the tank is idle
|
|
public static int[] tileCheckList;
|
|
|
|
public static int[] tiles3x3 = new int[]{-129, -128, -127, -1, 0, 1, 127, 128, 129};
|
|
|
|
//public boolean wasCloaked;
|
|
public int targetCloakingStatus, currentCloakingStatus, currentShadowStatus;
|
|
|
|
public boolean hasMultiShotUpgrade;
|
|
public static solidObject[] secondaryTargets;
|
|
public static int[] secondaryAttackCheckList;
|
|
|
|
public stealthTank(vector origin, int bodyAngle, int teamNo){
|
|
speed = 0.015f;
|
|
attackRange = 1.91f;
|
|
groupAttackRange = 1.2f;
|
|
myDamage = 30;
|
|
start = origin.myClone();
|
|
centre = origin.myClone();
|
|
tempCentre = origin.myClone();
|
|
bodyCenter = origin.myClone();
|
|
this.bodyAngle = bodyAngle;
|
|
turretAngle = bodyAngle;
|
|
destinationAngle = bodyAngle;
|
|
this.immediateDestinationAngle = bodyAngle;
|
|
bodyAngleSum = bodyAngle;
|
|
this.teamNo = teamNo;
|
|
currentHP = maxHP;
|
|
type = 6;
|
|
cloakCooldownCount = 120;
|
|
|
|
if(bitmapVisionForEnemy == null){
|
|
bitmapVisionForEnemy = createBitmapVision(8);
|
|
bitmapVisionGainFromAttackingUnit = createBitmapVision(2);
|
|
}
|
|
|
|
if(secondaryTargets == null){
|
|
secondaryTargets = new solidObject[3];
|
|
}
|
|
|
|
ID = globalUniqID++;
|
|
randomNumber = gameData.getRandom();
|
|
height = centre.y + 0.2f;
|
|
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(1,0,0);
|
|
jDirection = new vector(0,1,0);
|
|
kDirection = new vector(0,0,1);
|
|
|
|
iDirection.rotate_XZ(360-bodyAngle);
|
|
kDirection.rotate_XZ(360-bodyAngle);
|
|
|
|
//create axis for body and turret
|
|
iDirectionBody = iDirection.myClone();
|
|
jDirectionBody = jDirection.myClone();
|
|
kDirectionBody = kDirection.myClone();
|
|
|
|
iDirectionTurret = iDirection.myClone();
|
|
jDirectionTurret = jDirection.myClone();
|
|
kDirectionTurret = kDirection.myClone();
|
|
|
|
//create polygons
|
|
makePolygons();
|
|
|
|
movement_offscreen = new vector(0,0,0);
|
|
|
|
if(tileCheckList == null){
|
|
tileCheckList = generateTileCheckList(6f);
|
|
secondaryAttackCheckList = generateTileCheckList(4);
|
|
|
|
//shaffule secondaryAttackCheckList
|
|
for(int i = 0; i < 100; i++){
|
|
int temp = (gameData.getRandom() * secondaryAttackCheckList.length) >> 10;
|
|
int temp1 = (gameData.getRandom() * secondaryAttackCheckList.length) >> 10;
|
|
|
|
int a = secondaryAttackCheckList[temp];
|
|
secondaryAttackCheckList[temp] = secondaryAttackCheckList[temp1];
|
|
secondaryAttackCheckList[temp1] = a;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
public void makePolygons(){
|
|
bodyCenter.y-=0.18f;
|
|
start.set(bodyCenter);
|
|
|
|
body = new polygon3D[43];
|
|
|
|
int skinTextureIndex = 23;
|
|
if(teamNo != 0)
|
|
skinTextureIndex = 10;
|
|
|
|
v = new vector[]{put(-0.04, 0.03, 0.07), put(-0.04, 0.055, 0.04), put(-0.04, 0.055, -0.05), put(-0.04, 0.03, -0.07), put(-0.04, 0, -0.07), put(-0.04, 0, 0.07)};
|
|
body[0] = new polygon3D(v, put(-0.04, 0.055, 0.07), put(-0.04, 0.055, -0.07), put(-0.04, 0.01, 0.07), mainThread.textures[skinTextureIndex], 1,0.2f,9);
|
|
|
|
v = new vector[]{put(0.04, 0, 0.07), put(0.04, 0, -0.07), put(0.04, 0.03, -0.07), put(0.04, 0.055, -0.05), put(0.04, 0.055, 0.04), put(0.04, 0.03, 0.07)};
|
|
body[1] = new polygon3D(v, put(0.04, 0.055, 0.07), put(0.04, 0.055, -0.07), put(0.04, 0.01, 0.07), mainThread.textures[skinTextureIndex], 1,0.2f,9);
|
|
|
|
v = new vector[]{put(-0.04, 0.03, 0.07), put(0.04, 0.03, 0.07), put(0.04, 0.055, 0.04), put(-0.04, 0.055, 0.04)};
|
|
body[2] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 1,0.3f,9);
|
|
|
|
v = new vector[]{put(-0.04, 0.055, 0.04), put(0.04, 0.055, 0.04), put(0.04, 0.055, -0.05), put(-0.04, 0.055, -0.05)};
|
|
body[3] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 1,1,9);
|
|
|
|
v = new vector[]{put(-0.04, 0.055, -0.05), put(0.04, 0.055, -0.05), put(0.04, 0.03, -0.07), put(-0.04, 0.03, -0.07)};
|
|
body[4] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 1,0.3f,9);
|
|
|
|
v = new vector[]{put(0.04, 0.03, 0.07),put(-0.04, 0.03, 0.07), put(-0.04, 0, 0.07), put(0.04, 0, 0.07)};
|
|
body[5] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 1,0.3f,9);
|
|
|
|
v = new vector[]{put(-0.04, 0.03, -0.07), put(0.04, 0.03, -0.07), put(0.04, 0., -0.07), put(-0.04, 0., -0.07)};
|
|
body[6] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 1,0.3f,9);
|
|
|
|
|
|
tempVector.set(start);
|
|
start = put(0,0,0.01);
|
|
|
|
v = new vector[]{put(-0.065, 0.03,0.1), put(-0.04, 0.03,0.1), put(-0.04, 0.03,0.03), put(-0.065, 0.03,0.03)};
|
|
body[7] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.04, 0.03,0.1), put(-0.065, 0.03,0.1), put(-0.065, 0.01,0.11), put(-0.04, 0.01,0.11)};
|
|
body[8] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.065, 0.03,0.03), put(-0.04, 0.03,0.03), put(-0.04, 0.01,0.029), put(-0.065, 0.01,0.029)};
|
|
body[9] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.065, 0.03,0.1), put(-0.065, 0.03,0.03), put(-0.065, 0.01,0.029), put(-0.065, 0.01,0.11)};
|
|
body[10] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.04, 0.01,0.11), put(-0.04, 0.01,0.029), put(-0.04, 0.03,0.03) ,put(-0.04, 0.03,0.1)};
|
|
body[11] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.065, 0.01,0.11), put(-0.065, 0.01,0.029), put(-0.065, -0.01,0.031), put(-0.065, -0.01,0.1)};
|
|
body[12] = new polygon3D(v, put(-0.065, 0.03,0.11), put(-0.065, 0.03,0.029), put(-0.065, -0.01,0.11), mainThread.textures[3], 1,1,9);
|
|
|
|
v = new vector[]{put(-0.04, -0.01,0.1), put(-0.04, -0.01,0.031), put(-0.04, 0.01,0.029), put(-0.04, 0.01,0.11)};
|
|
body[13] = new polygon3D(v, put(-0.04, 0.03,0.11), put(-0.04, 0.03,0.029), put(-0.04, -0.01,0.11), mainThread.textures[3], 1,1,9);
|
|
|
|
v = new vector[]{put(-0.065, 0.01,0.11), put(-0.065, -0.01,0.1), put(-0.04, -0.01,0.1), put(-0.04, 0.01,0.11)};
|
|
body[14] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[3], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.065, -0.01,0.031), put(-0.065, 0.01,0.029), put(-0.04, 0.01,0.029), put(-0.04, -0.01,0.031)};
|
|
body[15] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[3], 0.3f,0.5f,9);
|
|
|
|
start.set(tempVector);
|
|
start = put(0,0,-0.12);
|
|
|
|
v = new vector[]{put(-0.065, 0.03,0.1), put(-0.04, 0.03,0.1), put(-0.04, 0.03,0.03), put(-0.065, 0.03,0.03)};
|
|
body[16] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.04, 0.03,0.1), put(-0.065, 0.03,0.1), put(-0.065, 0.01,0.11), put(-0.04, 0.01,0.11)};
|
|
body[17] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.065, 0.03,0.03), put(-0.04, 0.03,0.03), put(-0.04, 0.01,0.029), put(-0.065, 0.01,0.029)};
|
|
body[18] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.065, 0.03,0.1), put(-0.065, 0.03,0.03), put(-0.065, 0.01,0.029), put(-0.065, 0.01,0.11)};
|
|
body[19] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.04, 0.01,0.11), put(-0.04, 0.01,0.029), put(-0.04, 0.03,0.03) ,put(-0.04, 0.03,0.1)};
|
|
body[20] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.065, 0.01,0.11), put(-0.065, 0.01,0.029), put(-0.065, -0.01,0.031), put(-0.065, -0.01,0.1)};
|
|
body[21] = new polygon3D(v, put(-0.065, 0.03,0.11), put(-0.065, 0.03,0.029), put(-0.065, -0.01,0.11), mainThread.textures[3], 1,1,9);
|
|
|
|
v = new vector[]{put(-0.04, -0.01,0.1), put(-0.04, -0.01,0.031), put(-0.04, 0.01,0.029), put(-0.04, 0.01,0.11)};
|
|
body[22] = new polygon3D(v, put(-0.04, 0.03,0.11), put(-0.04, 0.03,0.029), put(-0.04, -0.01,0.11), mainThread.textures[3], 1,1,9);
|
|
|
|
v = new vector[]{put(-0.065, 0.01,0.11), put(-0.065, -0.01,0.1), put(-0.04, -0.01,0.1), put(-0.04, 0.01,0.11)};
|
|
body[23] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[3], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.065, -0.01,0.031), put(-0.065, 0.01,0.029), put(-0.04, 0.01,0.029), put(-0.04, -0.01,0.031)};
|
|
body[24] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[3], 0.3f,0.5f,9);
|
|
|
|
start.set(tempVector);
|
|
start = put(0.105,0,-0.12);
|
|
|
|
v = new vector[]{put(-0.065, 0.03,0.1), put(-0.04, 0.03,0.1), put(-0.04, 0.03,0.03), put(-0.065, 0.03,0.03)};
|
|
body[25] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.04, 0.03,0.1), put(-0.065, 0.03,0.1), put(-0.065, 0.01,0.11), put(-0.04, 0.01,0.11)};
|
|
body[26] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.065, 0.03,0.03), put(-0.04, 0.03,0.03), put(-0.04, 0.01,0.029), put(-0.065, 0.01,0.029)};
|
|
body[27] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.065, 0.03,0.1), put(-0.065, 0.03,0.03), put(-0.065, 0.01,0.029), put(-0.065, 0.01,0.11)};
|
|
body[28] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.04, 0.01,0.11), put(-0.04, 0.01,0.029), put(-0.04, 0.03,0.03) ,put(-0.04, 0.03,0.1)};
|
|
body[29] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.065, 0.01,0.11), put(-0.065, 0.01,0.029), put(-0.065, -0.01,0.031), put(-0.065, -0.01,0.1)};
|
|
body[30] = new polygon3D(v, put(-0.065, 0.03,0.11), put(-0.065, 0.03,0.029), put(-0.065, -0.01,0.11), mainThread.textures[3], 1,1,9);
|
|
|
|
v = new vector[]{put(-0.04, -0.01,0.1), put(-0.04, -0.01,0.031), put(-0.04, 0.01,0.029), put(-0.04, 0.01,0.11)};
|
|
body[31] = new polygon3D(v, put(-0.04, 0.03,0.11), put(-0.04, 0.03,0.029), put(-0.04, -0.01,0.11), mainThread.textures[3], 1,1,9);
|
|
|
|
v = new vector[]{put(-0.065, 0.01,0.11), put(-0.065, -0.01,0.1), put(-0.04, -0.01,0.1), put(-0.04, 0.01,0.11)};
|
|
body[32] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[3], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.065, -0.01,0.031), put(-0.065, 0.01,0.029), put(-0.04, 0.01,0.029), put(-0.04, -0.01,0.031)};
|
|
body[33] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[3], 0.3f,0.5f,9);
|
|
|
|
start.set(tempVector);
|
|
start = put(0.105,0,0.01);
|
|
|
|
v = new vector[]{put(-0.065, 0.03,0.1), put(-0.04, 0.03,0.1), put(-0.04, 0.03,0.03), put(-0.065, 0.03,0.03)};
|
|
body[34] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.04, 0.03,0.1), put(-0.065, 0.03,0.1), put(-0.065, 0.01,0.11), put(-0.04, 0.01,0.11)};
|
|
body[35] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.065, 0.03,0.03), put(-0.04, 0.03,0.03), put(-0.04, 0.01,0.029), put(-0.065, 0.01,0.029)};
|
|
body[36] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.065, 0.03,0.1), put(-0.065, 0.03,0.03), put(-0.065, 0.01,0.029), put(-0.065, 0.01,0.11)};
|
|
body[37] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.04, 0.01,0.11), put(-0.04, 0.01,0.029), put(-0.04, 0.03,0.03) ,put(-0.04, 0.03,0.1)};
|
|
body[38] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.065, 0.01,0.11), put(-0.065, 0.01,0.029), put(-0.065, -0.01,0.031), put(-0.065, -0.01,0.1)};
|
|
body[39] = new polygon3D(v, put(-0.065, 0.03,0.11), put(-0.065, 0.03,0.029), put(-0.065, -0.01,0.11), mainThread.textures[3], 1,1,9);
|
|
|
|
v = new vector[]{put(-0.04, -0.01,0.1), put(-0.04, -0.01,0.031), put(-0.04, 0.01,0.029), put(-0.04, 0.01,0.11)};
|
|
body[40] = new polygon3D(v, put(-0.04, 0.03,0.11), put(-0.04, 0.03,0.029), put(-0.04, -0.01,0.11), mainThread.textures[3], 1,1,9);
|
|
|
|
v = new vector[]{put(-0.065, 0.01,0.11), put(-0.065, -0.01,0.1), put(-0.04, -0.01,0.1), put(-0.04, 0.01,0.11)};
|
|
body[41] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[3], 0.3f,0.5f,9);
|
|
|
|
v = new vector[]{put(-0.065, -0.01,0.031), put(-0.065, 0.01,0.029), put(-0.04, 0.01,0.029), put(-0.04, -0.01,0.031)};
|
|
body[42] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[3], 0.3f,0.5f,9);
|
|
|
|
start.set(tempVector);
|
|
|
|
turretCenter = put(0, 0.065, 0.0);
|
|
start.set(turretCenter);
|
|
|
|
turret = new polygon3D[66];
|
|
|
|
int turretSkinTexture = 64;
|
|
if(teamNo != 0)
|
|
turretSkinTexture = 26;
|
|
|
|
double r1 = 0.031;
|
|
double r2 = 0.02;
|
|
double r3 = 0.025;
|
|
double theta = Math.PI/16;
|
|
for(int i = 0; i < 32; i++){
|
|
v = new vector[]{put(r2*Math.cos(i*theta), r2*Math.sin(i*theta), -0.075),
|
|
put(r2*Math.cos((i+1)*theta), r2*Math.sin((i+1)*theta), -0.075),
|
|
put(r1*Math.cos((i+1)*theta), r1*Math.sin((i+1)*theta), 0.035),
|
|
put(r1*Math.cos(i*theta), r1*Math.sin(i*theta), 0.035)
|
|
};
|
|
turret[i] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[turretSkinTexture], 10,10,9);
|
|
}
|
|
|
|
for(int i = 0; i < 32; i++){
|
|
v = new vector[]{put(r1*Math.cos(i*theta), r1*Math.sin(i*theta), 0.035),
|
|
put(r1*Math.cos((i+1)*theta), r1*Math.sin((i+1)*theta), 0.035),
|
|
put(r3*Math.cos((i+1)*theta), r3*Math.sin((i+1)*theta), 0.08),
|
|
put(r3*Math.cos(i*theta), r3*Math.sin(i*theta), 0.08)
|
|
};
|
|
turret[i +32] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[turretSkinTexture], 10,10,9);
|
|
|
|
}
|
|
|
|
v = new vector[32];
|
|
for(int i = 1; i < 33; i++)
|
|
v[32 - i] = put(r2*Math.cos(i*theta), r2*Math.sin(i*theta), -0.075);
|
|
turret[64] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[turretSkinTexture], 10,10,9);
|
|
|
|
|
|
v = new vector[32];
|
|
for(int i = 1; i < 33; i++)
|
|
v[i-1] = put(r3*Math.cos(i*theta), r3*Math.sin(i*theta), 0.08);
|
|
turret[65] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[turretSkinTexture], 10,10,9);
|
|
|
|
for(int i = 0; i < 66; i++){
|
|
turret[i].Ambient_I+=20;
|
|
turret[i].reflectance = 70;
|
|
turret[i].findDiffuse();
|
|
}
|
|
|
|
}
|
|
|
|
//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+=20;
|
|
return;
|
|
}
|
|
|
|
if(experience >= 60){
|
|
myDamage = 45;
|
|
level = 1;
|
|
if(experience >= 120){
|
|
level = 2;
|
|
myDamage = 60;
|
|
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(isCloaked){
|
|
if(teamNo!=0){
|
|
isSelectable = false;
|
|
}
|
|
}else{
|
|
isSelectable = true;
|
|
}
|
|
|
|
if(cloakCooldownCount > 0){
|
|
cloakCooldownCount--;
|
|
isCloaked = false;
|
|
}
|
|
|
|
if(cloakCooldownCount ==0)
|
|
isCloaked = true;
|
|
|
|
if(isCloaked){
|
|
if(teamNo != 0){
|
|
if(!mainThread.fogOfWarDisabled && !mainThread.afterMatch)
|
|
if(currentCloakingStatus < 127)
|
|
currentCloakingStatus+=3;
|
|
}else{
|
|
if(currentCloakingStatus < 70){
|
|
currentCloakingStatus+=3;
|
|
}
|
|
}
|
|
|
|
if(currentShadowStatus < 127)
|
|
currentShadowStatus+=6;
|
|
}else{
|
|
if(currentCloakingStatus > 0){
|
|
currentCloakingStatus-=3;
|
|
if(currentCloakingStatus < 0)
|
|
currentCloakingStatus = 0;
|
|
}
|
|
|
|
if(currentShadowStatus > 0){
|
|
currentShadowStatus-=6;
|
|
if(currentShadowStatus < 0)
|
|
currentShadowStatus = 0;
|
|
}
|
|
|
|
}
|
|
|
|
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, make sure the tank isnt moving at a ridiculous speed
|
|
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 - 500);
|
|
visionBoundary.y = (int)(tempCentre.screenY - 1200);
|
|
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 < 17; y++){
|
|
for(int x = 0; x < 17; x++){
|
|
if(bitmapVisionForEnemy[x+ y*17])
|
|
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] = 2;
|
|
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] || mainThread.fogOfWarDisabled || mainThread.afterMatch;
|
|
|
|
if(teamNo == 0 || attackStatus == isAttacking || exposedCountDown > 0 || visible_minimap){
|
|
if(!(isCloaked && teamNo!=0) || mainThread.fogOfWarDisabled || mainThread.afterMatch){
|
|
tempInt = theAssetManager.unitsForMiniMap[theAssetManager.unitsForMiniMapCount];
|
|
tempInt[0] = teamNo + (this.type << 8);
|
|
tempInt[1] = boundary2D.x1/16;
|
|
tempInt[2] = 127 - boundary2D.y1/16;
|
|
tempInt[3] = 2;
|
|
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 && !isCloaked){
|
|
//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(isCloaked && teamNo!=0){
|
|
visible_minimap = false;
|
|
//if the stealth tank completely fades into back ground, then it is invisible
|
|
if(teamNo != 0 && currentCloakingStatus >=120)
|
|
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);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rasterizer.cloakTexture = gameData.cloakTextures[0];
|
|
rasterizer.cloakedShadowThreshold = currentShadowStatus;
|
|
|
|
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);
|
|
|
|
//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.add(movement);
|
|
turret[i].origin.subtract(turretCenter);
|
|
turret[i].origin.rotate_XZ(turretAngleDelta);
|
|
turret[i].origin.add(turretCenter);
|
|
|
|
turret[i].bottomEnd.add(movement);
|
|
turret[i].bottomEnd.subtract(turretCenter);
|
|
turret[i].bottomEnd.rotate_XZ(turretAngleDelta);
|
|
turret[i].bottomEnd.add(turretCenter);
|
|
|
|
turret[i].rightEnd.add(movement);
|
|
turret[i].rightEnd.subtract(turretCenter);
|
|
turret[i].rightEnd.rotate_XZ(turretAngleDelta);
|
|
turret[i].rightEnd.add(turretCenter);
|
|
}
|
|
|
|
for(int j = 0; j < turret[i].vertex3D.length; j++){
|
|
turret[i].vertex3D[j].add(movement);
|
|
turret[i].vertex3D[j].subtract(turretCenter);
|
|
turret[i].vertex3D[j].rotate_XZ(turretAngleDelta);
|
|
turret[i].vertex3D[j].add(turretCenter);
|
|
}
|
|
|
|
|
|
turret[i].normal.rotate_XZ(turretAngleDelta);
|
|
turret[i].findDiffuse();
|
|
}
|
|
}
|
|
|
|
//carry out commands given by player or AI commander
|
|
public void carryOutCommands(){
|
|
if(currentCommand == StandBy){
|
|
resetLogicStatus();
|
|
if(!isCloaked){
|
|
performStandByLogic();
|
|
}
|
|
|
|
}else if(currentCommand == move){
|
|
performMovementLogic();
|
|
avoidGettingStucked();
|
|
|
|
}else if(currentCommand == attackInNumbers || currentCommand == attackCautiously){
|
|
performAttackLogic();
|
|
avoidGettingStucked();
|
|
|
|
}else if(currentCommand == attackMove){
|
|
performAttackMoveLogic();
|
|
avoidGettingStucked();
|
|
}
|
|
}
|
|
|
|
public void resetLogicStatus(){
|
|
movement.reset();
|
|
turretAngleDelta = 0;
|
|
bodyAngleDelta = 0;
|
|
currentMovementStatus = freeToMove;
|
|
attackStatus = noTarget;
|
|
stuckCount = 0;
|
|
destinationX = centre.x;
|
|
destinationY = centre.z;
|
|
insideDeistinationRadiusCount = 0;
|
|
obstacle = null;
|
|
closeToDestination = false;
|
|
}
|
|
|
|
//the tank will attack with any hostile unit that moved into its firing range
|
|
public void performStandByLogic(){
|
|
//scan for hostile unit
|
|
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];
|
|
|
|
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){
|
|
attackMoveTo((tile[j].centre.x + centre.x)/2, (tile[j].centre.z+centre.z)/2);
|
|
currentCommand = solidObject.attackMove;
|
|
secondaryCommand = solidObject.attackMove;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//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);
|
|
movement.set(destinationX - centre.x, 0, destinationY - centre.z);
|
|
|
|
//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();
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//attack a single unit, ignore any hostile units it encounters
|
|
public void performAttackLogic(){
|
|
|
|
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));
|
|
|
|
//check if light tank has the line of sight to its target
|
|
hasLineOfSightToTarget = true;
|
|
if(distanceToDesination <= attackRange){
|
|
int numberOfIterations = (int)(distanceToDesination * 8);
|
|
float dx = (destinationX - centre.x)/numberOfIterations;
|
|
float dy = (destinationY - centre.z)/numberOfIterations;
|
|
float xStart = centre.x;
|
|
float yStart = centre.z;
|
|
|
|
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){
|
|
hasLineOfSightToTarget = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if(currentMovementStatus != hugRight && currentMovementStatus != hugLeft){
|
|
calculateMovement();
|
|
destinationAngle = geometry.findAngle(centre.x, centre.z, destinationX, destinationY);
|
|
immediateDestinationAngle = destinationAngle;
|
|
}
|
|
|
|
|
|
if((currentCommand == attackInNumbers && distanceToDesination <= groupAttackRange && hasLineOfSightToTarget) || (currentCommand == attackCautiously && distanceToDesination < attackRange && hasLineOfSightToTarget)){
|
|
movement.reset();
|
|
currentMovementStatus = freeToMove;
|
|
obstacle = null;
|
|
}
|
|
|
|
if(distanceToDesination <= attackRange){
|
|
|
|
if(hasLineOfSightToTarget)
|
|
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)
|
|
fireRailgunShot(attackAngle);
|
|
}else{
|
|
fireRailgunShot(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 && hasLineOfSightToTarget && 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 && hasLineOfSightToTarget && 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 && hasLineOfSightToTarget){
|
|
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 && hasLineOfSightToTarget){
|
|
|
|
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;
|
|
|
|
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];
|
|
|
|
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){
|
|
if(tile[j].type < 100 || tile[j].type >= 199){
|
|
attack(tile[j]);
|
|
currentCommand = attackInNumbers;
|
|
return;
|
|
}else{
|
|
if(target == null)
|
|
target = tile[j];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(target != null && ((target.centre.x - centre.x)*(target.centre.x - centre.x) + (target.centre.z - centre.z)*(target.centre.z - centre.z)) <= attackRange*attackRange){
|
|
attack(target);
|
|
currentCommand = attackInNumbers;
|
|
return;
|
|
}
|
|
|
|
performMovementLogic();
|
|
}
|
|
|
|
|
|
public void fireRailgunShot(int attackAngle){
|
|
if(attackCoolDown == 0 && targetObject.currentHP >0 && hasLineOfSightToTarget){
|
|
//if there is nothing between the tank and its target fire a railgun shot
|
|
firingPosition.set(0, -0.4f, 0.12f);
|
|
firingPosition.rotate_XZ(360 - attackAngle);
|
|
firingPosition.add(centre.x, 0, centre.z);
|
|
|
|
tempVector.set(0, 0, 0.1f);
|
|
tempVector.rotate_XZ(360 - attackAngle);
|
|
|
|
attackCoolDown = myAttackCooldown;
|
|
cloakCooldownCount = 120;
|
|
|
|
for(float i = 0.1f; i < distanceToDesination; i+=0.1f){
|
|
if(theAssetManager.helixCount >= theAssetManager.helixInfo.length)
|
|
break;
|
|
|
|
//spawn railgun trail
|
|
tempFloat = theAssetManager.helixInfo[theAssetManager.helixCount];
|
|
tempFloat[0] = firingPosition.x;
|
|
tempFloat[1] = firingPosition.y;
|
|
tempFloat[2] = firingPosition.z;
|
|
tempFloat[3] = attackAngle;
|
|
theAssetManager.helixCount++;
|
|
firingPosition.add(tempVector);
|
|
}
|
|
|
|
|
|
//spawn a mini explosion at target location
|
|
tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount];
|
|
tempFloat[0] = targetObject.centre.x;
|
|
tempFloat[1] = firingPosition.y;
|
|
tempFloat[2] = targetObject.centre.z;
|
|
tempFloat[3] = 0.8f;
|
|
tempFloat[4] = 1;
|
|
tempFloat[5] = 0;
|
|
tempFloat[6] = 6 + (gameData.getRandom()%4);
|
|
tempFloat[7] = firingPosition.y + 1.75f;
|
|
theAssetManager.explosionCount++;
|
|
|
|
int myDamageModified = myDamage;
|
|
|
|
if(targetObject.type==0){
|
|
myDamageModified=(int)(myDamage*2);
|
|
}else if(targetObject.type==1 || targetObject.type==6){
|
|
myDamageModified=(int)(myDamage*1.75);
|
|
}else if(targetObject.type > 100 || targetObject.type == 2 || targetObject.type == 3){
|
|
myDamageModified=(int)(myDamage*0.3);
|
|
}else if(targetObject.type == 7) {
|
|
myDamageModified=(int)(myDamage*0.3);
|
|
}
|
|
|
|
//damage and alert target unit
|
|
targetObject.currentHP-=myDamageModified;
|
|
targetObject.underAttackCountDown = 120;
|
|
targetObject.attacker = this;
|
|
|
|
int xPos = (int)(targetObject.centre.x*64);
|
|
int yPos = (int)(targetObject.centre.z*64);
|
|
int start = xPos/16 + (127 - yPos/16)*128;
|
|
int targetTeamNo = targetObject.teamNo;
|
|
solidObject[] tile;
|
|
|
|
for(int i = 0; i < 9; i++){
|
|
int index = start + tiles3x3[i];
|
|
if(index > 16383 || index < 0)
|
|
continue;
|
|
tile = mainThread.gridMap.tiles[index];
|
|
for(int j = 0; j < 4; j++){
|
|
if(tile[j] != null){
|
|
if(tile[j].teamNo == targetTeamNo && tile[j].currentCommand == solidObject.StandBy && targetTeamNo != teamNo && tile[j].isCloaked == false){
|
|
if(tile[j].type < 100){
|
|
tile[j].attack(this);
|
|
tile[j].currentCommand = solidObject.attackInNumbers;
|
|
}
|
|
}else if(tile[j].teamNo == targetTeamNo && tile[j].currentCommand == solidObject.attackMove && targetTeamNo != teamNo && tile[j].isCloaked == false){
|
|
if(tile[j].attackStatus != solidObject.isAttacking ||
|
|
(tile[j].attackStatus == isAttacking && tile[j].targetObject != null && tile[j].targetObject.type < 199 && tile[j].targetObject.type > 7)){
|
|
targetObject.attack(this);
|
|
targetObject.currentCommand = solidObject.attackInNumbers;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if(hasMultiShotUpgrade && targetObject.type < 100){
|
|
//find up to 3 random secondary targets around main targets
|
|
for(int i = 0; i < secondaryTargets.length; i++)
|
|
secondaryTargets[i] = null;
|
|
|
|
int targetCount = 0;
|
|
int randomNumber = gameData.getRandom()%secondaryAttackCheckList.length;
|
|
|
|
for(int k = randomNumber; k < secondaryAttackCheckList.length + randomNumber; k++){
|
|
int i = k%secondaryAttackCheckList.length;
|
|
if(secondaryAttackCheckList[i] != Integer.MAX_VALUE){
|
|
int index = start + secondaryAttackCheckList[i];
|
|
if(index < 0 || index >= 16384)
|
|
continue;
|
|
tile = mainThread.gridMap.tiles[index];
|
|
|
|
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 && tile[j].type < 100){
|
|
if(tile[j] != secondaryTargets[0] && tile[j] != secondaryTargets[1] && tile[j] != secondaryTargets[2] && tile[j] != targetObject){
|
|
secondaryTargets[targetCount] = tile[j];
|
|
targetCount++;
|
|
if(targetCount == 3)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(targetCount == 3)
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
for(int i = 0; i < 3; i++){
|
|
if( secondaryTargets[i] != null){
|
|
double distance = Math.sqrt((secondaryTargets[i].centre.x - targetObject.centre.x)*(secondaryTargets[i].centre.x - targetObject.centre.x) + (secondaryTargets[i].centre.z - targetObject.centre.z)*(secondaryTargets[i].centre.z - targetObject.centre.z));
|
|
|
|
|
|
tempVector.set(secondaryTargets[i].centre);
|
|
tempVector.subtract(targetObject.centre);
|
|
tempVector.y = 0;
|
|
tempVector.unit();
|
|
tempVector.scale(0.1f);
|
|
|
|
firingPosition.set(targetObject.centre);
|
|
firingPosition.y = -0.4f;
|
|
|
|
int secondaryAttackAngle = geometry.findAngle(targetObject.centre.x, targetObject.centre.z, secondaryTargets[i].centre.x, secondaryTargets[i].centre.z);
|
|
|
|
|
|
for(float j = 0; j < distance; j+=0.1f){
|
|
if(theAssetManager.helixCount >= theAssetManager.helixInfo.length)
|
|
break;
|
|
|
|
//spawn railgun trail
|
|
tempFloat = theAssetManager.helixInfo[theAssetManager.helixCount];
|
|
tempFloat[0] = firingPosition.x;
|
|
tempFloat[1] = firingPosition.y;
|
|
tempFloat[2] = firingPosition.z;
|
|
tempFloat[3] = secondaryAttackAngle;
|
|
theAssetManager.helixCount++;
|
|
firingPosition.add(tempVector);
|
|
}
|
|
|
|
|
|
//spawn a mini explosion at target location
|
|
tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount];
|
|
tempFloat[0] = secondaryTargets[i].centre.x;
|
|
tempFloat[1] = -0.4f;
|
|
tempFloat[2] = secondaryTargets[i].centre.z;
|
|
tempFloat[3] = 0.8f;
|
|
tempFloat[4] = 1;
|
|
tempFloat[5] = 0;
|
|
tempFloat[6] = 6 + (gameData.getRandom()%4);
|
|
tempFloat[7] = -0.4f + 1.75f;
|
|
theAssetManager.explosionCount++;
|
|
|
|
//damage and alert target unit
|
|
|
|
myDamageModified = myDamage;
|
|
|
|
if(secondaryTargets[i].type==0 || targetObject.type==1){
|
|
myDamageModified=(int)(myDamage*3);
|
|
|
|
}else if(targetObject.type==6){
|
|
myDamageModified=(int)(myDamage*1.75);
|
|
}else if(targetObject.type == 2 || targetObject.type == 3){
|
|
myDamageModified=(int)(myDamage*0.3);
|
|
}else if(secondaryTargets[i].type == 7) {
|
|
myDamageModified=(int)(myDamage*0.2);
|
|
}
|
|
|
|
|
|
secondaryTargets[i].currentHP-=((int)(myDamageModified/3));
|
|
secondaryTargets[i].underAttackCountDown = 120;
|
|
secondaryTargets[i].attacker = this;
|
|
|
|
if((secondaryTargets[i].secondaryCommand == solidObject.attackMove || secondaryTargets[i].currentCommand == solidObject.StandBy) && (secondaryTargets[i].attackStatus != solidObject.isAttacking ||
|
|
(secondaryTargets[i].attackStatus == isAttacking && secondaryTargets[i].targetObject != null && secondaryTargets[i].targetObject.type < 199 && secondaryTargets[i].targetObject.type > 7))){
|
|
secondaryTargets[i].attack(this);
|
|
secondaryTargets[i].currentCommand = solidObject.attackInNumbers;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
public void draw(){
|
|
if(!visible)
|
|
return;
|
|
|
|
rasterizer.modelCenterX = (int)(tempCentre.screenX);
|
|
rasterizer.modelCenterY = (int)(tempCentre.screenY);
|
|
rasterizer.cloakTexture = gameData.cloakTextures[(randomNumber + mainThread.gameFrame * 2)%120];
|
|
rasterizer.cloakedThreshold = currentCloakingStatus;
|
|
|
|
|
|
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;}
|
|
}
|