commit 7c83ed126762c6bbd5514785920c72b32d378e95 Author: Pan Date: Thu Aug 30 23:07:37 2018 +1200 Test Commit diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..07661e7 --- /dev/null +++ b/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9bf81e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/main.class diff --git a/.project b/.project new file mode 100644 index 0000000..341f391 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + Java_RTS + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/core/.gitignore b/core/.gitignore new file mode 100644 index 0000000..8a42e92 --- /dev/null +++ b/core/.gitignore @@ -0,0 +1,20 @@ +/AssetManager.class +/DaemonThread.class +/PathFinder.class +/Rect.class +/Ticker.class +/Turn2DTo3DFactory.class +/baseInfo.class +/camera.class +/gameData.class +/geometry.class +/grid.class +/mainThread.class +/polygon3D.class +/postProcessingThread.class +/rasterizer.class +/sunLight.class +/terrain.class +/textRenderer.class +/texture.class +/vector.class diff --git a/core/AssetManager.java b/core/AssetManager.java new file mode 100644 index 0000000..6bf0334 --- /dev/null +++ b/core/AssetManager.java @@ -0,0 +1,820 @@ +package core; + +import enemyAI.*; +import entity.*; +import gui.*; +import particles.*; + +//This class stores and maintains all the entities created in the game +public class AssetManager { + + public int polygonCount; + + public int visibleUnitCount; + public solidObject[] visibleUnit; + + public int[][] selectedUnitsInfo; + public int[][] selectedUnitsInfo2; + + public float[][] visionPolygonInfo; + public float[][] visionPolygonInfo2; + public int visionPolygonCount; + + public int[][] unitsForMiniMap; + public int[][] unitsForMiniMap2; + public int unitsForMiniMapCount; + + public boolean[] minimapBitmap; + public boolean[] minimapBitmap2; + + public float[][] smokeEmmiterList; + public float[][] smokeEmmiterList2; + public int smokeEmmiterCount; + + public float[][] explosionInfo; + public float[][] explosionInfo2; + public int explosionCount;; + + public float[][] helixInfo; + public float[][] helixInfo2; + public int helixCount; + + public double[] confirmationIconInfo; + public double[] confirmationIconInfo2; + + + public lightTank[] lightTanks; + public heavyTank[] heavyTanks; + public palmTree[] trees; + public int plamTreeCount; + public powerPlant[] powerPlants; + public refinery[] refineries; + public rocketTank[] rocketTanks; + public harvester[] harvesters; + public goldMine[] goldMines; + public constructionVehicle[] constructionVehicles; + public constructionYard[] constructionYards; + public factory[] factories; + public drone[] drones; + public communicationCenter[] communicationCenters; + public techCenter[] techCenters; + public stealthTank[] stealthTanks; + public gunTurret[] gunTurrets; + public missileTurret[] missileTurrets; + + public terrain Terrain; + + public bullet[] bullets; + public rocket[] rockets; + public polygon3D[] visionPolygon; + + + public void init(){ + + + selectedUnitsInfo = new int[100][6]; + selectedUnitsInfo2 = new int[100][6]; + + visionPolygonInfo = new float[400][5]; + visionPolygonInfo2 = new float[400][5]; + + unitsForMiniMap = new int[1000][5]; + unitsForMiniMap2 = new int[1000][5]; + + + smokeEmmiterList = new float[100][8]; + smokeEmmiterList2 = new float[100][8]; + + minimapBitmap = new boolean[128 * 128]; + minimapBitmap2 = new boolean[128 * 128]; + + + explosionInfo = new float[100][8]; + explosionInfo2 = new float[100][8]; + + helixInfo = new float[128][4]; + helixInfo2 = new float[128][4]; + + confirmationIconInfo = new double[5]; + confirmationIconInfo2 = new double[5]; + + + bullets = new bullet[200]; + for(int i = 0; i < 200; i ++){ + bullets[i] = new bullet(); + + } + + rockets = new rocket[200]; + for(int i = 0; i < 200; i ++){ + rockets[i] = new rocket(); + + } + + visibleUnit = new solidObject[400]; + + //polygons which represent the area of sight for player + double angle = Math.PI/24; + visionPolygon = new polygon3D[4]; + vector[] v = new vector[48]; + for(int i = 0; i < 48; i++){ + v[i] = new vector((float)Math.sin(i*angle)*1.6f, 1f, (float)Math.cos(i*angle)*1.6f); + } + visionPolygon[0] = new polygon3D(v, v[0], v[1], v[3], null, 1,1, 2); + + // vision created by an attacking enemy unit + v = new vector[48]; + for(int i = 0; i < 48; i++){ + v[i] = new vector((float)Math.sin(i*angle)*0.5f, -1.5f, (float)Math.cos(i*angle)*0.5f); + } + visionPolygon[1] = new polygon3D(v, v[0], v[1], v[3], null, 1,1, 2); + + //vision created by building + v = new vector[48]; + for(int i = 0; i < 48; i++){ + v[i] = new vector((float)Math.sin(i*angle)*2.1f, 1f, (float)Math.cos(i*angle)*2.1f); + } + visionPolygon[2] = new polygon3D(v, v[0], v[1], v[3], null, 1,1, 2); + + //vision created by communication center + v = new vector[48]; + for(int i = 0; i < 48; i++){ + v[i] = new vector((float)Math.sin(i*angle)*3.1f, 1f, (float)Math.cos(i*angle)*3.1f); + } + visionPolygon[3] = new polygon3D(v, v[0], v[1], v[3], null, 1,1, 2); + + + lightTanks = new lightTank[768]; + heavyTanks = new heavyTank[256]; + trees = new palmTree[2048]; + powerPlants = new powerPlant[256]; + refineries = new refinery[128]; + rocketTanks = new rocketTank[512]; + harvesters = new harvester[128]; + constructionVehicles = new constructionVehicle[64]; + goldMines = new goldMine[16]; + constructionYards = new constructionYard[64]; + factories = new factory[128]; + drones = new drone[384]; + communicationCenters = new communicationCenter[128]; + techCenters = new techCenter[64]; + stealthTanks = new stealthTank[384]; + gunTurrets = new gunTurret[512]; + missileTurrets = new missileTurret[256]; + + + Terrain = new terrain(); + + //unit costs/hit point/power consumption/exp on kill + //lightTank 300/120/0/10 + //rocketTank 450/70/0/15 + //harvester 800/260/0/25 + //stealth tank 600/80/0/20 + //heavyTank 1100/320/0/50 + //constructionVehicle 1700/300/0/30 + // + //power plant 500/400/+500/25 + //refinery 1200/750/-150/35 + //communication center 1000/550/-250/35 + //factory 1400/850/-200/40 + //tech center 1500/s/-450/50 + //gun turret 400/250/-100/20 + //missile turret 750/250/(-200/-400)/35 + //construction yard 1700/1000/0/50 + // + + + //harvester speed research 1200 + //missile turret overcharge research 1500 + //light tank range upgrade 1500 + //Missile tank dmg upgrade 2500 + //stealth tank split lasor 2500 + //Heavy tank regen 3000 + + + goldMines[0] = new goldMine(2f,-0.515f, 1.25f, 30000); + goldMines[1] = new goldMine(9.5f,-0.515f, 5.5f, 30000); + goldMines[2] = new goldMine(2f,-0.515f, 28.25f, 40000); + goldMines[3] = new goldMine(26f,-0.515f, 3.5f, 40000); + goldMines[4] = new goldMine(29.75f,-0.515f, 30f, 30000); + goldMines[5] = new goldMine(22.5f,-0.515f, 25.5f, 30000); + goldMines[6] = new goldMine(15.5f,-0.515f, 17.75f, 45000); + goldMines[7] = new goldMine(16.5f,-0.515f, 12.5f, 45000); + + + //create trees from bitmap + short[] treeBitmap = mainThread.textures[56].pixelData; + for(int i = 0; i < 114; i++){ + for(int j = 0; j < 114; j++){ + if((treeBitmap[j + i * 128]<<10) <128 && plamTreeCount < trees.length){ + trees[plamTreeCount] = new palmTree(j*0.28f, -0.3f, (113 -i)*0.28f); + plamTreeCount++; + } + + } + } + + mainThread.pc = new playerCommander(); + mainThread.pc.init(); + + mainThread.ec = new enemyCommander(); + mainThread.ec.init(); + + + } + + public void prepareAssetForNewGame(){ + addConstructionVehicle(new constructionVehicle(new vector(3.125f,-0.3f, 2.125f), 90, 0)); + addConstructionVehicle(new constructionVehicle(new vector(29.625f,-0.3f, 28.875f), 90, 1)); + constructionVehicles[1].expand(); + + for(int i = 0; i < 6; i ++){ + + for(int j = 0; j < 10; j++){ + + //if(i == 0) { + //rocketTank l = new rocketTank(new vector(j*0.25f+ 1.125f,-0.3f, 22.125f - i*0.25f), 90, 1); + //l.damageMultiplier =2; + //addRocketTank(l); + //techCenter.rocketTankResearched_enemy = true; + + //}else { + //heavyTank l = new heavyTank(new vector(j*0.25f+ 1.125f,-0.3f, 22.125f - i*0.25f), 90, 1); + + //addHeavyTank(l); + //} + + + } + } + + for(int i = 0; i < 10; i ++){ + + for(int j = 0; j < 6; j++){ + //heavyTank l = new heavyTank(new vector(i*0.25f+ 1.125f,-0.3f, 17.375f - 0.25f*j), 90, 0); + //addHeavyTank(l); + //l.hasMultiShotUpgrade = true; + //lightTank l = new lightTank(new vector(i*0.25f + 1.125f,-0.3f, 0.5f + 18.625f + j*0.25f), 90, 0); + + //l.attackRange = 1.99f; + + //lightTank.tileCheckList_player = lightTank.generateTileCheckList(6); + + //addLightTank(l); + //addMissileTurret(new missileTurret(i*0.25f -0.125f + 1, -0.65f, 0.25f + 16.125f + j*0.25f, 0)); + + } + } + + + + } + + public void addContructionYard(constructionYard o){ + for(int i = 0; i < constructionYards.length; i++){ + if(constructionYards[i] == null){ + constructionYards[i] = o; + break; + } + } + } + + public void addPowerPlant(powerPlant o){ + for(int i = 0; i < powerPlants.length; i++){ + if(powerPlants[i] == null){ + powerPlants[i] = o; + break; + } + } + } + + public void addRefinery(refinery o){ + for(int i = 0; i < refineries.length; i++){ + if(refineries[i] == null){ + refineries[i] = o; + break; + } + } + } + + public void addFactory(factory o){ + for(int i = 0; i < factories.length; i++){ + if(factories[i] == null){ + factories[i] = o; + break; + } + } + } + + public void addDrone(drone o){ + for(int i = 0; i < drones.length; i++){ + if(drones[i] == null){ + drones[i] = o; + break; + } + } + } + + public void addCommunicationCenter(communicationCenter o){ + for(int i = 0; i < communicationCenters.length; i++){ + if(communicationCenters[i] == null){ + communicationCenters[i] = o; + break; + } + } + } + + public void addTechCenter(techCenter o){ + for(int i = 0; i < techCenters.length; i++){ + if(techCenters[i] == null){ + techCenters[i] = o; + break; + } + } + } + + public void addHarvester(harvester o){ + for(int i = 0; i < harvesters.length; i++){ + if(harvesters[i] == null){ + harvesters[i] = o; + break; + } + } + } + + public void addLightTank(lightTank o){ + for(int i = 0; i < lightTanks.length; i++){ + if(lightTanks[i] == null){ + lightTanks[i] = o; + break; + } + } + } + + public void addHeavyTank(heavyTank o){ + for(int i = 0; i < heavyTanks.length; i++){ + if(heavyTanks[i] == null){ + heavyTanks[i] = o; + break; + } + } + } + + public void addStealthTank(stealthTank o){ + for(int i = 0; i < stealthTanks.length; i++){ + if(stealthTanks[i] == null){ + stealthTanks[i] = o; + break; + } + } + } + + public void addRocketTank(rocketTank o){ + for(int i = 0; i < rocketTanks.length; i++){ + if(rocketTanks[i] == null){ + rocketTanks[i] = o; + break; + } + } + } + + public void addConstructionVehicle(constructionVehicle o){ + for(int i = 0; i < constructionVehicles.length; i++){ + if(constructionVehicles[i] == null){ + constructionVehicles[i] = o; + break; + } + } + } + + public void addGunTurret(gunTurret o){ + for(int i = 0; i < gunTurrets.length; i++){ + if(gunTurrets[i] == null){ + gunTurrets[i] = o; + break; + } + } + } + + public void addMissileTurret(missileTurret o){ + for(int i = 0; i < missileTurrets.length; i++){ + if(missileTurrets[i] == null){ + missileTurrets[i] = o; + break; + } + } + } + + + public void updateAndDraw(){ + polygonCount = 0; + visibleUnitCount = 0; + visionPolygonCount = 0; + unitsForMiniMapCount = 0; + explosionCount = 0; + smokeEmmiterCount = 0; + helixCount = 0; + + + Terrain.update(); + + for(int i = 0; i < lightTanks.length; i++){ + if(lightTanks[i] != null) + lightTanks[i].update(); + } + + for(int i = 0; i < heavyTanks.length; i++){ + if(heavyTanks[i] != null) + heavyTanks[i].update(); + } + + for(int i = 0; i < stealthTanks.length; i++){ + if(stealthTanks[i] != null) + stealthTanks[i].update(); + } + + for(int i = 0; i < plamTreeCount; i++) + trees[i].update(); + + + for(int i = 0; i < constructionYards.length; i++){ + if(constructionYards[i] != null) + constructionYards[i].update(); + } + + for(int i = 0; i < powerPlants.length; i++){ + if(powerPlants[i] != null) + powerPlants[i].update(); + } + + for(int i = 0; i < techCenters.length; i++){ + if(techCenters[i] != null) + techCenters[i].update(); + } + + for(int i = 0; i < gunTurrets.length; i++){ + if(gunTurrets[i] != null) + gunTurrets[i].update(); + } + + for(int i = 0; i < missileTurrets.length; i++){ + if(missileTurrets[i] != null) + missileTurrets[i].update(); + } + + for(int i = 0; i < communicationCenters.length; i++){ + if(communicationCenters[i] != null) + communicationCenters[i].update(); + } + + for(int i = 0; i < refineries.length; i++){ + if(refineries[i] != null) + refineries[i].update(); + } + + for(int i = 0; i < factories.length; i++){ + if(factories[i] != null) + factories[i].update(); + } + + for(int i = 0; i < drones.length; i++){ + if(drones[i] != null) + drones[i].update(); + } + + + for(int i = 0; i < rocketTanks.length; i++){ + if(rocketTanks[i] != null) + rocketTanks[i].update(); + } + + for(int i = 0; i < harvesters.length; i++){ + if(harvesters[i] != null) + harvesters[i].update(); + } + + for(int i = 0; i < constructionVehicles.length; i++){ + if(constructionVehicles[i] != null) + constructionVehicles[i].update(); + } + + + for(int i = 0; i < 10; i++){ + if(goldMines[i] != null) + goldMines[i].update(); + } + + + //start drawing + //maximize the zbuffer value in the area that are occupied by UI, so the drawing process will not waste time filling the pixels which would eventually get overdrawn + int start = 381 * 768 + 3; + int start2 = 381 * 768 + 635; + for(int y = 0; y < 131; y++){ + for(int x = 0; x < 128; x ++){ + mainThread.zBuffer[start + x + y*768] = Integer.MAX_VALUE; + mainThread.zBuffer[start2 + x + y*768] = Integer.MAX_VALUE; + } + } + + + + for(int i = 0; i < 200; i ++) + bullets[i].updateAndDraw(); + + for(int i = 0; i < 200; i ++) + rockets[i].update(); + + + for(int i = 0; i < lightTanks.length; i++){ + if(lightTanks[i] != null) + lightTanks[i].draw(); + } + + for(int i = 0; i < heavyTanks.length; i++){ + if(heavyTanks[i] != null) + heavyTanks[i].draw(); + } + + for(int i = 0; i < stealthTanks.length; i++){ + if(stealthTanks[i] != null) + stealthTanks[i].draw(); + } + + for(int i = 0; i < plamTreeCount; i++) + trees[i].draw(); + + for(int i = 0; i < powerPlants.length; i++){ + if(powerPlants[i] != null) + powerPlants[i].draw(); + } + + for(int i = 0; i < gunTurrets.length; i++){ + if(gunTurrets[i] != null) + gunTurrets[i].draw(); + } + + for(int i = 0; i < missileTurrets.length; i++){ + if(missileTurrets[i] != null) + missileTurrets[i].draw(); + } + + for(int i = 0; i < communicationCenters.length; i++){ + if(communicationCenters[i] != null) + communicationCenters[i].draw(); + } + + for(int i = 0; i < techCenters.length; i++){ + if(techCenters[i] != null) + techCenters[i].draw(); + } + + for(int i = 0; i < refineries.length; i++){ + if(refineries[i] != null) + refineries[i].draw(); + } + + for(int i = 0; i < rocketTanks.length; i++){ + if(rocketTanks[i] != null) + rocketTanks[i].draw(); + } + + for(int i = 0; i < harvesters.length; i++){ + if(harvesters[i] != null) + harvesters[i].draw(); + } + + for(int i = 0; i < constructionVehicles.length; i++){ + if(constructionVehicles[i] != null) + constructionVehicles[i].draw(); + } + + for(int i = 0; i < constructionYards.length; i++){ + if(constructionYards[i] != null) + constructionYards[i].draw(); + } + + + + for(int i = 0; i < goldMines.length; i++){ + if(goldMines[i] != null) + goldMines[i].draw(); + } + + for(int i = 0; i < 200; i ++) + rockets[i].draw(); + + + for(int i = 0; i < drones.length; i++){ + if(drones[i] != null) + drones[i].draw(); + } + + for(int i = 0; i < factories.length; i++){ + if(factories[i] != null) + factories[i].draw(); + } + + + Terrain.draw(); + + + + if(mainThread.pc.selectedConstructionYard != null){ + mainThread.pc.selectedConstructionYard.drawDeploymentGrid(); + } + + for(int i = 0; i < factories.length; i++){ + if(factories[i] != null) + factories[i].drawRallyPointLine(); + } + + + //prepare selected unit list + for(int i = 0; i < 99; i++){ + if(mainThread.pc.selectedUnits[i] != null && mainThread.pc.selectedUnits[i].isSelectable){ + selectedUnitsInfo[i][0] = mainThread.pc.selectedUnits[i].level << 16 | mainThread.pc.selectedUnits[i].groupNo << 8 | mainThread.pc.selectedUnits[i].type; + selectedUnitsInfo[i][1] = (int)mainThread.pc.selectedUnits[i].tempCentre.screenX; + selectedUnitsInfo[i][2] = (int)mainThread.pc.selectedUnits[i].tempCentre.screenY; + if(mainThread.pc.selectedUnits[i].type == 199){ + selectedUnitsInfo[i][1] = (int)mainThread.pc.selectedUnits[i].screenX_gui; + selectedUnitsInfo[i][2] = (int)mainThread.pc.selectedUnits[i].screenY_gui; + } + + selectedUnitsInfo[i][3] = (int)mainThread.pc.selectedUnits[i].type; + selectedUnitsInfo[i][4] = mainThread.pc.selectedUnits[i].currentHP; + selectedUnitsInfo[i][5] = mainThread.pc.selectedUnits[i].progressStatus; + }else{ + selectedUnitsInfo[i][0] = -1; + } + } + + } + + + //swap the resources that are held by the main thread and the post processing thread + public void swapResources(){ + int[][] list; + list = selectedUnitsInfo; + selectedUnitsInfo = selectedUnitsInfo2; + selectedUnitsInfo2 = list; + + float[][] floatList; + floatList = visionPolygonInfo; + visionPolygonInfo = visionPolygonInfo2; + visionPolygonInfo2 = floatList; + + int[][] unitList; + unitList = unitsForMiniMap; + unitsForMiniMap = unitsForMiniMap2; + unitsForMiniMap2 = unitList; + + boolean[] bitmap; + bitmap = minimapBitmap; + minimapBitmap = minimapBitmap2; + minimapBitmap2 = bitmap; + + float[][] emmiterList; + emmiterList = smokeEmmiterList; + smokeEmmiterList = smokeEmmiterList2; + smokeEmmiterList2 = emmiterList; + + float[][] explosionList; + explosionList = explosionInfo; + explosionInfo = explosionInfo2; + explosionInfo2 = explosionList; + + double[] iconInfo; + iconInfo = confirmationIconInfo; + confirmationIconInfo = confirmationIconInfo2; + confirmationIconInfo2 = iconInfo; + } + + //spawn a bullet + public void spawnBullet(int angle, int damage, solidObject target, vector centre, solidObject attacker){ + for(int i = 0; i < 200; i ++) + if(!bullets[i].isInAction){ + bullets[i].setActive(angle, damage, target, centre, attacker); + break; + } + } + + //spawn a rocket + public void spawnRocket(int angle, int damage, solidObject target, vector centre, solidObject attacker){ + for(int i = 0; i < 200; i ++) + if(!rockets[i].isInAction){ + rockets[i].setActive(angle, damage, target, centre, attacker); + break; + } + } + + //remove object that ceased to exist (e.g get destroyed) + public void removeObject(solidObject o){ + + mainThread.pc.removeDestoryedObjectFromSelection(o); + for(int i = 0; i < lightTanks.length; i++){ + if(lightTanks[i] == o){ + lightTanks[i] = null; + return; + } + } + + for(int i = 0; i < stealthTanks.length; i++){ + if(stealthTanks[i] == o){ + stealthTanks[i] = null; + return; + } + } + + for(int i = 0; i < powerPlants.length; i++){ + if(powerPlants[i] == o){ + powerPlants[i] = null; + return; + } + } + + for(int i = 0; i < techCenters.length; i++){ + if(techCenters[i] == o){ + techCenters[i] = null; + return; + } + } + + for(int i = 0; i < gunTurrets.length; i++){ + if(gunTurrets[i] == o){ + gunTurrets[i] = null; + return; + } + } + + for(int i = 0; i < missileTurrets.length; i++){ + if(missileTurrets[i] == o){ + missileTurrets[i] = null; + return; + } + } + + for(int i = 0; i < communicationCenters.length; i++){ + if(communicationCenters[i] == o){ + communicationCenters[i] = null; + return; + } + } + + for(int i = 0; i < refineries.length; i++){ + if(refineries[i] == o){ + refineries[i] = null; + return; + } + } + + for(int i = 0; i < factories.length; i++){ + if(factories[i] == o){ + factories[i] = null; + return; + } + } + + for(int i = 0; i < drones.length; i++){ + if(drones[i] == o){ + drones[i] = null; + return; + } + } + + for(int i = 0; i < rocketTanks.length; i++){ + if(rocketTanks[i] == o){ + rocketTanks[i] = null; + return; + } + } + + for(int i = 0; i < heavyTanks.length; i++){ + if(heavyTanks[i] == o){ + heavyTanks[i] = null; + return; + } + } + + for(int i = 0; i < harvesters.length; i++){ + if(harvesters[i] == o){ + harvesters[i] = null; + return; + } + } + + for(int i = 0; i < constructionVehicles.length; i++){ + if(constructionVehicles[i] == o){ + constructionVehicles[i] = null; + return; + } + } + + for(int i = 0; i < constructionYards.length; i++){ + if(constructionYards[i] == o){ + constructionYards[i] = null; + return; + } + } + + } +} diff --git a/core/DaemonThread.java b/core/DaemonThread.java new file mode 100644 index 0000000..223a55b --- /dev/null +++ b/core/DaemonThread.java @@ -0,0 +1,10 @@ +package core; + +public class DaemonThread implements Runnable { + public void run(){ + try{ + Thread.sleep(Long.MAX_VALUE); + } + catch(Exception e){} + } +} diff --git a/core/PathFinder.java b/core/PathFinder.java new file mode 100644 index 0000000..39b5fe7 --- /dev/null +++ b/core/PathFinder.java @@ -0,0 +1,148 @@ +package core; + +/* +1. You start the search from the destination-point (Step 0) and not the start-point. +2. You mark the 4 squares over/under and left/right of the current square with "1" (step value) (if its not a wall) as in "one step from the destination", then you add these squares to a node-list. +3. Go through the current node-list and repeat point 2 on each entry, mark the appropriate squares "2" (n+1) and add these to a swap node-list.Squares already marked with a step-value are IGNORED (like a wall). +4. Repeat point 2 & 3 while incresing the step-value for every cycle/point until you have reached the start-point. (or continue and scan the whole maze if desired). +5. Now you have the shortest way to the target, by simply moving to the adjacent square with the lowest number - until you have reached the destination! +*/ + + + +public class PathFinder{ + public static int[] nodes = new int[128*128]; + + public static boolean createHeuristicMap(byte[] heuristicMap, int occupiedTile0, int occupiedTile1, int occupiedTile2, int occupiedTile3, int destX, int destY){ + + if(destX == 0) + destX = 1; + if(destX == 127) + destX = 126; + if(destY == 0) + destY = 1; + if(destY == 127) + destY = 126; + + + int l = 128 * 128; + for(int i = 0; i < l ; i++) + heuristicMap[i] = 127; + boolean[] obstacleMap = mainThread.gridMap.previousObstacleMap; + + int destTile = destX + destY*128; + //mark destination tile with heuristic value 0 + if(destTile < 0) + destTile = 0; + if(destTile >= 16384) + destTile = 16383; + heuristicMap[destTile] = 0; + + int topTile = destTile- 128; + int botTile = destTile+ 128; + int leftTile = destTile- 1; + int rightTile = destTile+ 1; + + //check if path is the starting tiles is reached + if(topTile == occupiedTile0 || topTile == occupiedTile1 || topTile == occupiedTile2 || topTile == occupiedTile3 || + botTile == occupiedTile0 || botTile == occupiedTile1 || botTile == occupiedTile2 || botTile == occupiedTile3 || + leftTile == occupiedTile0 || leftTile == occupiedTile1 || leftTile == occupiedTile2 || leftTile == occupiedTile3 || + rightTile == occupiedTile0 || rightTile == occupiedTile1 || rightTile == occupiedTile2 || rightTile == occupiedTile3){ + return true; + } + + + int nodeCount = 0; + + if(obstacleMap[topTile]){ + nodes[nodeCount] = topTile; + heuristicMap[topTile] = 1; + nodeCount++; + } + + if(obstacleMap[botTile]){ + nodes[nodeCount] = botTile; + heuristicMap[botTile] = 1; + nodeCount++; + } + + if(obstacleMap[leftTile]){ + nodes[nodeCount] = leftTile; + heuristicMap[leftTile] = 1; + nodeCount++; + } + + if(obstacleMap[rightTile]){ + nodes[nodeCount] = rightTile; + heuristicMap[rightTile] = 1; + nodeCount++; + } + + int startIndex = 0; + int endIndex = startIndex + nodeCount; + + + + for(byte i = 0, distance = 2; i < 126; i++, distance++){ // max depth = 126 + + + nodeCount = 0; + for(int j = startIndex; j < endIndex; j++){ + + destTile = nodes[j]; + + + topTile = destTile- 128; + botTile = destTile+ 128; + leftTile = destTile- 1; + rightTile = destTile+ 1; + + //check if path is the starting tiles is reached + if(topTile == occupiedTile0 || topTile == occupiedTile1 || topTile == occupiedTile2 || topTile == occupiedTile3 || + botTile == occupiedTile0 || botTile == occupiedTile1 || botTile == occupiedTile2 || botTile == occupiedTile3 || + leftTile == occupiedTile0 || leftTile == occupiedTile1 || leftTile == occupiedTile2 || leftTile == occupiedTile3 || + rightTile == occupiedTile0 || rightTile == occupiedTile1 || rightTile == occupiedTile2 || rightTile == occupiedTile3){ + + return true; + + + } + + if(heuristicMap[topTile] == 127 && obstacleMap[topTile]){ + nodes[endIndex + nodeCount] = topTile; + heuristicMap[topTile] = distance; + nodeCount++; + } + + if(heuristicMap[botTile] == 127 && obstacleMap[botTile]){ + nodes[endIndex + nodeCount] = botTile; + heuristicMap[botTile] = distance; + nodeCount++; + } + + if(heuristicMap[leftTile] == 127 && obstacleMap[leftTile]){ + nodes[endIndex + nodeCount] = leftTile; + heuristicMap[leftTile] = distance; + nodeCount++; + } + + if(heuristicMap[rightTile] == 127 && obstacleMap[rightTile]){ + nodes[endIndex + nodeCount] = rightTile; + heuristicMap[rightTile] = distance; + nodeCount++; + } + + + } + startIndex = endIndex; + endIndex+=nodeCount; + + } + + return false; + + } + + + +} diff --git a/core/Rect.java b/core/Rect.java new file mode 100644 index 0000000..74a1ad1 --- /dev/null +++ b/core/Rect.java @@ -0,0 +1,58 @@ +package core; + +import entity.solidObject; + +//this clase define a rectangle in Cartesian coordinate +public class Rect { + + public int x1,x2,y1,y2,width,height; + + public solidObject owner; + + public Rect(int x1, int y1, int width, int height){ + this.x1 = x1; + this.y1 = y1; + this.width = width; + this.height = height; + x2 = x1 + width - 1; + y2 = y1 - height + 1; + } + + public void setOrigin(int x1, int y1){ + this.x1 = x1; + this.y1 = y1; + x2 = x1 + width - 1; + y2 = y1 - height + 1; + } + + public boolean intersect(Rect r){ + return !(x1 > r.x2 || r.x1 > x2 || y2 > r.y1 || r.y2 > y1); + } + + public boolean contains(int x, int y){ + return x >= x1 && x <=x2 && y <= y1 && y >= y2; + } + + public void expand(int r){ + x1-=r; + x2+=r; + y1+=r; + y2-=r; + width+=2*r; + height+=2*r; + } + + public void shrink(int r){ + x1+=r; + x2-=r; + y1-=r; + y2+=r; + width-=2*r; + height-=2*r; + } + + public String toString(){ + return x1 + " " + y1 + " " + width + " " + height; + } + +} diff --git a/core/Ticker.java b/core/Ticker.java new file mode 100644 index 0000000..4f1677f --- /dev/null +++ b/core/Ticker.java @@ -0,0 +1,78 @@ +package core; + + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class Ticker implements Runnable{ + + ActionListener al; + private boolean isTicking; + Thread t; + int delay; + + public Ticker(int i, ActionListener actionlistener){ + al = actionlistener; + delay = i; + t = new Thread(this); + t.start(); + isTicking = false; + } + + public Ticker(int i){ + delay = i; + t = new Thread(this); + t.start(); + isTicking = false; + } + + public void addActionListener(ActionListener actionlistener){ + if(al == null) + al = actionlistener; + else + System.out.println("WARNING: ActionListener already added to Ticker."); + } + + public boolean isRunning(){ + return isTicking; + } + + public void start(){ + isTicking = true; + } + + public void stop() { + isTicking = false; + } + + public void setDelay(int i){ + delay = i; + } + + public int getDelay(){ + return delay; + } + + private void fireActionPerformed(){ + if(al == null || !isTicking){ + return; + } else{ + ActionEvent actionevent = new ActionEvent(this, 0, null); + al.actionPerformed(actionevent); + return; + } + } + + public void run(){ + do{ + fireActionPerformed(); + try{ + Thread.sleep(delay); + } + catch(InterruptedException interruptedexception){ + System.out.println("WARNING: Ticker thread interrupted."); + } + } while(true); + } +} + diff --git a/core/Turn2DTo3DFactory.java b/core/Turn2DTo3DFactory.java new file mode 100644 index 0000000..891af51 --- /dev/null +++ b/core/Turn2DTo3DFactory.java @@ -0,0 +1,75 @@ +package core; + +//takes a pixel position from a rasterized polygon and find its 3D location in world space + +public class Turn2DTo3DFactory { + + public vector O, U, V, W, A, B, C; + + public vector location3D; + + public float X, Y; + + public void init(){ + O = new vector(0,0,0); + U = new vector(0,0,0); + V = new vector(0,0,0); + W = new vector(0,0,0); + A = new vector(0,0,0); + B = new vector(0,0,0); + C = new vector(0,0,0); + location3D = new vector(0,0,0); + } + + public vector get3DLocation(polygon3D poly, int x, int y){ + O.set(poly.origin); + O.subtract(camera.position); + O.rotate_XZ(camera.XZ_angle); + O.rotate_YZ(camera.YZ_angle); + + U.set(poly.rightEnd); + U.subtract(camera.position); + U.rotate_XZ(camera.XZ_angle); + U.rotate_YZ(camera.YZ_angle); + + + + V.set(poly.bottomEnd); + V.subtract(camera.position); + V.rotate_XZ(camera.XZ_angle); + V.rotate_YZ(camera.YZ_angle); + + U.subtract(O); + U.unit(); + + V.subtract(O); + V.unit(); + + A.cross(V,O); + B.cross(O,U); + C.cross(U,V); + + W.set(x-384, -y + 256, 650); + + X = A.dot(W)/C.dot(W); + Y = B.dot(W)/C.dot(W); + + O.set(poly.origin); + U.set(poly.rightEnd); + V.set(poly.bottomEnd); + + U.subtract(O); + V.subtract(O); + + + X/=(U.getLength()); + Y/=(V.getLength()); + + location3D.set(O); + location3D.add(U, X); + location3D.add(V, Y); + + return location3D; + } + +} diff --git a/core/baseInfo.java b/core/baseInfo.java new file mode 100644 index 0000000..f905c84 --- /dev/null +++ b/core/baseInfo.java @@ -0,0 +1,93 @@ +package core; + +//store all the information about a base, eg current credit, number of structures , current power level, tech trees and etc... + +public class baseInfo { + public int numberOfPowerPlant; + public int numberOfConstructionYard; + public int numberOfRefinery; + public int numberOfFactory; + public int numberOfCommunicationCenter; + public int numberOfTechCenter; + public int numberOfGunTurret; + public int numberOfMissileTurret, numberOfOverChargedMissileTurret; + public boolean canBuildPowerPlant, canBuildRefinery, canBuildFactory, canBuildCommunicationCenter, canBuildTechCenter, canBuildGunTurret, canBuildMissileTurret; + public boolean canBuildLightTank, canBuildRocketTank, canBuildDrone, canBuildStealthTank, canBuildHeavyTank, canBuildMCV, canBuildHarvester; + + public int currentCredit; + public int currentPowerLevel; + public int currentPowerConsumption; + public int powerStatus; + public boolean lowPower; + + public baseInfo(){ + currentCredit = 5000; + + } + + public void update(){ + //update tech tree + canBuildPowerPlant = true; + canBuildRefinery = false; + canBuildFactory = false; + canBuildCommunicationCenter= false; + canBuildTechCenter = false; + canBuildGunTurret = false; + canBuildMissileTurret= false; + + canBuildLightTank = true; + canBuildRocketTank = true; + canBuildDrone = true; + canBuildHarvester = false; + canBuildMCV = false; + canBuildHeavyTank = false; + canBuildStealthTank = false; + + if(numberOfPowerPlant > 0){ + canBuildRefinery = true; + + } + + if(numberOfRefinery > 0){ + canBuildFactory = true; + canBuildHarvester = true; + } + + if(numberOfFactory > 0){ + canBuildCommunicationCenter = true; + canBuildGunTurret = true; + } + + if(numberOfCommunicationCenter > 0){ + canBuildMissileTurret = true; + canBuildTechCenter = true; + canBuildStealthTank = true; + canBuildMCV = true; + } + + if(numberOfTechCenter > 0){ + canBuildHeavyTank = true; + } + + + currentPowerLevel = numberOfPowerPlant*500 + numberOfConstructionYard*100; + currentPowerConsumption = numberOfRefinery*150 + numberOfFactory*200 + numberOfCommunicationCenter*250 + numberOfGunTurret*100 + numberOfMissileTurret*200 + numberOfOverChargedMissileTurret*150 + numberOfTechCenter*400; + + //calculate power level and power consumption + if(currentPowerLevel == 0){ + powerStatus = -1; + }else{ + powerStatus = currentPowerConsumption * 100 / currentPowerLevel; + } + if(powerStatus == -1 || powerStatus > 100) + lowPower = true; + else + lowPower = false; + + if(powerStatus != -1){ + powerStatus = currentPowerConsumption << 16 | currentPowerLevel; + } + + } + +} diff --git a/core/camera.java b/core/camera.java new file mode 100644 index 0000000..5614a90 --- /dev/null +++ b/core/camera.java @@ -0,0 +1,134 @@ +package core; + + +import java.awt.*; + +public class camera{ + public static vector position; + + public static vector view_Direction; + + public static vector left, right, left_, right_; + + public static boolean MOVE_LEFT, MOVE_RIGHT, MOVE_UP, MOVE_DOWN, TURN_LEFT, TURN_RIGHT; + + public static int XZ_angle, YZ_angle; + + public static float sinXZ_angle, cosXZ_angle, sinYZ_angle, cosYZ_angle; + + public static final vector viewDirection = new vector(0, 0, 1); + + //a rectangle that represents the screen area + public static final Rectangle screen = new Rectangle(0,0,768, 512); + + + public camera(vector p, int XZ, int YZ){ + view_Direction = new vector(0, 0, 1); + position = p; + XZ_angle = XZ; + YZ_angle = YZ; + + left = new vector(0,0,0); + right = new vector(0,0,0); + left_ = new vector(0, -1, 0); + right_ = new vector(0, 1, 0); + } + + public void update(){ + position.add(view_Direction.x*3, 0 , view_Direction.z*3); + + + if(TURN_RIGHT){ + XZ_angle+=1; + + + } + + if(TURN_LEFT){ + XZ_angle-=1; + } + + float x = position.x; + float z = position.z; + + if(MOVE_LEFT){ + left.cross(view_Direction, left_); + left.unit(); + position.add(left, -0.1f); + + + } + + if(MOVE_RIGHT){ + right.cross(view_Direction, right_); + right.unit(); + position.add(right, -0.1f); + + } + + if(MOVE_UP){ + vector up = new vector(view_Direction.x, 0, view_Direction.z); + up.unit(); + position.add(up, 0.1f); + } + + if(MOVE_DOWN){ + vector down = new vector(view_Direction.x, 0, view_Direction.z); + down.unit(); + position.add(down, -0.1f); + } + + //make sure the camera never leaves the map + if(position.x < 0.5){ + position.x = 0.5f; + + } + + if(position.z < 0.5){ + position.z = 0.5f; + + } + + if(position.x > 31.5){ + position.x = 31.5f; + + } + if(position.z > 31.5){ + position.z = 31.5f; + + } + + + + XZ_angle = (XZ_angle + 360) % 360; + YZ_angle = (YZ_angle + 360) % 360; + sinXZ_angle = gameData.sin[XZ_angle]; + cosXZ_angle = gameData.cos[XZ_angle]; + sinYZ_angle = gameData.sin[YZ_angle]; + cosYZ_angle = gameData.cos[YZ_angle]; + + + + view_Direction.set(viewDirection); + view_Direction.rotate_YZ(YZ_angle); + view_Direction.rotate_XZ(XZ_angle); + view_Direction.y*=-1; + view_Direction.x*=-1; + view_Direction.unit(); + + position.add(-view_Direction.x*3, 0 , -view_Direction.z*3); + + + MOVE_LEFT = false; + MOVE_RIGHT = false; + MOVE_UP = false; + MOVE_DOWN = false; + TURN_LEFT = false; + TURN_RIGHT = false; + + + + + } + +} \ No newline at end of file diff --git a/core/gameData.java b/core/gameData.java new file mode 100644 index 0000000..5e4956a --- /dev/null +++ b/core/gameData.java @@ -0,0 +1,196 @@ +package core; + +import java.awt.Image; +import java.awt.image.PixelGrabber; + +import javax.imageio.ImageIO; + +//Store useful arithmetic data for the game engine such as +//Cos/Sin look up table, color palette, etc... +public class gameData { + public static int[] random; + public static int randomIndex; + public static float[] sin; + public static float[] cos; + public static int[][] colorTable, colorTableTemp; + public static float[] intensityTable; + public static int[][] size; + public static byte[][] cloakTextures; + + public static String imageFolder = "../images/"; + + + public static void makeData(){ + + //Make random number table + random = new int[1024]; + for(int i = 0; i < 1024; i ++){ + random[i] = (int)(Math.random()*1024); + + } + + + //Make sin and cos look up tables + sin = new float[361]; + cos = new float[361]; + for(int i = 0; i < 361; i ++){ + sin[i] = (float)Math.sin(Math.PI*i/180); + cos[i] = (float)Math.cos(Math.PI*i/180); + } + + //make color palette. + //The main color palette has 32768 (15bits) different colors with 128 different intensity levels, + //the default intensity is at level 31 . + + if(colorTable == null) + colorTable = new int[128][32768]; + if(colorTableTemp == null) + colorTableTemp = new int[32768][128]; + + intensityTable = new float[128]; + + double r, g, b, dr, dg, db; + int r_, g_, b_; + + for(int i = 0; i < 32768; i++){ + r = (double)((i & 31744) >> 10)*8; + g = (double)((i & 992) >> 5)*8; + b = (double)((i & 31))*8; + + dr = r*0.75/64; + dg = g*0.75/64; + db = b*0.75/64; + + + + //calculated the intensity from lvl 0 ~ 63 + for(int j = 0; j < 64; j++){ + r_ = (int)(r-dr*j); + g_ = (int)(g-dg*j); + b_ = (int)(b-db*j); + + + colorTableTemp[i][63 - j] = b_ + (g_<<8)+ (r_<<16); + intensityTable[63 - j] = 1 - (0.75f/64)*j; + } + + + + dr = r*0.75/64; + dg = g*0.75/64; + db = b*0.75/64; + + + + double d = (dr + dg + db)/3; + + //calculated the intensity from lvl 64 ~ 127 + for(int j = 1; j <= 64; j++){ + r_ = (int)(r+d*j); + g_ = (int)(g+d*j); + b_ = (int)(b+d*j); + if(r_ > 255) + r_ = 255; + if(g_ > 255) + g_ = 255; + if(b_ > 255) + b_ = 255; + + + colorTableTemp[i][63 + j] = b_ + (g_<<8)+ (r_<<16); + intensityTable[63 + j] = 1 + (0.75f/64)*j; + } + } + + for(int i = 0; i < 128; i++){ + for(int j = 0; j <32768; j++ ) + colorTable[i][j] = colorTableTemp[j][i]; + } + + //free memory used for creating color table + colorTableTemp = null; + + + //create particle bitmap + size = new int[9][]; + size[0] = new int[]{0,-1, -768}; + size[1] = new int[]{-769,0,-1, -768}; + size[2] = new int[]{1, 0,-1, -768,768}; + size[3] = new int[]{-769,-767,1, 0,-1, -768,768}; + size[4] = new int[]{-769,-767,1, 0,-1, -768,768, 767, 769}; + size[5] = new int[]{-1536, -1537, -770,-769,-768, -767, -2, -1, 0, 1, 767, 768}; + size[6] = new int[]{-1537, -1535, -770,-766,766, 770,1535, 1537,-1536,-769,-2,-767,1, 2, 0,-1, -768,768, 767, 769, 1536}; + size[7] = new int[]{-1534, -1538, 1538, 1534, -2304, 2304, -3, 3, -1537, -1535, -770,-766,766, 770,1535, 1537,-1536,-769,-2,-767,1, 2, 0,-1, -768,768, 767, 769, 1536}; + size[8] = new int[]{0}; + + + //create cloack textures + cloakTextures= new byte[120][64*64]; + + int[] buffer = new int[64*64]; + + loadTexture("69.jpg", buffer, cloakTextures[0], 64, 64); + + loadTexture("70.jpg", buffer, cloakTextures[40], 64, 64); + + loadTexture("71.jpg", buffer, cloakTextures[80], 64, 64); + + for(int i = 1; i < 40; i++){ + for(int j = 0; j < 64*64; j++){ + cloakTextures[i][j] = (byte)(cloakTextures[0][j] + (cloakTextures[40][j] - cloakTextures[0][j])* i / 40); + cloakTextures[40 + i][j] = (byte)(cloakTextures[40][j] + (cloakTextures[80][j] - cloakTextures[40][j])* i / 40); + cloakTextures[80 + i][j] = (byte)(cloakTextures[80][j] + (cloakTextures[0][j] - cloakTextures[80][j])* i / 40); + } + } + + + + + System.gc(); + + } + + //get a random number + public static int getRandom(){ + randomIndex++; + if(randomIndex >= 1024) + randomIndex=0; + return random[randomIndex]; + + } + + + + //It frees the data stored when the applet is finished + public static void destory(){ + random = null; + sin = null; + cos = null; + colorTable = null; + } + + public static void loadTexture(String imgName, int[] buffer, byte[] dest, int width, int height){ + Image img = null; + try{ + img = ImageIO.read(gameData.class.getResource(imageFolder + imgName)); + }catch(Exception e){ + e.printStackTrace(); + } + + + PixelGrabber pg = new PixelGrabber(img, 0, 0, width, height, buffer, 0, width); + try { + pg.grabPixels(); + }catch(Exception e){ + e.printStackTrace(); + } + + for(int i = 0; i < buffer.length; i++){ + dest[i] = (byte)((buffer[i]&255)/2); + + } + + } + + +} diff --git a/core/geometry.java b/core/geometry.java new file mode 100644 index 0000000..0367ac2 --- /dev/null +++ b/core/geometry.java @@ -0,0 +1,205 @@ +package core; + +//determine the drawing orders for polygons and models +public class geometry { + + public static vector temp = new vector(0,0,0); + public static vector temp1 = new vector(0,0,0); + public static vector temp2 = new vector(0,0,0); + + //solutions for liner equation + // a1 * X + b1 * Y = c1 + // a2 * X + b2 * Y = c2 + public static float X, Y; + + + //solve liner equation with 2 variables + public static void solveLinerEquation2D(float a1, float a2, float b1, float b2, float c1, float c2){ + if(a1 != 0){ + Y = (c2 - a2*c1/a1)/(b2 - a2*b1/a1); + X = (c1 - b1*Y)/a1; + }else{ + float a, b, c; + a = a1; + a1 = a2; + a2 = a; + + b = b1; + b1 = b2; + b2 = b; + + c = c1; + c1 = c2; + c2 = c; + + Y = (c2 - a2*c1/a1)/(b2 - a2*b1/a1); + X = (c1 - b1*Y)/a1; + } + } + + + //find angle between 2 point with respect to the positive y axis + public static int findAngle(float x0, float y0, float x1, float y1){ + + return (int)(Math.atan2(-(x1 - x0), -(y1 - y0))/Math.PI * 180) + 180; + } + + //find the direction of rotation between 2 angles + public static int findAngleDelta(int start, int finish,int maxTurnRate){ + int difference = finish - start; + + + + if(difference < 0){ + if(difference < -180){ + if(difference < -360 + maxTurnRate) + return 360 + difference; + else + return maxTurnRate; + }else{ + if(difference > -maxTurnRate) + return difference; + else + return -maxTurnRate; + } + + }else{ + if(difference > 180){ + if(difference > 360 - maxTurnRate) + return difference - 360; + else + return -maxTurnRate; + }else{ + if(difference < maxTurnRate) + return difference; + else + return maxTurnRate; + } + + } + } + + //draw dot line + public static void drawLine(vector startPoint, vector endPoint, int color, byte shadowBit){ + + int[] screen = mainThread.screen; + + temp1.set(startPoint); + temp1.y = -0.5f; + temp1.x -= 0.07f; + temp1.subtract(camera.position); + temp1.rotate_XZ(camera.XZ_angle); + temp1.rotate_YZ(camera.YZ_angle); + + temp2.set(endPoint); + temp2.y = -0.5f; + temp2.subtract(camera.position); + temp2.rotate_XZ(camera.XZ_angle); + temp2.rotate_YZ(camera.YZ_angle); + + if(temp1.z < 1f && temp2.z < 1f) + return; + + + if(temp1.z < 1f){ + float f = (temp2.z - 1)/(temp2.z - temp1.z); + temp.set(temp1); + temp.subtract(temp2); + temp.scale(f); + temp1.set(temp2); + temp1.add(temp); + + } + temp1.updateLocation(); + + + + if(temp2.z < 1f){ + float f = (temp1.z - 1)/(temp1.z - temp2.z); + temp.set(temp2); + temp.subtract(temp1); + temp.scale(f); + temp2.set(temp1); + temp2.add(temp); + } + temp2.updateLocation(); + + int xPos1 = (int)temp1.screenX; + int yPos1 = (int)temp1.screenY; + + + int xPos2 = (int)temp2.screenX; + int yPos2 = (int)temp2.screenY; + + int start = 0; + int x, y; + int xDirection, yDirection; + + if(xPos1 < xPos2) + xDirection = 1; + else + xDirection = -1; + + if(yPos1 < yPos2) + yDirection = 1; + else + yDirection = -1; + + if(Math.abs(xPos2 - xPos1) > Math.abs(yPos2 - yPos1)){ + float slope = (float)(yPos2 - yPos1)/(xPos2 - xPos1); + for(int i = 0; i <= Math.abs(xPos2 - xPos1); i ++){ + x = xPos1 + i*xDirection; + y = (int)(yPos1 + slope*i*xDirection); + + if(x <0 || x > 767 || y < 0 || y > 511) + continue; + + + screen[start + x + y*768] = color; + mainThread.shadowBitmap[start + x + y*768] = shadowBit; + } + + }else{ + float slope = (float)(xPos2 - xPos1)/(yPos2 - yPos1); + for(int i = 0; i <= Math.abs(yPos2 - yPos1); i ++){ + y = yPos1 + i*yDirection; + x = (int)(xPos1 + slope*i*yDirection); + + if(x <0 || x > 767 || y < 0 || y > 511) + continue; + + screen[start + x + y*768] = color; + mainThread.shadowBitmap[start + x + y*768] = shadowBit; + + + } + } + + + + + int index; + for(int j = 0; j < 5; j++){ + for(int k = 0; k < 5; k++){ + int xPos = xPos2 - 2 + k; + int yPos = yPos2 - 2 + j; + if(xPos < 0 || xPos > 767 || yPos < 0 || yPos > 511) + continue; + + index = xPos + yPos*768; + + if(index >= 0 && index < 512*768){ + screen[index] = color; + mainThread.shadowBitmap[index] = shadowBit; + } + + } + } + + + + + + } + +} diff --git a/core/grid.java b/core/grid.java new file mode 100644 index 0000000..91b7a68 --- /dev/null +++ b/core/grid.java @@ -0,0 +1,60 @@ +package core; + +import entity.*; + +public class grid { + + public int size; + public solidObject[][] tiles; //a list of colliable objects, used by local path finding + public boolean[] previousObstacleMap, currentObstacleMap; //a boolean representation of the collideble objects, used by A star + + public grid(int size){ + this.size = size; + tiles = new solidObject[size * size][5]; + + previousObstacleMap = new boolean[size * size]; + currentObstacleMap = new boolean[size * size]; + + for(int i = 0; i < size * size; i++){ + previousObstacleMap[i] = true; + currentObstacleMap[i] = true; + } + + } + + public void update(){ + int l = size * size; + for(int i = 0; i < l; i++){ + previousObstacleMap[i] = currentObstacleMap[i]; + currentObstacleMap[i] = true; + } + + for(int i = 0; i < size; i++){ + currentObstacleMap[i] = false; + currentObstacleMap[l - 1 - i] = false; + currentObstacleMap[i * 128] = false; + currentObstacleMap[(i+1) * 128 - 1] = false; + } + } + + + + + public void draw(){ + int pos = 2 + 20 * 768; + boolean tile; + int[] screen = mainThread.screen2; + for(int i = 0; i < 128; i++){ + for(int j = 0; j < 128; j++){ + tile = previousObstacleMap[j + i*128]; + if(!tile) + screen[pos + j + i*768] = 0; + + } + } + } + + +} + + diff --git a/core/mainThread.java b/core/mainThread.java new file mode 100644 index 0000000..83b31a4 --- /dev/null +++ b/core/mainThread.java @@ -0,0 +1,526 @@ +package core; + +//Java real time strategy + +import java.awt.*; +import java.awt.event.*; +import java.awt.image.*; + +import javax.imageio.ImageIO; +import javax.swing.JFrame; +import javax.swing.JPanel; + +import enemyAI.*; +import gui.*; + +public class mainThread extends JFrame implements KeyListener, ActionListener, MouseMotionListener, MouseListener, FocusListener{ + + public static int[] screen; + public static int[] screen2; + public static int[] zBuffer; + public static int[] zBuffer2; + public static BufferedImage doubleBuffer; + public static BufferedImage doubleBuffer2; + public static BufferedImage bf; + public static Ticker t; + public static int frameInterval; + public static int frameIndex; + public static long lastDraw; + public static int sleepTime; + public static int framePerSecond, cpuUsage; + public static double thisTime, lastTime; + public static boolean JavaRTSLoaded; + public static boolean inGame; + public static texture[] textures; + public static byte[][] lightMapTextures; + public static int[][] lightMapTexturesInfo; + public static camera Camera; + public static playerCommander pc; + public static enemyCommander ec; + public static AssetManager theAssetManager; + public static grid gridMap; + public static postProcessingThread PPT; + public static Object PPT_Lock; + public static JPanel panel; + public static Turn2DTo3DFactory my2Dto3DFactory; + public static byte[] shadowBitmap; + public static byte[] shadowBitmap2; + + public static short[] displacementBuffer; + public static short[] displacementBuffer2; + + + + public mainThread(){ + setTitle("JAVA RTS"); + panel= (JPanel) this.getContentPane(); + panel.setPreferredSize(new Dimension(768, 512)); + panel.setMinimumSize(new Dimension(768,512)); + panel.setLayout(null); + + setResizable(false); + pack(); + setVisible(true); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + setLocation(dim.width/2-this.getSize().width/2, dim.height/2-this.getSize().height/2); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + + + + //load resource if the applet is loaded for the first time. (i.e refresh browser will not cause the applet to load resources again) + if(JavaRTSLoaded == false){ + //create screen buffer + doubleBuffer = new BufferedImage(768, 512, BufferedImage.TYPE_INT_RGB); + DataBuffer dest = doubleBuffer.getRaster().getDataBuffer(); + screen = ((DataBufferInt)dest).getData(); + + doubleBuffer2 = new BufferedImage(768, 512, BufferedImage.TYPE_INT_RGB); + DataBuffer dest2 = doubleBuffer2.getRaster().getDataBuffer(); + screen2 = ((DataBufferInt)dest2).getData(); + + //create depth buffer + zBuffer = new int[393216]; + zBuffer2 = new int[393216]; + + //create shadoow bitmap + shadowBitmap = new byte[393216]; + shadowBitmap2 = new byte[393216]; + + for(int i = 0; i < 393216; i++){ + shadowBitmap[i] = 127; + shadowBitmap2[i] = 127; + } + + //create displacement buffer + displacementBuffer = new short[393216]; + displacementBuffer2 = new short[393216]; + for(int i = 0; i < 393216; i++){ + displacementBuffer[i] = 12345; + + } + + //create camera + Camera = new camera(new vector(3,2f,-1.25f), 0, 300); + + //Create look up tables + gameData.makeData(); + + //init grid + gridMap = new grid(128); + + //init light source + sunLight.init(); + + //init rasterizer + rasterizer.init(); + + //init 2d to 3d factory + my2Dto3DFactory = new Turn2DTo3DFactory(); + my2Dto3DFactory.init(); + + loadTexture(); + + //init post processing thread + postProcessingThread.init(); + + theAssetManager = new AssetManager(); + theAssetManager.init(); + + frameIndex = 0; + frameInterval = 33; + lastDraw = 0; + + JavaRTSLoaded = true; + + //test only + inGame = true; + } + + + + //Add key handler + panel.addKeyListener(this); + panel.addMouseMotionListener(this); + panel.addMouseListener(this); + panel.addFocusListener(this); + panel.requestFocus(); + + //create main thread + t = new Ticker(0); + t.addActionListener(this); + + //create a daemon thread which will sleep for the duration of the game + Thread dt = new Thread(new DaemonThread() ); + dt.setDaemon(true); + + + //create another thread to create post processing effects + PPT_Lock = new Object(); + PPT = new postProcessingThread(); + Thread theTread = new Thread(PPT); + + //start threads + t.start(); + dt.start(); + theTread.start(); + + + } + + + //This method is called every time the ticker ticks. To take advantage of modern multicore cpu, + //The graphic engine does polygon rasterization on the main thread and post processing stuff (explosion, + //smokes, user interface etc...) on a second thread. One draw back is that the post processing + //thread is always lag the main thread by 1 frame. However it is barely noticeable. + + public void actionPerformed(ActionEvent e){ + frameIndex++; + + inputHandler.processInput(); + + //handle user's interaction with game GUI + if(frameIndex == 1){ + theAssetManager.prepareAssetForNewGame(); + } + + gridMap.update(); + + + + //Clears the z-buffer. All depth values are set to 0. + clearDepthBuffer(); + + //update camera + Camera.update(); + + //update light source + sunLight.update(); + + //update and draw 3D mashes from game objects + theAssetManager.updateAndDraw(); + + pc.update(); + ec.update(); + + + + //gridMap.draw(); + + if(this.getGraphics() != null && PPT!= null){ + //wait for the Post processing Thread if it is still working + waitForPostProcessingThread(); + + //prepare resources for the post processing thread + postProcessingThread.prepareResources(); + + //Signal post processing thread that it can proceed + synchronized(PPT) { + PPT.notify(); + } + + if(frameIndex %2 == 0 && frameIndex > 3){ + bf = doubleBuffer; + paintComponent(panel.getGraphics()); + }else if(frameIndex != 1 && frameIndex > 3){ + bf = doubleBuffer2; + paintComponent(panel.getGraphics()); + } + + swapResources(); + + //maintain a constant frame rate + regulateFramerate(); + }else{ + System.exit(-1); + } + } + + public void paintComponent(Graphics g){ + + //copy the pixel information to the video memory + Graphics2D g2 =(Graphics2D)bf.getGraphics(); //(Graphics2D)g; + + //display polygon count and frame rate + g2.setColor(Color.WHITE); + g2.drawString("FPS: " + framePerSecond + " " + "Polygons: " + theAssetManager.polygonCount + " " + "Thread1 Sleep: " + sleepTime + "ms " + "Thread2 Sleep: " + postProcessingThread.sleepTime + "ms " , 5, 15); + + //copy the screen buffer to video memory + g.drawImage(bf, 0, 0, this); + } + + + + + public void clearDepthBuffer(){ + zBuffer[0] = 0; + for(int i = 1; i < 393216; i+=i) + System.arraycopy(zBuffer, 0, zBuffer, i, 393216 - i >= i ? i : 393216 - i); + } + + + //read keyboard inputs + public void keyPressed(KeyEvent e){ + + if(e.getKeyCode() == KeyEvent.VK_LEFT) + inputHandler.leftKeyPressed = true; + else if(e.getKeyCode() == KeyEvent.VK_RIGHT) + inputHandler.rightKeyPressed = true; + else if(e.getKeyCode() == KeyEvent.VK_CONTROL) + inputHandler.controlKeyPressed = true; + + inputHandler.readCharacter(e.getKeyChar()); + + } + + public void keyReleased(KeyEvent e){ + if(e.getKeyCode() == KeyEvent.VK_LEFT) + inputHandler.leftKeyPressed = false; + else if(e.getKeyCode() == KeyEvent.VK_RIGHT) + inputHandler.rightKeyPressed = false; + else if(e.getKeyCode() == KeyEvent.VK_CONTROL) + inputHandler.controlKeyPressed = false; + + inputHandler.handleKeyRelease(e.getKeyChar()); + } + + + + public void keyTyped(KeyEvent e) { + + + } + + + + public void mouseDragged(MouseEvent e) { + inputHandler.mouse_x = e.getX(); + inputHandler.mouse_y = e.getY(); + + } + + + public void mouseMoved(MouseEvent e) { + inputHandler.mouse_x = e.getX(); + inputHandler.mouse_y = e.getY(); + + } + + + @Override + public void mouseClicked(MouseEvent arg0) {} + + + @Override + public void mouseEntered(MouseEvent arg0) { + inputHandler.mouseIsInsideScreen = true; + } + + + @Override + public void mouseExited(MouseEvent arg0) { + inputHandler.mouseIsInsideScreen = false; + } + + + @Override + public void mousePressed(MouseEvent e) { + if(e.getButton() == 1){ + inputHandler.leftMouseButtonPressed = true; + + } + + if(e.getButton() == 3){ + inputHandler.rightMouseButtonPressed = true; + } + + } + + + @Override + public void mouseReleased(MouseEvent e) { + if(e.getButton() == 1){ + + inputHandler.leftMouseButtonReleased = true; + } + + if(e.getButton() == 3){ + inputHandler.rightMouseButtonReleased = true; + } + + } + + public void loadTexture(){ + textures = new texture[73]; + String imageFolder = "../images/"; + try{ + textures[0] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "1.jpg")), 9, 9); + textures[1] = new texture("explosion aura", ImageIO.read(getClass().getResource(imageFolder + "2.jpg")), 7, 7); + textures[2] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "3.jpg")), 6, 6); + textures[3] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "4.jpg")), 8, 6); + textures[4] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "5.jpg")), 7, 7); + textures[5] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "6.jpg")), 5, 7); + textures[6] = new texture("explosion", ImageIO.read(getClass().getResource(imageFolder + "7.jpg")), 8, 8); + textures[7] = new texture("explosion", ImageIO.read(getClass().getResource(imageFolder + "8.jpg")), 8, 8); + textures[8] = new texture("explosion", ImageIO.read(getClass().getResource(imageFolder + "9.jpg")), 8, 8); + textures[9] = new texture("explosion", ImageIO.read(getClass().getResource(imageFolder + "10.jpg")), 8, 8); + textures[10] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "12.jpg")), 6, 6); + textures[11] = new texture("smoke", ImageIO.read(getClass().getResource(imageFolder + "11.jpg")), 9, 9); + textures[12] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "13.jpg")), 7, 7); + textures[13] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "14.jpg")), 7, 7); + textures[14] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "15.jpg")), 5, 5); + textures[15] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "16.jpg")), 5, 5); + textures[16] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "17.jpg")), 5, 5); + textures[17] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "18.jpg")), 7, 7); + textures[18] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "19.jpg")), 6, 6); + textures[19] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "20.jpg")), 6, 6); + textures[20] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "21.jpg")), 6, 6); + textures[21] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "22.jpg")), 6, 6); + textures[22] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "23.jpg")), 6, 6); + textures[23] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "25.jpg")), 6, 6); + textures[24] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "24.jpg")), 5, 5); + textures[25] = new texture("solid color", 160 << 16 | 160 << 8 | 160, 5, 5); + textures[26] = new texture("solid color", 80 << 16 | 80 << 8 | 80, 5, 5); + textures[27] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "26.jpg")), 5, 5); + textures[28] = new texture("solid color", 173 << 16 | 161 << 8 | 89, 5, 5); + textures[29] = new texture("solid color", 200 << 16 | 200 << 8 | 200, 5, 5); + textures[30] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "27.jpg")), 8, 8); + textures[31] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "28.jpg")), 6, 6); + textures[32] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "29.jpg")), 6, 6); + textures[33] = new texture("solid color", 130 << 16 | 130 << 8 | 130, 5, 5); + textures[34] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "30.jpg")), 7, 7); + textures[35] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "31.jpg")), 7, 7); + textures[36] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "32.jpg")), 7, 7); + textures[37] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "33.jpg")), 7, 7); + textures[38] = new texture("heightmap", ImageIO.read(getClass().getResource(imageFolder + "34.jpg")), 8, 8); + textures[39] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "35.jpg")), 8, 8); + textures[40] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "36.jpg")), 7, 7); + textures[41] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "37.jpg")), 8, 8); + textures[42] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "38.jpg")), 6, 6); + textures[43] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "39.jpg")), 6, 6); + textures[44] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "40.jpg")), 5, 5); + textures[45] = new texture("solid color", 0 << 16 | 131 << 8 | 243, 5, 5); + textures[46] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "41.jpg")), 5, 5); + textures[47] = new texture("solid color", 50 << 16 | 50 << 8 | 50, 5, 5); + textures[48] = new texture("solid color", 149 << 16 | 137 << 8 | 97, 5, 5); + textures[49] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "42.jpg")), 6, 6); + textures[50] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "43.jpg")), 5, 5); + textures[51] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "45.jpg")), 8, 8); + textures[52] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "46.jpg")), 7, 7); + textures[53] = new texture("solid color", 179 << 16 | 0 << 8 | 0, 5, 5); + textures[54] = new texture("water", ImageIO.read(getClass().getResource(imageFolder + "51.jpg")), ImageIO.read(getClass().getResource(imageFolder + "90.jpg")), 8, 8); + textures[55] = new texture("heightmap", ImageIO.read(getClass().getResource(imageFolder + "52.jpg")), 8, 8); + textures[56] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "53.jpg")), 7, 7); + textures[57] = new texture("heightmap", ImageIO.read(getClass().getResource(imageFolder + "54.jpg")), 8, 8); + textures[58] = new texture("heightmap", ImageIO.read(getClass().getResource(imageFolder + "55.jpg")), 8, 8); + textures[59] = new texture("heightmap", ImageIO.read(getClass().getResource(imageFolder + "56.jpg")), 8, 8); + textures[60] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "61.jpg")), 4, 7); + textures[61] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "62.jpg")), 7, 7); + textures[62] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "63.jpg")), 7, 7); + textures[63] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "64.jpg")), 5, 7); + textures[64] = new texture("solid color", 56 << 16 |79 << 8 | 167, 5, 5); + textures[65] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "68.jpg")), 8, 8); + textures[66] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "73.jpg")), 6, 6); + textures[67] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "74.jpg")), 6, 6); + textures[68] = new texture("solid color", 255 << 16 | 255 << 8 | 255, 5, 5); + textures[69] = new texture("solid color", 255 << 16 | 0 << 8 | 0, 5, 5); + textures[70] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "80.jpg")), 5, 5); + textures[71] = new texture("basic", ImageIO.read(getClass().getResource(imageFolder + "82.jpg")), 6, 6); + textures[72] = new texture("solid color", 120 << 16 | 120 << 8 | 100, 5, 5); + + for(int i = 0; i < textures.length; i++) + textures[i].ID = i; + + }catch(Exception e){ + e.printStackTrace(); + } + + + } + + public void waitForPostProcessingThread(){ + //wait till post processing thread finishes + synchronized(PPT_Lock) { + while(PPT.isWorking()){ + + try { + PPT_Lock.wait(); + + } catch (InterruptedException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + } + } + + + public void swapResources(){ + int[] s; + s = screen; + screen = screen2; + screen2 = s; + + int[] buffer; + buffer = zBuffer; + zBuffer = zBuffer2; + zBuffer2 = buffer; + + byte[] b; + b = shadowBitmap; + shadowBitmap = shadowBitmap2; + shadowBitmap2 = b; + + short[] Dbuffer; + Dbuffer = displacementBuffer; + displacementBuffer = displacementBuffer2; + displacementBuffer2 = Dbuffer; + + rasterizer.screen = mainThread.screen; + rasterizer.shadowBitmap = mainThread.shadowBitmap; + rasterizer.zBuffer = mainThread.zBuffer; + rasterizer.displacementBuffer = mainThread.displacementBuffer; + + theAssetManager.swapResources(); + pc.theSideBarManager.swapResources(); + + } + + public void regulateFramerate(){ + if(frameIndex%30==0){ + double thisTime = System.currentTimeMillis(); + framePerSecond = (int)(1000/((thisTime - lastTime)/30)); + lastTime = thisTime; + } + sleepTime = 0; + while(System.currentTimeMillis()-lastDraw= 0){ + visibleInLightSpace = false; + return; + } + + + //translate vertex from world space to light space + float x = 0,y = 0, z = 0, + sunX = sunLight.position.x, sunY = sunLight.position.y, sunZ = sunLight.position.z, + sinXZ = sunLight.sinXZ_angle, + cosXZ = sunLight.cosXZ_angle, + sinYZ = sunLight.sinYZ_angle, + cosYZ = sunLight.cosYZ_angle; + + + for(int i = 0; i < L; i++){ + tempVector5 = vertex3D[i]; + tempVector6 = vertex2D[i]; + + //shifting + x = tempVector5.x - sunX; + y = tempVector5.y - sunY; + z = tempVector5.z - sunZ; + + //rotating + tempVector6.x = cosXZ*x - sinXZ*z; + tempVector6.z = sinXZ*x + cosXZ*z; + + z = tempVector6.z; + + tempVector6.y = cosYZ*y - sinYZ*z; + tempVector6.z = sinYZ*y + cosYZ*z; + tempVector6.updateLocationOrthognal(); + tempVector6.z_lightspace = tempVector6.z; + + tempVector5.z_lightspace = tempVector6.z; + tempVector5.screenX_lightspace = tempVector6.screenX_lightspace; + tempVector5.screenY_lightspace = tempVector6.screenY_lightspace; + } + + if(type == 1){ + rasterizer.renderShadow(this); + }else{ + if(type == 4) + rasterizer.renderShadowRemover(this); + else if(type == 9) + rasterizer.renderCloakedShadow(this); + } + + } + + public void update_lightspace_withoutDrawing(){ + //back face culling + visibleInLightSpace = true; + if(sunLight.lightDirection.dot(normal) > 0){ + visibleInLightSpace = false; + return; + } + + //translate vertex from world space to light space + float x = 0,y = 0, z = 0, + sunX = sunLight.position.x, sunY = sunLight.position.y, sunZ = sunLight.position.z, + sinXZ = sunLight.sinXZ_angle, + cosXZ = sunLight.cosXZ_angle, + sinYZ = sunLight.sinYZ_angle, + cosYZ = sunLight.cosYZ_angle; + + for(int i = 0; i < L; i++){ + //shifting + x = vertex3D[i].x - sunX; + y = vertex3D[i].y - sunY; + z = vertex3D[i].z - sunZ; + + //rotating + vertex2D[i].x = cosXZ*x - sinXZ*z; + vertex2D[i].z = sinXZ*x + cosXZ*z; + + z = vertex2D[i].z; + + vertex2D[i].y = cosYZ*y - sinYZ*z; + vertex2D[i].z = sinYZ*y + cosYZ*z; + vertex2D[i].updateLocationOrthognal(); + vertex2D[i].z_lightspace = vertex2D[i].z; + + vertex3D[i].z_lightspace = vertex2D[i].z; + vertex3D[i].screenX_lightspace = vertex2D[i].screenX_lightspace; + vertex3D[i].screenY_lightspace = vertex2D[i].screenY_lightspace; + } + } + + + + + + //clipping + public void findClipping(){ + visibleCount = 0; + //the clipping algorithm iterate through all the vertex of the polygons, if it finds + //a vertex which is behind the clipping plane(z = 0.001), then generate 2 new vertex on the + //clipping plane + + for(int i = 0; i < L; i++){ + if(tempVertex[i].z >= 0.1){ + vertex2D[visibleCount].set(tempVertex[i]); + vertex2D[visibleCount].updateLocation(); + visibleCount++; + } else{ + int index = (i+L - 1)%L; + if(tempVertex[index].z >= 0.1005){ + approximatePoint(visibleCount, tempVertex[i], tempVertex[index]); + visibleCount++; + } + index = (i+1)%L; + if(tempVertex[index].z >= 0.1005){ + approximatePoint(visibleCount, tempVertex[i], tempVertex[index]); + visibleCount++; + } + } + } + } + + //find the approximate projection point on the clipping plane + public void approximatePoint(int index, vector behindPoint, vector frontPoint){ + tempVector1.set(frontPoint.x - behindPoint.x, frontPoint.y - behindPoint.y, frontPoint.z - behindPoint.z); + tempVector1.scale((frontPoint.z- 0.1f)/tempVector1.z); + vertex2D[index].set(frontPoint.x, frontPoint.y, frontPoint.z); + vertex2D[index].subtract(tempVector1); + vertex2D[index].updateLocation(); + } + + + + //find diffuse intensity of this polygon + public void findDiffuse(){ + //calculate the diffuse intensity from the light source + tempVector1.set(-lightDirection.x, -lightDirection.y, -lightDirection.z); + double I = normal.dot(tempVector1); + + diffuse_I = Ambient_I + (int)(I*reflectance); + + if(I < 0) + diffuse_I = Ambient_I; + + } + + //create a smooth 1 dimensional shade map for the polygon. Only works if the polygon belongs to a + //cylindrical object. + public void createShadeSpan(vector theCenter, vector v0, vector v1){ + smoothShading = true; + + tempVector1.set(v0); + tempVector1.subtract(theCenter); + tempVector1.unit(); + tempVector2.set(v1); + tempVector2.subtract(theCenter); + tempVector2.unit(); + + tempVector3.set(-lightDirection.x, -lightDirection.y, -lightDirection.z); + + I_left = tempVector1.dot(tempVector3)*reflectance + Ambient_I; + if(I_left < Ambient_I) + I_left = Ambient_I; + + I_right = tempVector2.dot(tempVector3)*reflectance + Ambient_I; + if(I_right < Ambient_I) + I_right = Ambient_I; + + I_difference = (I_right - I_left)/textureScaledWidth; + } + + public void findNormal(){ + tempVector1.set(vertex3D[1]); + tempVector1.subtract(vertex3D[0]); + tempVector2.set(vertex3D[2]); + tempVector2.subtract(vertex3D[1]); + normal.cross(tempVector1, tempVector2); + normal.unit(); + + } + + public void draw(){ + //send this polygon to rasterizer + if(visible){ + mainThread.theAssetManager.polygonCount++; + rasterizer.rasterize(this); + } + } +} diff --git a/core/postProcessingThread.java b/core/postProcessingThread.java new file mode 100644 index 0000000..afbf003 --- /dev/null +++ b/core/postProcessingThread.java @@ -0,0 +1,965 @@ +package core; + +import entity.*; +import gui.MiniMap; +import gui.SideBar; +import gui.confirmationIcon; +import particles.explosion; +import particles.helix; +import particles.smokeParticle; + +//this class handles all the post processing effect +public class postProcessingThread implements Runnable{ + + public static int[] currentScreen; + public static int[] currentZbuffer; + public static int[][] currentSelectedUnitsInfo; + public static int[][] unitInfoTable; + public static float[][] visionPolygonInfo; + public static float[][] explosionInfo; + public static float[][] helixInfo; + public static int visionPolygonCount; + public static int visibleUnitCount; + public static int explosionCount; + public static int helixCount; + + public static boolean[] minimapBitmap; + + public static float[][] smokeEmmiterList; + public static int smokeEmmiterCount; + + public static int[][] unitsForMiniMap; + public static int unitsForMiniMapCount; + + public static MiniMap theMiniMap; + public static SideBar theSideBar; + + private boolean isWorking; + public static int sleepTime; + + public static byte[] fogOfWarBuffer; + public static byte[] fogOfWarBuffer2; + + public static byte[] shadowBitmap; + public static byte[] smoothedShadowBitmap; + public static short[] displacementBuffer; + public static int[] offScreen; + + //2 arrays that define the scan lines of the polygon + public static int[] xLeft = new int[512], xRight = new int[512]; + public static int[] xMin = new int[512], xMax = new int[512]; + + public static vector cameraPosition = new vector(0,0,0); + public static float sinXZ,cosXZ,sinYZ,cosYZ ; + public static int cameraXZAngle; + + public static Turn2DTo3DFactory my2Dto3DFactory; + + public static explosion[] explosions; + + public static smokeParticle[] smokeParticles; + public int currentParticleIndex; + + public static helix[] railgunHelix; + public int currentHelix; + + public static int[] sideBarInfo; + + public static confirmationIcon theConfirmationIcon; + + public static double[] confirmationIconInfo; + + public static textRenderer theTextRenderer; + + //A pool of vectors which will be used for vector arithmetic + public static vector + tempVector1 = new vector(0,0,0), + tempVector2 = new vector(0,0,0), + tempVector3 = new vector(0,0,0), + tempVector4 = new vector(0,0,0); + + //the polygon that post processing filter is working on + public static polygon3D poly; + + //these variables will represent their equivalents in the polygon3D class during rasterization + public static vector[] vertex2D; + + + //temporary variables that will be used in texture mapping + public static float aDotW, bDotW, cDotW, cDotWInverse, w, textureHeight, textureWidth; + public static int BigX, BigY, d_x, d_y, k, X1, Y1, BigDx, BigDy, dx, dy, dz, X, Y, textureIndex, temp, temp1, temp2, temp3, r,g,b, scale, yOffset, xOffset, x_right, x_left, z_left, z_right, start, end, teamNo, type; + + + //the amount of vertex after clipping + public static int visibleCount; + + //the number of avaliable credit for player commander + public static int playerMoney; + + //the power status for player commander + public static int playerPowerStatus; + + //frame counter + public static int frameIndex; + + public static vector lightReflect; + public static vector eyeDirection; + + public static void init(){ + //create font bitmaps + theTextRenderer = new textRenderer(); + theTextRenderer.init(); + + + fogOfWarBuffer = new byte[512 * 768]; + fogOfWarBuffer2 = new byte[512 * 768]; + + smoothedShadowBitmap = new byte[512 * 768]; + + offScreen = new int[512*768]; + + //init minimap hud + theMiniMap = new MiniMap(); + theMiniMap.init(); + + //init sidebar interface + theSideBar = new SideBar(); + theSideBar.init(); + + + unitInfoTable = new int[201][4]; + + // Max health Health_bar Length Health_bar Xpos Health_bar yPos + unitInfoTable[0] = new int[]{lightTank.maxHP, 44, -22, -25}; + unitInfoTable[1] = new int[]{rocketTank.maxHP, 44, -22, -36}; + unitInfoTable[2] = new int[]{harvester.maxHP, 58, -29, -46}; + unitInfoTable[3] = new int[]{constructionVehicle.maxHP, 58, -29, -40}; + unitInfoTable[6] = new int[]{stealthTank.maxHP, 44, -22, -30}; + unitInfoTable[7] = new int[]{heavyTank.maxHP, 58, -29, -37}; + unitInfoTable[101] = new int[]{powerPlant.maxHP, 88, -37, -80}; + unitInfoTable[102] = new int[]{refinery.maxHP, 132, -65, -130}; + unitInfoTable[103] = new int[]{goldMine.maxHP, 100, -49, -80}; + unitInfoTable[104] = new int[]{constructionYard.maxHP, 132, -65, -130}; + unitInfoTable[105] = new int[]{factory.maxHP, 132, -65, -130}; + unitInfoTable[106] = new int[]{communicationCenter.maxHP, 88, -37, -70}; + unitInfoTable[107] = new int[]{techCenter.maxHP, 88, -37, -115}; + unitInfoTable[199] = new int[]{missileTurret.maxHP, 44, -22, -20}; + unitInfoTable[200] = new int[]{gunTurret.maxHP, 44, -22, -35}; + + my2Dto3DFactory = new Turn2DTo3DFactory(); + my2Dto3DFactory.init(); + + explosions = new explosion[200]; + for(int i = 0; i < 200; i++) + explosions[i] = new explosion(); + + + smokeParticles = new smokeParticle[2000]; + for(int i = 0; i < 2000; i++) + smokeParticles[i] = new smokeParticle(); + + railgunHelix = new helix[1500]; + for(int i = 0; i < 1500; i++) + railgunHelix[i] = new helix(); + + theConfirmationIcon = new confirmationIcon(); + + frameIndex = 0; + + lightReflect = new vector(0,0,0); + eyeDirection = new vector(0,0,0); + } + + public void run(){ + while(true){ + synchronized (this) { + try { + synchronized (mainThread.PPT_Lock) { + mainThread.PPT_Lock.notify(); + isWorking = false; + } + + long time = System.currentTimeMillis(); + wait(); + sleepTime = (int)(System.currentTimeMillis() - time); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + isWorking = true; + } + + doPostProcesssing(); + frameIndex++; + + } + } + + + public boolean isWorking(){ + if(isWorking) + return true; + else + return false; + } + + + + + public void doPostProcesssing(){ + int ObjectType, groupNo, level, maxHealth, healthBarLength, remainingHealth, xPos, yPos, selectAreaWidth, selectAreaHeight, color = 0; + + + //load explosion animation instances + float[] tempFloat; + for(int i = 0, j = 0; i < 200; i ++){ + if(!explosions[i].isInAction){ + if(j < explosionCount){ + tempFloat = explosionInfo[j]; + explosions[i].setActive(tempFloat[0], tempFloat[1], tempFloat[2], tempFloat[3], (int)tempFloat[4], (int)tempFloat[5], (int)tempFloat[6], tempFloat[7]); + j++; + }else { + break; + } + } + } + + + //sort explosion according to its size + //for(int i = 1; i < 200; i++){ + // for(int j = 0; j <200 - i; j++){ + // if(explosions[j].size > explosions[j+1].size){ + // explosion temp = explosions[j+1]; + // explosions[j+1] = explosions[j]; + // explosions[j] = temp; + // } + // } + //} + + + //blur shadow bitmap to create an illusion of antialiased shadow + blurShadow(); + + + //draw explosion animations + for(int i = 0; i < 200; i++) + explosions[i].updateAndDrawExplosionAura(); + + + + //blend shadow bitmap with screen buffer + blendShadow(); + + + //apply distortion map + int xMap; + int yMap; + int distortionIndex; + + for(int i = 0; i < 393216; i++){ + if(displacementBuffer[i] != 31){ + xMap = ((displacementBuffer[i]&992) >> 5) - 16; + yMap = (displacementBuffer[i]&31) - 16; + distortionIndex = i + xMap + yMap*768; + if(distortionIndex > 0 && distortionIndex < 393216 ){ + if(currentZbuffer[i] - currentZbuffer[distortionIndex] > -1000000) + offScreen[i] = currentScreen[distortionIndex]; + else + offScreen[i] = currentScreen[i]; + } + } + } + int r1, r2, r3, r4,r5, g1,g2,g3,g4,g5,b1,b2,b3,b4,b5; + + int c = (30/2) << 16 | (30)<<8| 31; + + + + + lightReflect.set(0,0,1); + lightReflect.rotate_YZ(230); + lightReflect.rotate_XZ(13); + lightReflect.y*=-1; + lightReflect.x*=-1; + lightReflect.set(lightReflect.x, -lightReflect.y, lightReflect.z); + lightReflect.rotate_XZ(camera.XZ_angle); + lightReflect.rotate_YZ(camera.YZ_angle); + + + int SpriteValue = 0; + int MASK7Bit = 0xFEFEFF; + int overflow = 0; + int pixel = 0; + + for(int i = 768; i < 392448; i++){ + if(displacementBuffer[i] != 31){ + + r1 = (offScreen[i + 1]&0xff0000) >> 16; + r2 = (offScreen[i - 767]&0xff0000) >> 16; + r3 = (offScreen[i - 768]&0xff0000) >> 16; + r4 = (offScreen[i - 1]&0xff0000) >> 16; + + + g1 = (offScreen[i + 1]&0xff00) >> 8; + g2 = (offScreen[i - 767]&0xff00) >> 8; + g3 = (offScreen[i - 768]&0xff00) >> 8; + g4 = (offScreen[i]&0xff00) >> 8; + + + b1 = (offScreen[i + 1]&0xff); + b2 = (offScreen[i - 767]&0xff); + b3 = (offScreen[i - 768]&0xff); + b4 = (offScreen[i]&0xff); + + + + + currentScreen[i] = (((r1 + r2 + r3 + r4)>>3) << 16 | ((g1 + g2 + g3 + g4)>>3) << 8 | ((b1 + b2 + b3 + b4)>>3 )) + c; + + yMap = (displacementBuffer[i]&64512) >> 10; + + + if(yMap > 0){ + eyeDirection.set(-i%768+384, -256 + i/768, -650); + eyeDirection.unit(); + float I = eyeDirection.dot(lightReflect); + + if(I > 0.985){ + int I_ = (int)((I-0.985) *24000); + + yMap = yMap * I_ /90; + + SpriteValue = 0x010101*yMap; + + pixel=(SpriteValue&MASK7Bit)+(currentScreen[i]&MASK7Bit); + overflow=pixel&0x1010100; + overflow=overflow-(overflow>>8); + currentScreen[i] = overflow|pixel; + } + + } + + displacementBuffer[i] = 31; + }else{ + + + } + + } + + + //create helix particles that are spawned by stealth tank's railgun trail. + for(int i = 0; i < helixCount; i++){ + tempFloat = helixInfo[i]; + railgunHelix[currentHelix].setActive(tempFloat[0], tempFloat[1], tempFloat[2], (int)tempFloat[3]); + currentHelix++; + currentHelix%=1500; + } + + //draw helix particles + for(int i = 0; i < 1500; i++){ + if(railgunHelix[i].isInAction) + railgunHelix[i].updateAndDraw(); + } + + + //draw explosion sprite + for(int i = 0; i < 200; i++) + explosions[i].drawExplosionSprite(); + + + + //create smoke particles + for(int i = 0; i < smokeEmmiterCount; i++){ + tempFloat = smokeEmmiterList[i]; + smokeParticles[currentParticleIndex].setActive(tempFloat[0], tempFloat[1], tempFloat[2], tempFloat[3], (int)tempFloat[4] , (int)tempFloat[5], tempFloat[6]); + currentParticleIndex++; + currentParticleIndex%=2000; + } + + + //draw smoke particles + for(int i = 0; i < 2000; i++){ + if(smokeParticles[i].isInAction) + smokeParticles[i].updateAndDraw(); + } + + + + + //draw health bar/Group info/unit level for every selected unit + for(int i = 0; i < 100; i++){ + if(currentSelectedUnitsInfo[i][0] != -1){ + ObjectType = (currentSelectedUnitsInfo[i][0] & 0xff); + groupNo = ((currentSelectedUnitsInfo[i][0] & 0xff00) >> 8); + level = ((currentSelectedUnitsInfo[i][0] & 0xff0000) >> 16); + maxHealth = unitInfoTable[ObjectType][0]; + healthBarLength = unitInfoTable[ObjectType][1]; + xPos = currentSelectedUnitsInfo[i][1] + unitInfoTable[ObjectType][2]; + yPos = currentSelectedUnitsInfo[i][2] + unitInfoTable[ObjectType][3]; + remainingHealth = healthBarLength * currentSelectedUnitsInfo[i][4] / maxHealth; + + //draw group info + if(groupNo != 255){ + theTextRenderer.drawText_outline(xPos, yPos + 3, ""+(groupNo+1), currentScreen, 0xffffff, 0); + } + if(level != 0){ + theTextRenderer.drawStarCharacter(xPos + healthBarLength - 13, yPos + 5, level, currentScreen, 0xffff33, 0); + } + + if(remainingHealth <= 2 && remainingHealth != 0) + remainingHealth = 2; + + if(ObjectType != 103){ + if(yPos > 0 && yPos < 512){ + + if(xPos >= 0 && xPos < 768) + currentScreen[xPos + yPos*768] = (currentScreen[xPos + yPos*768]&0xFEFEFE)>>1; + for(int j = xPos+1; j < xPos + healthBarLength-1; j++){ + if(j < 0 || j >= 768) + continue; + currentScreen[j + yPos*768] = 0; + } + if(xPos + healthBarLength-1 >= 0 && xPos + healthBarLength-1 < 768) + currentScreen[xPos + healthBarLength-1 + yPos*768] = (currentScreen[xPos + healthBarLength-1 + yPos*768]&0xFEFEFE)>>1; + } + + if((float)remainingHealth / healthBarLength > 0.5) + color = 0xdd00; + else if((float)remainingHealth / healthBarLength > 0.25) + color = 0xdddd00; + else + color = 0xdd0000; + + + for(int k = 0; k < 2; k++){ + yPos++; + + if(yPos > 0 && yPos < 512){ + for(int j = xPos; j < xPos + healthBarLength; j++){ + if(j < 0 || j >= 768) + continue; + if(j < xPos + remainingHealth) + currentScreen[j + yPos*768] = color; + else + currentScreen[j + yPos*768] = (currentScreen[j + yPos*768]&0xFEFEFE)>>1; + } + if(xPos > 0 && xPos < 768) + currentScreen[xPos + yPos*768] = 0; + if(xPos + healthBarLength -1 >0 && xPos + healthBarLength - 1 < 768) + currentScreen[xPos + healthBarLength -1 + yPos*768] = 0; + + } + } + + yPos++; + if(yPos > 0 && yPos < 512){ + if(xPos >= 0 && xPos < 768) + currentScreen[xPos + yPos*768] = (currentScreen[xPos + yPos*768]&0xFEFEFE)>>1; + for(int j = xPos+1; j < xPos + healthBarLength-1; j++){ + if(j < 0 || j >= 768) + continue; + currentScreen[j + yPos*768] = 0; + } + if(xPos + healthBarLength-1 >= 0 && xPos + healthBarLength-1 < 768) + currentScreen[xPos + healthBarLength-1 + yPos*768] = (currentScreen[xPos + healthBarLength-1 + yPos*768]&0xFEFEFE)>>1; + } + } + + //draw progress bar if appliable + if(currentSelectedUnitsInfo[i][5] >=0){ + int progress = healthBarLength * currentSelectedUnitsInfo[i][5] / 100; + + if(yPos > 0 && yPos < 512){ + if(xPos >= 0 && xPos < 768) + currentScreen[xPos + yPos*768] = (currentScreen[xPos + yPos*768]&0xFEFEFE)>>1; + for(int j = xPos+1; j < xPos + healthBarLength-1; j++){ + if(j < 0 || j >= 768) + continue; + currentScreen[j + yPos*768] = 0; + } + if(xPos + healthBarLength-1 >= 0 && xPos + healthBarLength-1 < 768) + currentScreen[xPos + healthBarLength-1 + yPos*768] = (currentScreen[xPos + healthBarLength-1 + yPos*768]&0xFEFEFE)>>1; + } + + + color = 0xd0b000; + + + for(int k = 0; k < 2; k++){ + yPos++; + + if(yPos > 0 && yPos < 512){ + for(int j = xPos; j < xPos + healthBarLength; j++){ + if(j < 0 || j >= 768) + continue; + if(j < xPos + progress) + currentScreen[j + yPos*768] = color; + else + currentScreen[j + yPos*768] = (currentScreen[j + yPos*768]&0xFEFEFE)>>1; + } + if(xPos > 0 && xPos < 768) + currentScreen[xPos + yPos*768] = 0; + if(xPos + healthBarLength -1 >0 && xPos + healthBarLength - 1 < 768) + currentScreen[xPos + healthBarLength -1 + yPos*768] = 0; + + } + } + + yPos++; + if(yPos > 0 && yPos < 512){ + if(xPos >= 0 && xPos < 768) + currentScreen[xPos + yPos*768] = (currentScreen[xPos + yPos*768]&0xFEFEFE)>>1; + for(int j = xPos+1; j < xPos + healthBarLength-1; j++){ + if(j < 0 || j >= 768) + continue; + currentScreen[j + yPos*768] = 0; + } + if(xPos + healthBarLength-1 >= 0 && xPos + healthBarLength-1 < 768) + currentScreen[xPos + healthBarLength-1 + yPos*768] = (currentScreen[xPos + healthBarLength-1 + yPos*768]&0xFEFEFE)>>1; + } + } + } + } + + + + //reset fogOfWarBuffer + fogOfWarBuffer[0] = 0; + for(int i = 1; i < 393216; i+=i){ + System.arraycopy(fogOfWarBuffer, 0, fogOfWarBuffer, i, 393216 - i >= i ? i : 393216 - i); + + } + + for(int i = 0; i < 512; i++){ + xMin[i] = 378; + xMax[i] = 378; + + } + + float[] list; + //shaffule vision polygons + for(int i = 0; i < 400; i++){ + temp = (gameData.getRandom() * visionPolygonCount) >> 10; + temp1 = (gameData.getRandom() * visionPolygonCount) >> 10; + + list = visionPolygonInfo[temp]; + visionPolygonInfo[temp] = visionPolygonInfo[temp1]; + visionPolygonInfo[temp1] = list; + } + + //update vision polygons + for(int i = 0; i < visionPolygonCount; i++){ + tempVector1.set(visionPolygonInfo[i][1], visionPolygonInfo[i][2], visionPolygonInfo[i][3]); + if(visionPolygonInfo[i][0] != 0){ + poly = mainThread.theAssetManager.visionPolygon[1]; + }else{ + poly = mainThread.theAssetManager.visionPolygon[(int)visionPolygonInfo[i][4]]; + } + tempVector1.subtract(poly.centre); + for(int j = 0; j < 48; j++) + poly.vertex3D[j].add(tempVector1); + + + poly.centre.add(tempVector1); + poly.update_visionPolygon(); + + rasterize(poly); + } + + + + //blur fog of war buffer, use cross shaped kernel + int radius = 16; + int radiusBit = 5; + int destIndex = 0; + int index = 0; + for(int i = 0; i < 512; i++){ + //init the first element in the row + temp = 0; + destIndex = i + 512 * 767 ; + + for(int j = 0; j < radius -1; j++){ + temp+=fogOfWarBuffer[index + j]; + } + temp+=43*radius; + fogOfWarBuffer2[destIndex] = (byte)(temp >> radiusBit); + index++; + destIndex-=512; + + for(int j = 1; j < radius; j++, index++, destIndex -=512){ + temp = temp + fogOfWarBuffer[index + radius -2] - 43; + fogOfWarBuffer2[destIndex] = (byte)(temp >> radiusBit); + } + + for(int j = radius; j < 768 - radius; j++, index++, destIndex -=512){ + temp = temp + fogOfWarBuffer[index + radius -2] - fogOfWarBuffer[index - radius]; + fogOfWarBuffer2[destIndex] = (byte)(temp >> radiusBit); + + } + for(int j = 0; j < radius; j++, index++, destIndex -=512){ + temp = temp - fogOfWarBuffer[index - radius] + 43; + fogOfWarBuffer2[destIndex] = (byte)(temp >> radiusBit); + } + } + + destIndex = 0; + index = 0; + for(int i = 0; i < 768; i++){ + //init the first element in the row + temp = 0; + destIndex = 767 - i; + + for(int j = 0; j < radius -1 ; j++){ + temp+=fogOfWarBuffer2[index + j]; + } + temp+=43*radius; + fogOfWarBuffer[destIndex] = (byte)(temp >> radiusBit); + index++; + destIndex+=768; + + for(int j = 1; j < radius; j++, index++, destIndex +=768){ + temp = temp + fogOfWarBuffer2[index + radius -2] - 43; + fogOfWarBuffer[destIndex] = (byte)(temp >> radiusBit); + } + + for(int j = radius; j < 512 - radius; j++, index++, destIndex +=768){ + temp = temp + fogOfWarBuffer2[index + radius -2] - fogOfWarBuffer2[index - radius]; + fogOfWarBuffer[destIndex] = (byte)(temp >> radiusBit); + } + for(int j = 0; j < radius; j++, index++, destIndex +=768){ + temp = temp - fogOfWarBuffer2[index - radius] + 43; + fogOfWarBuffer[destIndex] = (byte)(temp >> radiusBit); + } + } + + + //blend fog of war to the frame buffer + for(int i = 0; i < 512 * 768; i++){ + temp = fogOfWarBuffer[i]; + if(temp < 112) { + r = (((currentScreen[i] & 0xff0000) >> 16) * (temp + 143)) >> 8; + g = (((currentScreen[i] & 0xff00) >> 8) * (temp + 143)) >> 8 ; + b = ((currentScreen[i] & 0xff) * (temp + 143)) >> 8; + currentScreen[i] = r << 16 | g << 8 | b; + } + } + + + //draw select rectangle + if(mainThread.pc.isSelectingUnit){ + xPos = mainThread.pc.area.x; + yPos = mainThread.pc.area.y; + selectAreaWidth = mainThread.pc.area.width; + selectAreaHeight = mainThread.pc.area.height; + + try{ + if(!(yPos == 511 || xPos == 767)){ + for(int i = xPos; i < xPos + selectAreaWidth; i++) + currentScreen[i + yPos*768] = 0xaa00; + for(int i = xPos; i < xPos + selectAreaWidth; i++) + currentScreen[i + (yPos + 1)*768] = 0xcc00; + + for(int i = xPos; i < xPos + selectAreaWidth; i++) + currentScreen[i + (yPos+selectAreaHeight-1)*768] = 0xcc00; + for(int i = xPos; i < xPos + selectAreaWidth; i++) + currentScreen[i + (yPos + selectAreaHeight)*768] = 0xaa00; + + + for(int i = yPos; i < yPos + selectAreaHeight; i++) + currentScreen[xPos + i*768] = 0xaa00; + + for(int i = yPos+1; i < yPos + selectAreaHeight-1; i++) + currentScreen[xPos + 1 + i*768] = 0xcc00; + + for(int i = yPos; i < yPos + selectAreaHeight; i++) + currentScreen[xPos + selectAreaWidth + i*768] = 0xaa00; + + for(int i = yPos + 1; i < yPos + selectAreaHeight - 1; i++) + currentScreen[xPos - 1 + selectAreaWidth + i*768] = 0xcc00; + } + }catch(Exception e){} + } + + //draw confirmation icon + if(confirmationIconInfo[0] != 0){ + theConfirmationIcon.setActive((float)confirmationIconInfo[1], (float)confirmationIconInfo[2], (int)confirmationIconInfo[3]); + } + + theConfirmationIcon.updateAndDraw(); + + for(int i = 0; i < confirmationIconInfo.length; i++){ + confirmationIconInfo[i] = 0; + } + + //draw mini map + theMiniMap.draw(currentScreen, minimapBitmap, unitsForMiniMap, unitsForMiniMapCount); + theSideBar.draw(currentScreen, sideBarInfo); + + + } + + //start rasterization + public static void rasterize(polygon3D polygon){ + poly = polygon; + vertex2D = poly.vertex2D; + visibleCount = poly.visibleCount; + scanPolygon(); + } + + + + + //convert a polygon to scan lines + public static void scanPolygon(){ + start = 512; + end = -1; + int startX, g, startY, endY, temp_x; + float gradient; + + for(int i = 0; i < visibleCount; i++){ + vector v1 = vertex2D[i]; + vector v2; + + if(i == visibleCount -1 ){ + v2 = vertex2D[0]; + }else{ + v2 = vertex2D[i+1]; + } + + boolean downwards = false; + + //ensure v1.y < v2.y; + if (v1.screenY> v2.screenY) { + downwards = true; + vector temp = v1; + v1 = v2; + v2 = temp; + } + float dy = v2.screenY - v1.screenY; + + // ignore horizontal lines + if (dy == 0) { + + continue; + } + + + startY = Math.max((int)(v1.screenY) + 1, 0); + endY = Math.min((int)(v2.screenY), 511); + + + if(startY < start ) + start = startY; + + if(endY > end) + end = endY; + + + //calculate x increment along this edge + gradient = (v2.screenX - v1.screenX)* 2048 /dy; + startX = (int)((v1.screenX *2048) + (startY - v1.screenY) * gradient); + g = (int)(gradient); + for (int y=startY; y<=endY; y++) { + temp_x = startX>>11; + + if(downwards){ + if(temp_x >= 0) + xLeft[y] = temp_x; + else + xLeft[y] = 0; + }else{ + if(temp_x <= 767) + xRight[y] = temp_x; + else + xRight[y] = 768; + } + startX+=g; + + } + } + + + for(int i = start; i <= end; i++){ + temp = xLeft[i]; + temp1 = xRight[i]; + temp2 = xMin[i]; + temp3 = xMax[i]; + + if(temp1 <= temp3 && temp >= temp2) + continue; + + if(!(temp > temp3) && !(temp2 > temp1)){ + xMax[i] = Math.max(temp3, temp1); + xMin[i] = Math.min(temp2, temp); + for(int j = xMin[i]; j < xMax[i]; j++){ + fogOfWarBuffer[j + i*768] = (byte)127; + + } + continue; + } + + xMax[i] = temp1; + xMin[i] = temp; + for(int j = temp; j < temp1; j++){ + fogOfWarBuffer[j + i*768] = (byte)127; + } + } + } + + public static void blurShadow(){ + int index = 0; + if(cameraXZAngle <= 45 || cameraXZAngle >315){ + for(int i = 0; i < 511; i ++){ + for(int j = 1; j < 768; j++){ + index = j + i*768; + if(shadowBitmap[index] < 0){ + if(shadowBitmap[index] == -127) + smoothedShadowBitmap[index] = 32; + else + smoothedShadowBitmap[index]= (byte)(shadowBitmap[index] + 127); + + }else{ + smoothedShadowBitmap[index] = (byte)((shadowBitmap[index] + shadowBitmap[index - 1] + shadowBitmap[index + 768] + shadowBitmap[index + 767]) >> 2); + //smoothedShadowBitmap[index] = (byte)((shadowBitmap[index+769] + shadowBitmap[index+767] + shadowBitmap[index-769] + shadowBitmap[index-767] + shadowBitmap[index-768] + shadowBitmap[index] + shadowBitmap[index - 1] + shadowBitmap[index + 768] + shadowBitmap[index + 1])>>3); + + + } + } + } + for(int i = 0; i < 393216; i+= 768) + smoothedShadowBitmap[i] = shadowBitmap[i]; + for(int i = 392448; i < 393216; i++) + smoothedShadowBitmap[i] = shadowBitmap[i]; + + } + + if(cameraXZAngle <= 315 && cameraXZAngle > 225){ + for(int i = 511; i > 0; i --){ + for(int j = 1; j < 768; j++){ + index = j + i*768; + if(shadowBitmap[index] < 0){ + if(shadowBitmap[index] == -127) + smoothedShadowBitmap[index] = 32; + else + smoothedShadowBitmap[index]= (byte)(shadowBitmap[index] + 127); + }else{ + smoothedShadowBitmap[index] = (byte)((shadowBitmap[index] + shadowBitmap[index - 1] + shadowBitmap[index - 768] + shadowBitmap[index - 769]) >> 2); + + + } + } + } + for(int i = 0; i < 393216; i+= 768) + smoothedShadowBitmap[i] = shadowBitmap[i]; + for(int i = 0; i < 768; i++) + smoothedShadowBitmap[i] = shadowBitmap[i]; + + + } + + if(cameraXZAngle <= 225 && cameraXZAngle > 135){ + for(int i = 511; i > 0; i --){ + for(int j = 0; j < 767; j++){ + index = j + i*768; + if(shadowBitmap[index] < 0){ + if(shadowBitmap[index] == -127) + smoothedShadowBitmap[index] = 32; + else + smoothedShadowBitmap[index]= (byte)(shadowBitmap[index] + 127); + }else{ + smoothedShadowBitmap[index] = (byte)((shadowBitmap[index] + shadowBitmap[index + 1] + shadowBitmap[index - 768] + shadowBitmap[index - 767]) >> 2); + + + } + } + } + for(int i = 767; i < 393216; i+= 768) + smoothedShadowBitmap[i] = shadowBitmap[i]; + for(int i = 0; i < 768; i++) + smoothedShadowBitmap[i] = shadowBitmap[i]; + } + + if(cameraXZAngle <= 135 && cameraXZAngle > 45){ + for(int i = 0; i < 511; i ++){ + for(int j = 0; j < 767; j++){ + index = j + i*768; + if(shadowBitmap[index] < 0){ + if(shadowBitmap[index] == -127) + smoothedShadowBitmap[index] = 32; + else + smoothedShadowBitmap[index]= (byte)(shadowBitmap[index] + 127); + }else{ + smoothedShadowBitmap[index] = (byte)((shadowBitmap[index] + shadowBitmap[index + 1] + shadowBitmap[index + 768] + shadowBitmap[index + 769]) >> 2); + + } + } + } + for(int i = 767; i < 393216; i+= 768) + smoothedShadowBitmap[i] = shadowBitmap[i]; + for(int i = 392448; i < 393216; i++) + smoothedShadowBitmap[i] = shadowBitmap[i]; + } + } + + public static void blendShadow(){ + //blend shadow bitmap to the frame buffer + for(int i = 0; i < 512 * 768; i++){ + temp = smoothedShadowBitmap[i]; + if(temp <= 0) { + temp = shadowBitmap[i]; + } + + + r = (((currentScreen[i] & 0xff0000) >> 16) * temp ) >> 5; + g = (((currentScreen[i] & 0xff00) >> 8) * temp) >> 5 ; + b = ((currentScreen[i] & 0xff) * temp) >> 5; + + if(r > 255) + r = 255; + if(g > 255) + g = 255; + if(b > 255) + b = 255; + + currentScreen[i] = r << 16 | g << 8 | b; + } + } + + public static void prepareResources(){ + currentScreen = mainThread.screen; + currentZbuffer = mainThread.zBuffer; + displacementBuffer = mainThread.displacementBuffer; + shadowBitmap = mainThread.shadowBitmap; + currentSelectedUnitsInfo = mainThread.theAssetManager.selectedUnitsInfo; + visionPolygonInfo = mainThread.theAssetManager.visionPolygonInfo; + visionPolygonCount = mainThread.theAssetManager.visionPolygonCount; + unitsForMiniMap = mainThread.theAssetManager.unitsForMiniMap; + unitsForMiniMapCount = mainThread.theAssetManager.unitsForMiniMapCount; + minimapBitmap = mainThread.theAssetManager.minimapBitmap; + explosionInfo = mainThread.theAssetManager.explosionInfo; + explosionCount = mainThread.theAssetManager.explosionCount; + helixInfo = mainThread.theAssetManager.helixInfo; + helixCount = mainThread.theAssetManager.helixCount; + smokeEmmiterList = mainThread.theAssetManager.smokeEmmiterList; + smokeEmmiterCount = mainThread.theAssetManager.smokeEmmiterCount; + sideBarInfo = mainThread.pc.theSideBarManager.sideBarInfo; + confirmationIconInfo = mainThread.theAssetManager.confirmationIconInfo; + + cameraPosition.set(camera.position); + sinXZ = camera.sinXZ_angle; + cosXZ = camera.cosXZ_angle; + sinYZ = camera.sinYZ_angle; + cosYZ = camera.cosYZ_angle; + cameraXZAngle = camera.XZ_angle; + + theMiniMap.findCorners(); + + playerMoney = mainThread.pc.theBaseInfo.currentCredit; + playerPowerStatus = mainThread.pc.theBaseInfo.powerStatus; + + } + + + +} diff --git a/core/rasterizer.java b/core/rasterizer.java new file mode 100644 index 0000000..c1628c1 --- /dev/null +++ b/core/rasterizer.java @@ -0,0 +1,2296 @@ +package core; + +//The rasterizer class will draw any polygon into the screen buffer. +//The texture mapping methods will differ depends on the type of polygon, +//The universal formula for texture mapping is: +// x = A dot W/C dot W +// y = B dot W/C dot W +// where A = V cross O B = O cross U C = U cross V, +// V, a vector representing the texture's y direction +// U, a vector representing the texture's x direction +// O, the origin of the texture +// W is the projection length of the texel on the clipping plane +// x, y is the texture coordinate +// +//Won't handle z-axis rotation. + + + + +public class rasterizer { + //2 arrays that define the scan lines of the polygon + public static int[] xLeft = new int[512], xRight = new int[512]; + + //2 arrays that define the z depth across the polygon + public static int[] zLeft = new int[512], zRight = new int[512]; + + //2 arrays that define the reflections across the polygon + public static vector[] RLeft = new vector[512], RRight = new vector[512]; + + //2 arrays that define the intensity across the polygon + public static int[] iLeft = new int[512], iRight = new int[512]; + + //2 arrays that define the scan lines of the polygon in light space + public static int[] xLeft_lightspace = new int[1024], xRight_lightspace = new int[1024]; + + //2 arrays that define the z depth across the polygon in light space + public static int[] zLeft_lightspace = new int[1024], zRight_lightspace = new int[1024]; + + //a short array which represent zbuffer + public static int[] zBuffer; + + public static int[] screen; + + public static int[] shadowBuffer; + public static byte[] shadowBitmap; + + public static short[] displacementBuffer; + + + //init Texture coordinate vectors + public static vector + W = new vector(0,0,0), + O = new vector(0,0,0), + V = new vector(0,0,0), + U = new vector(0,0,0), + A = new vector(0,0,0), + B = new vector(0,0,0), + C = new vector(0,0,0), + C_unit = new vector(0,0,0); + + + //A pool of vectors which will be used for vector arithmetic + public static vector + tempVector1 = new vector(0,0,0), + tempVector2 = new vector(0,0,0), + tempVector3 = new vector(0,0,0), + tempVector4 = new vector(0,0,0); + + //the polygon that rasterizer is working on + public static polygon3D poly; + + //these variables will represent their equivalents in the polygon3D class during rasterization + public static vector[] tempVertex, vertex2D, reflections; + public static int widthMask, heightMask, widthBits, diffuse_I; + public static float A_offset, B_offset, C_offset; + + //the transparency level of the polygon. + public static int alpha; + + //the amount of vertex after clipping + public static int visibleCount; + + //temporary variables that will be used in texture mapping + public static float aDotW, bDotW, cDotW, cDotWInverse, w, textureHeight, textureWidth; + public static int BigX, BigY, d_x, d_y, k, X1, Y1, BigDx, BigDy, dx, dy, dz, X, Y, textureIndex, temp, temp1, temp2, r,g,b, scale, yOffset, xOffset, x_right, x_left, z_left, z_right, start, end; + public static short I, variation; + public static vector dReflection, startReflection, endReflection; + public static int z_origin, dz_xdirection, dz_ydirection, XY_origin_x, XY_origin_y, dXY_xdirection_x, dXY_xdirection_y, dXY_ydirection_x, dXY_ydirection_y; + + public static int cloakedThreshold, modelCenterX, modelCenterY, cloaked_x, cloaked_y, cloakedShadowThreshold; + public static byte[] cloakTexture; + + + //initialize rasteriser + public static void init(){ + for(int i = 0; i < 512; i++ ){ + RLeft[i] = new vector(0,0,0); + RRight[i] = new vector(0,0,0); + } + + dReflection = new vector(0,0,0); + startReflection = new vector(0,0,0); + endReflection = new vector(0,0,0); + screen = mainThread.screen; + zBuffer = mainThread.zBuffer; + shadowBitmap = mainThread.shadowBitmap; + shadowBuffer = sunLight.shadowBuffer; + displacementBuffer = mainThread.displacementBuffer; + } + + + + //start rasterization + public static void rasterize(polygon3D polygon){ + poly = polygon; + widthMask = poly.widthMask; + heightMask = poly.heightMask; + textureHeight = poly.textureHeight; + textureWidth = poly.textureWidth; + widthBits = poly.widthBits; + vertex2D = poly.vertex2D; + visibleCount = poly.visibleCount; + + + //for different polygons, the texture mapping alogrithm will differ depend + //on the nature of the polygon in order to optimize rendering + if(poly.type == 1){ + + scanPolygon(); + findVectorOUV(); + if(poly.visibleInLightSpace){ + if(!poly.smoothShading){ + renderShadowedPolygon(); + }else{ + renderShadowedPolygon_smooth(); + } + }else + renderBasicPolygon(); + }else if(polygon.type == 0){ + scanPolygon(); + findVectorOUV(); + renderSoildPolygon(); + }else if(polygon.type == 2){ + scanPolygon(); + findVectorOUV(); + renderTerrainPolygon(); + }else if(polygon.type == 3){ + scanPolygon(); + findVectorOUV(); + renderUnderGroundPolygon(); + }else if(polygon.type == 4){ + scanPolygon(); + findVectorOUV(); + renderZbufferRemoverPolygon(); + }else if(polygon.type == 5){ + scanPolygon_Gouraud(); + findVectorOUV(); + //if(poly.visibleInLightSpace){ + renderShadowedPolygon_Gouraud(); + //}else + // renderBasicPolygon(); + }else if(polygon.type == 6){ + scanPolygon(); + findVectorOUV(); + renderWaterPolygon(); + }else if(polygon.type == 7){ + scanPolygon(); + findVectorOUV(); + renderLakeBottomPolygon(); + }else if(polygon.type == 8){ + scanPolygon(); + findVectorOUV(); + renderRoadSidePolygon(); + }else if(polygon.type == 9){ + scanPolygon(); + findVectorOUV(); + renderCloakedPolygon(); + }else if(polygon.type == 10){ + scanPolygon(); + findVectorOUV(); + renderDeployGridPolygon(); + } + } + + //calculate O,U and V + public static void findVectorOUV(){ + O.set(poly.origin); + O.subtract(camera.position); + O.rotate_XZ(camera.XZ_angle); + O.rotate_YZ(camera.YZ_angle); + + U.set(poly.rightEnd); + + U.subtract(camera.position); + U.rotate_XZ(camera.XZ_angle); + U.rotate_YZ(camera.YZ_angle); + + + + V.set(poly.bottomEnd); + V.subtract(camera.position); + V.rotate_XZ(camera.XZ_angle); + V.rotate_YZ(camera.YZ_angle); + + U.subtract(O); + U.unit(); + + V.subtract(O); + V.unit(); + + + C_unit.cross(U, V); + + w = 0x1000000/(650*C_unit.dot(O)); + + U.scale(poly.textureScaleX); + V.scale(poly.textureScaleY); + + + A.cross(V,O); + B.cross(O,U); + C.cross(U,V); + + + } + + //convert a polygon to scan lines + public static void scanPolygon(){ + start = 512; + end = -1; + int startX, g, startY, endY, temp_x; + float gradient; + + for(int i = 0; i < visibleCount; i++){ + vector v1 = vertex2D[i]; + vector v2; + + if(i == visibleCount -1 ){ + v2 = vertex2D[0]; + }else{ + v2 = vertex2D[i+1]; + } + + boolean downwards = false; + + //ensure v1.y < v2.y; + if (v1.screenY> v2.screenY) { + downwards = true; + vector temp = v1; + v1 = v2; + v2 = temp; + } + float dy = v2.screenY - v1.screenY; + + // ignore horizontal lines + if (dy == 0) { + + continue; + } + + + startY = Math.max((int)(v1.screenY) + 1, 0); + endY = Math.min((int)(v2.screenY), 511); + + + if(startY < start ) + start = startY; + + if(endY > end) + end = endY; + + + //calculate x increment along this edge + gradient = (v2.screenX - v1.screenX)* 2048 /dy; + startX = (int)((v1.screenX *2048) + (startY - v1.screenY) * gradient); + g = (int)(gradient); + for (int y=startY; y<=endY; y++) { + temp_x = startX>>11; + + if(downwards){ + if(temp_x >= 0) + xLeft[y] = temp_x; + else + xLeft[y] = 0; + }else{ + if(temp_x <= 767) + xRight[y] = temp_x; + else + xRight[y] = 768; + } + startX+=g; + + } + } + } + + //convert a polygon to scan lines + public static void scanPolygon_Gouraud(){ + start = 512; + end = -1; + int startX, g, startY, endY, temp_x, startDiffuse, gDiffuse, temp_diffuse; + float gradient, diffuseGradient; + + for(int i = 0; i < visibleCount; i++){ + vector v1 = vertex2D[i]; + int diffuse1 = poly.diffuse[i]*2048; + vector v2; + int diffuse2; + + if(i == visibleCount -1 ){ + v2 = vertex2D[0]; + diffuse2 = poly.diffuse[0]*2048; + }else{ + v2 = vertex2D[i+1]; + diffuse2 = poly.diffuse[i+1]*2048; + } + + boolean downwards = false; + + //ensure v1.y < v2.y; + if (v1.screenY> v2.screenY) { + downwards = true; + vector temp = v1; + v1 = v2; + v2 = temp; + + int tempDiffuse = diffuse1; + diffuse1 = diffuse2; + diffuse2 = tempDiffuse; + } + float dy = v2.screenY - v1.screenY; + + // ignore horizontal lines + if (dy == 0) { + + continue; + } + + + startY = Math.max((int)(v1.screenY) + 1, 0); + endY = Math.min((int)(v2.screenY), 511); + + + if(startY < start ) + start = startY; + + if(endY > end) + end = endY; + + + //calculate x increment along this edge + gradient = (v2.screenX - v1.screenX)* 2048 /dy; + startX = (int)((v1.screenX *2048) + (startY - v1.screenY) * gradient); + g = (int)(gradient); + + diffuseGradient = (diffuse2 - diffuse1)/dy; + startDiffuse = (int)(diffuse1 + (startY - v1.screenY)*diffuseGradient); + gDiffuse = (int)(diffuseGradient); + + for (int y=startY; y<=endY; y++) { + temp_x = startX>>11; + temp_diffuse = startDiffuse; + + if(downwards){ + if(temp_x >= 0) + xLeft[y] = temp_x; + else + xLeft[y] = 0; + + iLeft[y] = temp_diffuse; + }else{ + if(temp_x <= 767) + xRight[y] = temp_x; + else + xRight[y] = 768; + iRight[y] = temp_diffuse; + } + startX+=g; + startDiffuse+=gDiffuse; + } + } + } + + //disable shadow casting for the region within the silhouette of the polygon + public static void renderShadowRemover(polygon3D polygon){ + poly = polygon; + vertex2D = poly.vertex2D; + visibleCount = poly.L; + + start = 1024; + end = -1; + + float gradient, dy; + int startX, g, startY, endY, temp_x, dx; + + for(int i = 0; i < visibleCount; i++){ + vector v1 = vertex2D[i]; + vector v2; + + if(i == visibleCount -1 ){ + v2 = vertex2D[0]; + }else{ + v2 = vertex2D[i+1]; + } + + boolean downwards = false; + + + //ensure v1.y < v2.y; + if (v1.screenY_lightspace> v2.screenY_lightspace) { + downwards = true; + vector temp = v1; + v1 = v2; + v2 = temp; + } + + dy = v2.screenY_lightspace - v1.screenY_lightspace; + // ignore horizontal lines + if (dy == 0) { + continue; + } + + startY = Math.max((int)(v1.screenY_lightspace) + 1, 0); + endY = Math.min((int)(v2.screenY_lightspace), 1023); + + + if(startY < start ) + start = startY; + + if(endY > end) + end = endY; + + //calculate x increment along this edge + gradient = (v2.screenX_lightspace - v1.screenX_lightspace)* 2048 /dy; + startX = (int)((v1.screenX_lightspace *2048) + (startY - v1.screenY_lightspace) * gradient); + g = (int)(gradient); + + for (int y=startY; y<=endY; y++) { + temp_x = startX>>11; + + if(downwards){ + xLeft_lightspace[y] = temp_x; + + }else{ + xRight_lightspace[y] = temp_x ; + + } + startX+=g; + } + + } + + int index, endX; + + for(int y = start; y <= end; y++){ + startX = xLeft_lightspace[y]; + endX = xRight_lightspace[y]; + dx = endX - startX; + if(dx <= 0) + continue; + + index = startX + (y<<10); + for(;startX < endX; startX++, index++){ + shadowBuffer[index] = Integer.MAX_VALUE; //set the distance of the pixel in light space to infinite away + + } + } + } + + + //draw the polygon on the shadow buffer from light point of view + public static void renderShadow(polygon3D polygon){ + poly = polygon; + vertex2D = poly.vertex2D; + visibleCount = poly.L; + + start = 1024; + end = -1; + + + float gradient, dy; + int startX, g, startY, endY, temp_x, startZ, dz, dx; + + for(int i = 0; i < visibleCount; i++){ + vector v1 = vertex2D[i]; + vector v2; + + if(i == visibleCount -1 ){ + v2 = vertex2D[0]; + }else{ + v2 = vertex2D[i+1]; + } + + boolean downwards = false; + + + //ensure v1.y < v2.y; + if (v1.screenY_lightspace> v2.screenY_lightspace) { + downwards = true; + vector temp = v1; + v1 = v2; + v2 = temp; + } + + dy = v2.screenY_lightspace - v1.screenY_lightspace; + // ignore horizontal lines + if (dy == 0) { + continue; + } + + startY = Math.max((int)(v1.screenY_lightspace) + 1, 0); + endY = Math.min((int)(v2.screenY_lightspace), 1023); + + + if(startY < start ) + start = startY; + + if(endY > end) + end = endY; + + //calculate x increment along this edge + gradient = (v2.screenX_lightspace - v1.screenX_lightspace)* 2048 /dy; + startX = (int)((v1.screenX_lightspace *2048) + (startY - v1.screenY_lightspace) * gradient); + g = (int)(gradient); + + //calculate z depth increment along this edge + startZ = (int)(v1.z_lightspace * 1048576); + dz = (int)((v2.z_lightspace * 1048576 - startZ)/dy); + startZ = (int)(startZ + (startY - v1.screenY_lightspace)*dz); + + for (int y=startY; y<=endY; y++) { + temp_x = startX>>11; + + if(downwards){ + xLeft_lightspace[y] = temp_x; + zLeft_lightspace[y] = startZ; + }else{ + xRight_lightspace[y] = temp_x ; + zRight_lightspace[y] = startZ; + } + startX+=g; + startZ+=dz; + } + + } + + int index, endX; + + for(int y = start; y <= end; y++){ + startX = xLeft_lightspace[y]; + endX = xRight_lightspace[y]; + dx = endX - startX; + if(dx <= 0) + continue; + startZ = zLeft_lightspace[y]; + dz = (zRight_lightspace[y] - startZ)/dx; + index = startX + (y<<10); + for(;startX < endX; startX++, index++, startZ += dz){ + if(startZ < shadowBuffer[index&1048575]){ + shadowBuffer[index&1048575] = startZ; + } + } + } + } + + //draw the polygon on the shadow buffer from light point of view + public static void renderCloakedShadow(polygon3D polygon){ + poly = polygon; + vertex2D = poly.vertex2D; + visibleCount = poly.L; + + start = 1024; + end = -1; + + + float gradient, dy; + int startX, g, startY, endY, temp_x, startZ, dz, dx; + + for(int i = 0; i < visibleCount; i++){ + vector v1 = vertex2D[i]; + vector v2; + + if(i == visibleCount -1 ){ + v2 = vertex2D[0]; + }else{ + v2 = vertex2D[i+1]; + } + + boolean downwards = false; + + + //ensure v1.y < v2.y; + if (v1.screenY_lightspace> v2.screenY_lightspace) { + downwards = true; + vector temp = v1; + v1 = v2; + v2 = temp; + } + + dy = v2.screenY_lightspace - v1.screenY_lightspace; + // ignore horizontal lines + if (dy == 0) { + continue; + } + + startY = Math.max((int)(v1.screenY_lightspace) + 1, 0); + endY = Math.min((int)(v2.screenY_lightspace), 1023); + + + if(startY < start ) + start = startY; + + if(endY > end) + end = endY; + + //calculate x increment along this edge + gradient = (v2.screenX_lightspace - v1.screenX_lightspace)* 2048 /dy; + startX = (int)((v1.screenX_lightspace *2048) + (startY - v1.screenY_lightspace) * gradient); + g = (int)(gradient); + + //calculate z depth increment along this edge + startZ = (int)(v1.z_lightspace * 1048576); + dz = (int)((v2.z_lightspace * 1048576 - startZ)/dy); + startZ = (int)(startZ + (startY - v1.screenY_lightspace)*dz); + + for (int y=startY; y<=endY; y++) { + temp_x = startX>>11; + + if(downwards){ + xLeft_lightspace[y] = temp_x; + zLeft_lightspace[y] = startZ; + }else{ + xRight_lightspace[y] = temp_x ; + zRight_lightspace[y] = startZ; + } + startX+=g; + startZ+=dz; + } + + } + + int index, endX; + int the_index = 0; + + for(int y = start; y <= end; y++){ + startX = xLeft_lightspace[y]; + endX = xRight_lightspace[y]; + dx = endX - startX; + if(dx <= 0) + continue; + startZ = zLeft_lightspace[y]; + dz = (zRight_lightspace[y] - startZ)/dx; + index = startX + (y<<10); + for(;startX < endX; startX++, index++, the_index++, startZ += dz){ + + if(cloakTexture[the_index] >= cloakedShadowThreshold){ + if(startZ < shadowBuffer[index&1048575]){ + shadowBuffer[index&1048575] = startZ; + } + } + } + } + } + + //render basic polygon that can't be shadowed (e.g polygon which back facing the light source) + public static void renderBasicPolygon(){ + short[] texture = poly.myTexture.pixelData; + diffuse_I = poly.diffuse_I&127; + int[]colorTable = gameData.colorTable[diffuse_I]; + + int index; + + + A_offset = A.x*16; + B_offset = B.x*16; + C_offset = C.x*16; + + double Aoffset,Boffset,Coffset; + + for(int i = start; i <= end; i++){ + x_left=xLeft[i]; + x_right=xRight[i]; + dx = x_right - x_left; + if(dx <= 0) + continue; + + W.set(x_left-383, -i + 256, 650); + aDotW = A.dot(W); + bDotW = B.dot(W); + cDotW = C.dot(W); + + //find the texture coordinate for the start pixel of the scanline + cDotWInverse = 1/cDotW; + X = (int)(aDotW*cDotWInverse); + Y = (int)(bDotW*cDotWInverse); + X1 = X; + Y1 = Y; + + int temp = 768*i; + + + z_left = (int)(C_unit.dot(W)*w); + dz = (int)(C_unit.x*w); + + + for(int j = x_left; j < x_right; j+=16){ + X = X1; + Y = Y1; + + index = j + temp; + if(x_right - j > 15){ + //find the correct texture coordinate every 16 pixels. + //Use the interpolation values for the pixels in between. + aDotW+=A_offset; + bDotW+=B_offset; + cDotW+=C_offset; + cDotWInverse = 1/cDotW; + X1 = (int)(aDotW*cDotWInverse); + Y1 = (int)(bDotW*cDotWInverse); + dx = X1 - X; + dy = Y1 - Y; + + for( k = 16, d_x = 0, d_y = 0; k >0; k--, d_x+=dx, d_y+=dy, index++, z_left+=dz){ + + + if(zBuffer[index] < z_left){ + zBuffer[index] = z_left; + textureIndex = ( ((d_x>>4) + X)&widthMask) + ((((d_y>>4) + Y)&heightMask)<0; k--, d_x+=dx, d_y+=dy, index++, z_left+=dz){ + + if(zBuffer[index] < z_left){ + zBuffer[index] = z_left; + textureIndex = (((d_x/offset) + X)&widthMask) + ((((d_y/offset) + Y)&heightMask)< 15){ + //find the correct texture coordinate every 16 pixels. + //Use the interpolation values for the pixels in between. + aDotW+=A_offset; + bDotW+=B_offset; + cDotW+=C_offset; + cDotWInverse = 1/cDotW; + X1 = (int)(aDotW*cDotWInverse); + Y1 = (int)(bDotW*cDotWInverse); + dx = X1 - X; + dy = Y1 - Y; + + for( k = 16, d_x = 0, d_y = 0; k >0; k--, d_x+=dx, d_y+=dy, index++, z_left+=dz){ + + + if(zBuffer[index] < z_left){ + zBuffer[index] = depth + 20; + xPos = (d_x>>4) + X; + yPos = (d_y>>4) + Y; + textureIndex = (xPos&widthMask) + ((yPos&heightMask)<> 16; + screenY_lightspace = (XY_origin_y + dXY_xdirection_y * xPos + dXY_ydirection_y * yPos) >> 16; + + + + int size = (screenX_lightspace + (screenY_lightspace << 10)) & 1048575; + + + if(z_lightspace - shadowBuffer[size] < shadowBias){ + shadowBitmap[index] = 32; + }else{ + shadowBitmap[index] = shadowLevel; + + } + screen[index] = colorTable[texture[textureIndex]]; + + } + } + continue; + } + + int offset = x_right - j; + Aoffset = A.x*offset; + Boffset = B.x*offset; + Coffset = C.x*offset; + + aDotW+=Aoffset; + bDotW+=Boffset; + cDotW+=Coffset; + cDotWInverse = 1/cDotW; + X1 = (int)(aDotW*cDotWInverse); + Y1 = (int)(bDotW*cDotWInverse); + dx = X1 - X; + dy = Y1 - Y; + + for( k = offset, d_x = 0, d_y = 0; k >0; k--, d_x+=dx, d_y+=dy, index++, z_left+=dz){ + + if(zBuffer[index] < z_left){ + zBuffer[index] = depth + 20; + xPos = (d_x/offset) + X; + yPos = (d_y/offset) + Y; + textureIndex = (xPos&widthMask) + ((yPos&heightMask)<> 16; + screenY_lightspace = (XY_origin_y + dXY_xdirection_y * xPos + dXY_ydirection_y * yPos) >> 16; + + int size = (screenX_lightspace + (screenY_lightspace << 10)) & 1048575; + + if(z_lightspace - shadowBuffer[size] < shadowBias){ + shadowBitmap[index] = 32; + }else{ + shadowBitmap[index] = shadowLevel; + } + screen[index] = colorTable[texture[textureIndex]]; + + } + } + + break; + } + } + } + + + + + //redner basic texture mapped polygon + public static void renderShadowedPolygon(){ + short[] texture = poly.myTexture.pixelData; + diffuse_I = poly.diffuse_I&127; + int[] colorTable = gameData.colorTable[diffuse_I]; + + int index, z_lightspace, screenX_lightspace, screenY_lightspace, xPos, yPos; + byte shadowLevel = 13; + float diffuse_intensity = gameData.intensityTable[diffuse_I]; + float ambient_intensity = gameData.intensityTable[poly.Ambient_I]; + float shadow_intensity = diffuse_intensity * 13f/32f; + + float difference = shadow_intensity - ambient_intensity; + if(difference < 0){ + if(difference < -0.2) + shadowLevel = (byte)((ambient_intensity * 32f / diffuse_intensity) - 127); + else + shadowLevel = (byte)((ambient_intensity * 32f / diffuse_intensity)); + } + int shadowBias = poly.shadowBias; + + + + + A_offset = A.x*16; + B_offset = B.x*16; + C_offset = C.x*16; + + double Aoffset,Boffset,Coffset; + + //recalculate the screen position of orgin, rightEnd, bottomEnd in light space + //if they dont fit the corners of the polygon + if(!poly.textureFitPolygon){ + tempVector1.set(poly.origin); + tempVector1.subtract(sunLight.position); + tempVector1.rotate_XZ(sunLight.XZ_angle); + tempVector1.rotate_YZ(sunLight.YZ_angle); + tempVector1.updateLocationOrthognal(); + tempVector1.z_lightspace = tempVector1.z; + + tempVector2.set(poly.rightEnd); + tempVector2.subtract(sunLight.position); + tempVector2.rotate_XZ(sunLight.XZ_angle); + tempVector2.rotate_YZ(sunLight.YZ_angle); + tempVector2.updateLocationOrthognal(); + tempVector2.z_lightspace = tempVector2.z; + + tempVector3.set(poly.bottomEnd); + tempVector3.subtract(sunLight.position); + tempVector3.rotate_XZ(sunLight.XZ_angle); + tempVector3.rotate_YZ(sunLight.YZ_angle); + tempVector3.updateLocationOrthognal(); + tempVector3.z_lightspace = tempVector3.z; + + + }else{ + tempVector1.z_lightspace = poly.origin.z_lightspace; + tempVector2.z_lightspace = poly.rightEnd.z_lightspace; + tempVector3.z_lightspace = poly.bottomEnd.z_lightspace; + tempVector1.screenX_lightspace = poly.origin.screenX_lightspace; + tempVector2.screenX_lightspace = poly.rightEnd.screenX_lightspace; + tempVector3.screenX_lightspace = poly.bottomEnd.screenX_lightspace; + tempVector1.screenY_lightspace = poly.origin.screenY_lightspace; + tempVector2.screenY_lightspace = poly.rightEnd.screenY_lightspace; + tempVector3.screenY_lightspace = poly.bottomEnd.screenY_lightspace; + } + + + z_origin = (int)(tempVector1.z_lightspace * 1048576); + dz_xdirection = (int)((tempVector2.z_lightspace * 1048576 - z_origin)*poly.textureWidthInverse); + dz_ydirection = (int)((tempVector3.z_lightspace * 1048576 - z_origin)*poly.textureHeightInverse); + + XY_origin_x = (int)(65536 * tempVector1.screenX_lightspace); + XY_origin_y = (int)(65536* tempVector1.screenY_lightspace); + dXY_xdirection_x = (int)((tempVector2.screenX_lightspace * 65536 - XY_origin_x)*poly.textureWidthInverse); + dXY_xdirection_y = (int)((tempVector2.screenY_lightspace * 65536 - XY_origin_y)*poly.textureWidthInverse); + dXY_ydirection_x = (int)((tempVector3.screenX_lightspace * 65536 - XY_origin_x)*poly.textureHeightInverse); + dXY_ydirection_y = (int)((tempVector3.screenY_lightspace * 65536 - XY_origin_y)*poly.textureHeightInverse); + + + + + for(int i = start; i <= end; i++){ + x_left=xLeft[i]; + x_right=xRight[i]; + dx = x_right - x_left; + if(dx <= 0) + continue; + + W.set(x_left-383, -i + 256, 650); + aDotW = A.dot(W); + bDotW = B.dot(W); + cDotW = C.dot(W); + + //find the texture coordinate for the start pixel of the scanline + cDotWInverse = 1/cDotW; + X = (int)(aDotW*cDotWInverse); + Y = (int)(bDotW*cDotWInverse); + X1 = X; + Y1 = Y; + + int temp = 768*i; + + + z_left = (int)(C_unit.dot(W)*w); + dz = (int)(C_unit.x*w); + + + for(int j = x_left; j < x_right; j+=16){ + X = X1; + Y = Y1; + + index = j + temp; + if(x_right - j > 15){ + //find the correct texture coordinate every 16 pixels. + //Use the interpolation values for the pixels in between. + aDotW+=A_offset; + bDotW+=B_offset; + cDotW+=C_offset; + cDotWInverse = 1/cDotW; + X1 = (int)(aDotW*cDotWInverse); + Y1 = (int)(bDotW*cDotWInverse); + dx = X1 - X; + dy = Y1 - Y; + + for( k = 16, d_x = 0, d_y = 0; k >0; k--, d_x+=dx, d_y+=dy, index++, z_left+=dz){ + + if(zBuffer[index] < z_left){ + zBuffer[index] = z_left; + xPos = (d_x>>4) + X; + yPos = (d_y>>4) + Y; + textureIndex = (xPos&widthMask) + ((yPos&heightMask)<> 16; + screenY_lightspace = (XY_origin_y + dXY_xdirection_y * xPos + dXY_ydirection_y * yPos) >> 16; + + + int size = (screenX_lightspace + (screenY_lightspace << 10)) & 1048575; + + + if(z_lightspace - shadowBuffer[size] < shadowBias){ + shadowBitmap[index] = 32; + }else{ + shadowBitmap[index] = shadowLevel; + + } + screen[index] = colorTable[texture[textureIndex]]; + + } + } + continue; + } + + int offset = x_right - j; + Aoffset = A.x*offset; + Boffset = B.x*offset; + Coffset = C.x*offset; + + aDotW+=Aoffset; + bDotW+=Boffset; + cDotW+=Coffset; + cDotWInverse = 1/cDotW; + X1 = (int)(aDotW*cDotWInverse); + Y1 = (int)(bDotW*cDotWInverse); + dx = X1 - X; + dy = Y1 - Y; + + for( k = offset, d_x = 0, d_y = 0; k >0; k--, d_x+=dx, d_y+=dy, index++, z_left+=dz){ + + if(zBuffer[index] < z_left){ + zBuffer[index] = z_left; + xPos = (d_x/offset) + X; + yPos = (d_y/offset) + Y; + textureIndex = (xPos&widthMask) + ((yPos&heightMask)<> 16; + screenY_lightspace = (XY_origin_y + dXY_xdirection_y * xPos + dXY_ydirection_y * yPos) >> 16; + + int size = (screenX_lightspace + (screenY_lightspace << 10)) & 1048575; + + if(z_lightspace - shadowBuffer[size] < shadowBias){ + shadowBitmap[index] = 32; + }else{ + shadowBitmap[index] = shadowLevel; + } + screen[index] = colorTable[texture[textureIndex]]; + + } + } + + break; + } + } + } + + public static void renderShadowedPolygon_Gouraud(){ + short[] texture = poly.myTexture.pixelData; + diffuse_I = poly.diffuse_I&127; + int[] colorTable = gameData.colorTable[diffuse_I]; + + int index, z_lightspace, screenX_lightspace, screenY_lightspace, xPos, yPos; + byte shadowLevel = 13; + float diffuse_intensity = gameData.intensityTable[diffuse_I]; + float ambient_intensity = gameData.intensityTable[poly.Ambient_I]; + float shadow_intensity = diffuse_intensity * 13f/32f; + + int diffuseStart, diffuseGradient, lit; + + float difference = shadow_intensity - ambient_intensity; + if(difference < 0){ + if(difference < -0.2) + shadowLevel = (byte)((ambient_intensity * 32f / diffuse_intensity) - 127); + else + shadowLevel = (byte)((ambient_intensity * 32f / diffuse_intensity)); + } + int shadowBias = poly.shadowBias; + + A_offset = A.x*16; + B_offset = B.x*16; + C_offset = C.x*16; + + double Aoffset,Boffset,Coffset; + + //recalculate the screen position of orgin, rightEnd, bottomEnd in light space + //if they dont fit the corners of the polygon + if(!poly.textureFitPolygon){ + tempVector1.set(poly.origin); + tempVector1.subtract(sunLight.position); + tempVector1.rotate_XZ(sunLight.XZ_angle); + tempVector1.rotate_YZ(sunLight.YZ_angle); + tempVector1.updateLocationOrthognal(); + tempVector1.z_lightspace = tempVector1.z; + + tempVector2.set(poly.rightEnd); + tempVector2.subtract(sunLight.position); + tempVector2.rotate_XZ(sunLight.XZ_angle); + tempVector2.rotate_YZ(sunLight.YZ_angle); + tempVector2.updateLocationOrthognal(); + tempVector2.z_lightspace = tempVector2.z; + + tempVector3.set(poly.bottomEnd); + tempVector3.subtract(sunLight.position); + tempVector3.rotate_XZ(sunLight.XZ_angle); + tempVector3.rotate_YZ(sunLight.YZ_angle); + tempVector3.updateLocationOrthognal(); + tempVector3.z_lightspace = tempVector3.z; + + + }else{ + tempVector1.z_lightspace = poly.origin.z_lightspace; + tempVector2.z_lightspace = poly.rightEnd.z_lightspace; + tempVector3.z_lightspace = poly.bottomEnd.z_lightspace; + tempVector1.screenX_lightspace = poly.origin.screenX_lightspace; + tempVector2.screenX_lightspace = poly.rightEnd.screenX_lightspace; + tempVector3.screenX_lightspace = poly.bottomEnd.screenX_lightspace; + tempVector1.screenY_lightspace = poly.origin.screenY_lightspace; + tempVector2.screenY_lightspace = poly.rightEnd.screenY_lightspace; + tempVector3.screenY_lightspace = poly.bottomEnd.screenY_lightspace; + } + + + z_origin = (int)(tempVector1.z_lightspace * 1048576); + dz_xdirection = (int)((tempVector2.z_lightspace * 1048576 - z_origin)*poly.textureWidthInverse); + dz_ydirection = (int)((tempVector3.z_lightspace * 1048576 - z_origin)*poly.textureHeightInverse); + + XY_origin_x = (int)(65536 * tempVector1.screenX_lightspace); + XY_origin_y = (int)(65536* tempVector1.screenY_lightspace); + dXY_xdirection_x = (int)((tempVector2.screenX_lightspace * 65536 - XY_origin_x)*poly.textureWidthInverse); + dXY_xdirection_y = (int)((tempVector2.screenY_lightspace * 65536 - XY_origin_y)*poly.textureWidthInverse); + dXY_ydirection_x = (int)((tempVector3.screenX_lightspace * 65536 - XY_origin_x)*poly.textureHeightInverse); + dXY_ydirection_y = (int)((tempVector3.screenY_lightspace * 65536 - XY_origin_y)*poly.textureHeightInverse); + + + + + for(int i = start; i <= end; i++){ + x_left=xLeft[i]; + x_right=xRight[i]; + dx = x_right - x_left; + if(dx <= 0) + continue; + + W.set(x_left-383, -i + 256, 650); + aDotW = A.dot(W); + bDotW = B.dot(W); + cDotW = C.dot(W); + + //find the texture coordinate for the start pixel of the scanline + cDotWInverse = 1/cDotW; + X = (int)(aDotW*cDotWInverse); + Y = (int)(bDotW*cDotWInverse); + X1 = X; + Y1 = Y; + + int temp = 768*i; + + + z_left = (int)(C_unit.dot(W)*w); + dz = (int)(C_unit.x*w); + + if(iLeft[i] <0 || iLeft[i] >= 260096 || iRight[i] < 0 || iRight[i] >= 260096){ + iLeft[i] = 0; + iRight[i] = 0; + } + + diffuseStart = iLeft[i]; + diffuseGradient = (iRight[i] - iLeft[i])/dx; + + + for(int j = x_left; j < x_right; j+=16){ + X = X1; + Y = Y1; + + index = j + temp; + if(x_right - j > 15){ + //find the correct texture coordinate every 16 pixels. + //Use the interpolation values for the pixels in between. + aDotW+=A_offset; + bDotW+=B_offset; + cDotW+=C_offset; + cDotWInverse = 1/cDotW; + X1 = (int)(aDotW*cDotWInverse); + Y1 = (int)(bDotW*cDotWInverse); + dx = X1 - X; + dy = Y1 - Y; + + for( k = 16, d_x = 0, d_y = 0; k >0; k--, d_x+=dx, d_y+=dy, index++, z_left+=dz, diffuseStart+=diffuseGradient){ + + if(zBuffer[index] < z_left){ + zBuffer[index] = z_left; + xPos = (d_x>>4) + X; + yPos = (d_y>>4) + Y; + textureIndex = (xPos&widthMask) + ((yPos&heightMask)<> 16; + screenY_lightspace = (XY_origin_y + dXY_xdirection_y * xPos + dXY_ydirection_y * yPos) >> 16; + + + int size = (screenX_lightspace + (screenY_lightspace << 10)) & 1048575; + + + if(z_lightspace - shadowBuffer[size] < shadowBias){ + shadowBitmap[index] = 32; + screen[index] = gameData.colorTable[diffuseStart >> 11][texture[textureIndex]]; + }else{ + shadowBitmap[index] = shadowLevel; + screen[index] = colorTable[texture[textureIndex]]; + } + + + } + } + continue; + } + + int offset = x_right - j; + Aoffset = A.x*offset; + Boffset = B.x*offset; + Coffset = C.x*offset; + + aDotW+=Aoffset; + bDotW+=Boffset; + cDotW+=Coffset; + cDotWInverse = 1/cDotW; + X1 = (int)(aDotW*cDotWInverse); + Y1 = (int)(bDotW*cDotWInverse); + dx = X1 - X; + dy = Y1 - Y; + + for( k = offset, d_x = 0, d_y = 0; k >0; k--, d_x+=dx, d_y+=dy, index++, z_left+=dz, diffuseStart+=diffuseGradient){ + + if(zBuffer[index] < z_left){ + zBuffer[index] = z_left; + xPos = (d_x/offset) + X; + yPos = (d_y/offset) + Y; + textureIndex = (xPos&widthMask) + ((yPos&heightMask)<> 16; + screenY_lightspace = (XY_origin_y + dXY_xdirection_y * xPos + dXY_ydirection_y * yPos) >> 16; + + int size = (screenX_lightspace + (screenY_lightspace << 10)) & 1048575; + + if(z_lightspace - shadowBuffer[size] < shadowBias){ + shadowBitmap[index] = 32; + screen[index] = gameData.colorTable[diffuseStart >> 11][texture[textureIndex]]; + + }else{ + shadowBitmap[index] = shadowLevel; + screen[index] = colorTable[texture[textureIndex]]; + } + + + } + } + + break; + } + } + } + + public static void renderShadowedPolygon_smooth(){ + short[] texture = poly.myTexture.pixelData; + diffuse_I = poly.diffuse_I&127; + int[] colorTable = gameData.colorTable[diffuse_I]; + + int index, z_lightspace, screenX_lightspace, screenY_lightspace, xPos, yPos; + byte shadowLevel = 13; + float diffuse_intensity = gameData.intensityTable[diffuse_I]; + float ambient_intensity = gameData.intensityTable[poly.Ambient_I]; + float shadow_intensity = diffuse_intensity * 13f/32f; + + float difference = shadow_intensity - ambient_intensity; + if(difference < 0){ + if(difference < -0.2) + shadowLevel = (byte)((ambient_intensity * 32f / diffuse_intensity) - 127); + else + shadowLevel = (byte)((ambient_intensity * 32f / diffuse_intensity)); + } + int shadowBias = poly.shadowBias; + + double I_left = poly.I_left; + double I_difference = poly.I_difference; + int textureScaledWidth = poly.textureScaledWidth; + + A_offset = A.x*16; + B_offset = B.x*16; + C_offset = C.x*16; + + double Aoffset,Boffset,Coffset; + + //recalculate the screen position of orgin, rightEnd, bottomEnd in light space + //if they dont fit the corners of the polygon + if(!poly.textureFitPolygon){ + tempVector1.set(poly.origin); + tempVector1.subtract(sunLight.position); + tempVector1.rotate_XZ(sunLight.XZ_angle); + tempVector1.rotate_YZ(sunLight.YZ_angle); + tempVector1.updateLocationOrthognal(); + tempVector1.z_lightspace = tempVector1.z; + + tempVector2.set(poly.rightEnd); + tempVector2.subtract(sunLight.position); + tempVector2.rotate_XZ(sunLight.XZ_angle); + tempVector2.rotate_YZ(sunLight.YZ_angle); + tempVector2.updateLocationOrthognal(); + tempVector2.z_lightspace = tempVector2.z; + + tempVector3.set(poly.bottomEnd); + tempVector3.subtract(sunLight.position); + tempVector3.rotate_XZ(sunLight.XZ_angle); + tempVector3.rotate_YZ(sunLight.YZ_angle); + tempVector3.updateLocationOrthognal(); + tempVector3.z_lightspace = tempVector3.z; + + + }else{ + tempVector1.z_lightspace = poly.origin.z_lightspace; + tempVector2.z_lightspace = poly.rightEnd.z_lightspace; + tempVector3.z_lightspace = poly.bottomEnd.z_lightspace; + tempVector1.screenX_lightspace = poly.origin.screenX_lightspace; + tempVector2.screenX_lightspace = poly.rightEnd.screenX_lightspace; + tempVector3.screenX_lightspace = poly.bottomEnd.screenX_lightspace; + tempVector1.screenY_lightspace = poly.origin.screenY_lightspace; + tempVector2.screenY_lightspace = poly.rightEnd.screenY_lightspace; + tempVector3.screenY_lightspace = poly.bottomEnd.screenY_lightspace; + } + + + z_origin = (int)(tempVector1.z_lightspace * 1048576); + dz_xdirection = (int)((tempVector2.z_lightspace * 1048576 - z_origin)*poly.textureWidthInverse); + dz_ydirection = (int)((tempVector3.z_lightspace * 1048576 - z_origin)*poly.textureHeightInverse); + + XY_origin_x = (int)(65536 * tempVector1.screenX_lightspace); + XY_origin_y = (int)(65536* tempVector1.screenY_lightspace); + dXY_xdirection_x = (int)((tempVector2.screenX_lightspace * 65536 - XY_origin_x)*poly.textureWidthInverse); + dXY_xdirection_y = (int)((tempVector2.screenY_lightspace * 65536 - XY_origin_y)*poly.textureWidthInverse); + dXY_ydirection_x = (int)((tempVector3.screenX_lightspace * 65536 - XY_origin_x)*poly.textureHeightInverse); + dXY_ydirection_y = (int)((tempVector3.screenY_lightspace * 65536 - XY_origin_y)*poly.textureHeightInverse); + + + + + for(int i = start; i <= end; i++){ + x_left=xLeft[i]; + x_right=xRight[i]; + dx = x_right - x_left; + if(dx <= 0) + continue; + + W.set(x_left-383, -i + 256, 650); + aDotW = A.dot(W); + bDotW = B.dot(W); + cDotW = C.dot(W); + + //find the texture coordinate for the start pixel of the scanline + cDotWInverse = 1/cDotW; + X = (int)(aDotW*cDotWInverse); + Y = (int)(bDotW*cDotWInverse); + X1 = X; + Y1 = Y; + + int temp = 768*i; + + + z_left = (int)(C_unit.dot(W)*w); + dz = (int)(C_unit.x*w); + + + for(int j = x_left; j < x_right; j+=16){ + X = X1; + Y = Y1; + + index = j + temp; + if(x_right - j > 15){ + //find the correct texture coordinate every 16 pixels. + //Use the interpolation values for the pixels in between. + aDotW+=A_offset; + bDotW+=B_offset; + cDotW+=C_offset; + cDotWInverse = 1/cDotW; + X1 = (int)(aDotW*cDotWInverse); + Y1 = (int)(bDotW*cDotWInverse); + dx = X1 - X; + dy = Y1 - Y; + + for( k = 16, d_x = 0, d_y = 0; k >0; k--, d_x+=dx, d_y+=dy, index++, z_left+=dz){ + + + if(zBuffer[index] < z_left){ + zBuffer[index] = z_left; + xPos = (d_x>>4) + X; + yPos = (d_y>>4) + Y; + textureIndex = (xPos&widthMask) + ((yPos&heightMask)<> 16; + screenY_lightspace = (XY_origin_y + dXY_xdirection_y * xPos + dXY_ydirection_y * yPos) >> 16; + + + + int size = (screenX_lightspace + (screenY_lightspace << 10)) & 1048575; + + + if(z_lightspace - shadowBuffer[size] < shadowBias){ + shadowBitmap[index] = 32; + int lit = (int)(I_left + I_difference * (xPos%textureScaledWidth)); + if(lit < 0) + lit = 0; + screen[index] = gameData.colorTable[lit][texture[textureIndex]]; + }else{ + shadowBitmap[index] = shadowLevel; + + screen[index] = colorTable[texture[textureIndex]]; + } + + } + } + continue; + } + + int offset = x_right - j; + Aoffset = A.x*offset; + Boffset = B.x*offset; + Coffset = C.x*offset; + + aDotW+=Aoffset; + bDotW+=Boffset; + cDotW+=Coffset; + cDotWInverse = 1/cDotW; + X1 = (int)(aDotW*cDotWInverse); + Y1 = (int)(bDotW*cDotWInverse); + dx = X1 - X; + dy = Y1 - Y; + + for( k = offset, d_x = 0, d_y = 0; k >0; k--, d_x+=dx, d_y+=dy, index++, z_left+=dz){ + + if(zBuffer[index] < z_left){ + zBuffer[index] = z_left; + xPos = (d_x/offset) + X; + yPos = (d_y/offset) + Y; + textureIndex = (xPos&widthMask) + ((yPos&heightMask)<> 16; + screenY_lightspace = (XY_origin_y + dXY_xdirection_y * xPos + dXY_ydirection_y * yPos) >> 16; + + int size = (screenX_lightspace + (screenY_lightspace << 10)) & 1048575; + + if(z_lightspace - shadowBuffer[size] < shadowBias){ + shadowBitmap[index] = 32; + + int lit = (int)(I_left + I_difference * (xPos%textureScaledWidth)); + if(lit < 0) + lit = 0; + screen[index] = gameData.colorTable[lit][texture[textureIndex]]; + }else{ + shadowBitmap[index] = shadowLevel; + screen[index] = colorTable[texture[textureIndex]]; + } + } + } + + break; + } + } + + } + + //redner terrain polygon which can be shadowed but can not cast shadow + public static void renderTerrainPolygon(){ + int zTop = 4490089; + int zBot = 7127877; + int zDelta = (zBot - zTop)/511; + int depth; + + + short[] texture = poly.myTexture.pixelData; + diffuse_I = poly.diffuse_I&127; + int[] colorTable = gameData.colorTable[diffuse_I]; + + int index, z_lightspace, screenX_lightspace, screenY_lightspace, xPos, yPos; + + + double Aoffset,Boffset,Coffset; + + tempVector1.set(poly.origin); + tempVector1.subtract(sunLight.position); + tempVector1.rotate_XZ(sunLight.XZ_angle); + tempVector1.rotate_YZ(sunLight.YZ_angle); + tempVector1.updateLocationOrthognal(); + tempVector1.z_lightspace = tempVector1.z; + + tempVector2.set(poly.rightEnd); + tempVector2.subtract(sunLight.position); + tempVector2.rotate_XZ(sunLight.XZ_angle); + tempVector2.rotate_YZ(sunLight.YZ_angle); + tempVector2.updateLocationOrthognal(); + tempVector2.z_lightspace = tempVector2.z; + + tempVector3.set(poly.bottomEnd); + tempVector3.subtract(sunLight.position); + tempVector3.rotate_XZ(sunLight.XZ_angle); + tempVector3.rotate_YZ(sunLight.YZ_angle); + tempVector3.updateLocationOrthognal(); + tempVector3.z_lightspace = tempVector3.z; + + + z_origin = (int)(tempVector1.z_lightspace * 1048576); + dz_xdirection = (int)((tempVector2.z_lightspace * 1048576 - z_origin)*poly.textureWidthInverse); + dz_ydirection = (int)((tempVector3.z_lightspace * 1048576 - z_origin)*poly.textureHeightInverse); + + XY_origin_x = (int)(65536 * tempVector1.screenX_lightspace); + XY_origin_y = (int)(65536* tempVector1.screenY_lightspace); + dXY_xdirection_x = (int)((tempVector2.screenX_lightspace * 65536 - XY_origin_x)*poly.textureWidthInverse); + dXY_xdirection_y = (int)((tempVector2.screenY_lightspace * 65536 - XY_origin_y)*poly.textureWidthInverse); + dXY_ydirection_x = (int)((tempVector3.screenX_lightspace * 65536 - XY_origin_x)*poly.textureHeightInverse); + dXY_ydirection_y = (int)((tempVector3.screenY_lightspace * 65536 - XY_origin_y)*poly.textureHeightInverse); + + + + for(int i = start; i <= end; i++){ + x_left=xLeft[i]; + x_right=xRight[i]; + dx = x_right - x_left; + if(dx <= 0) + continue; + + depth = zTop + i*zDelta; + + W.set(x_left-383, -i + 256, 650); + aDotW = A.dot(W); + bDotW = B.dot(W); + cDotW = C.dot(W); + + //find the texture coordinate for the start pixel of the scanline + cDotWInverse = 1/cDotW; + X = (int)(aDotW*cDotWInverse); + Y = (int)(bDotW*cDotWInverse); + + + index = x_left + 768*i; + int offset = x_right - x_left; + Aoffset = A.x*offset; + Boffset = B.x*offset; + Coffset = C.x*offset; + + aDotW+=Aoffset; + bDotW+=Boffset; + cDotW+=Coffset; + cDotWInverse = 1/cDotW; + X1 = (int)(aDotW*cDotWInverse); + Y1 = (int)(bDotW*cDotWInverse); + dx = ((X1 - X) <<8 )/offset; + dy = ((Y1 - Y) << 8)/offset; + + + for( k = offset, d_x = 0, d_y = 0; k >0; k--, d_x+=dx, d_y+=dy, index++){ + if(zBuffer[index] < depth && zBuffer[index] != 1){ + zBuffer[index] = depth; + xPos = (d_x>>8) + X; + yPos = (d_y>>8) + Y; + textureIndex = (xPos&widthMask) + ((yPos&heightMask)<> 16; + screenY_lightspace = (XY_origin_y + dXY_xdirection_y * xPos + dXY_ydirection_y * yPos) >> 16; + + if(z_lightspace - shadowBuffer[screenX_lightspace + (screenY_lightspace << 10)] < 1){ + shadowBitmap[index] = 32; + }else{ + shadowBitmap[index] = 15; + } + screen[index] = colorTable[texture[textureIndex]]; + + } + + } + + + } + } + + //redner road pologons which is a special case for terrain polyongs + public static void renderRoadSidePolygon(){ + int zTop = 4490089; + int zBot = 7127877; + int zDelta = (zBot - zTop)/511; + int depth; + int color; + + short[] texture = poly.myTexture.pixelData; + diffuse_I = poly.diffuse_I&127; + int[] colorTable = gameData.colorTable[diffuse_I]; + + int index, z_lightspace, screenX_lightspace, screenY_lightspace, xPos, yPos; + + + double Aoffset,Boffset,Coffset; + + tempVector1.set(poly.origin); + tempVector1.subtract(sunLight.position); + tempVector1.rotate_XZ(sunLight.XZ_angle); + tempVector1.rotate_YZ(sunLight.YZ_angle); + tempVector1.updateLocationOrthognal(); + tempVector1.z_lightspace = tempVector1.z; + + tempVector2.set(poly.rightEnd); + tempVector2.subtract(sunLight.position); + tempVector2.rotate_XZ(sunLight.XZ_angle); + tempVector2.rotate_YZ(sunLight.YZ_angle); + tempVector2.updateLocationOrthognal(); + tempVector2.z_lightspace = tempVector2.z; + + tempVector3.set(poly.bottomEnd); + tempVector3.subtract(sunLight.position); + tempVector3.rotate_XZ(sunLight.XZ_angle); + tempVector3.rotate_YZ(sunLight.YZ_angle); + tempVector3.updateLocationOrthognal(); + tempVector3.z_lightspace = tempVector3.z; + + + z_origin = (int)(tempVector1.z_lightspace * 1048576); + dz_xdirection = (int)((tempVector2.z_lightspace * 1048576 - z_origin)*poly.textureWidthInverse); + dz_ydirection = (int)((tempVector3.z_lightspace * 1048576 - z_origin)*poly.textureHeightInverse); + + XY_origin_x = (int)(65536 * tempVector1.screenX_lightspace); + XY_origin_y = (int)(65536* tempVector1.screenY_lightspace); + dXY_xdirection_x = (int)((tempVector2.screenX_lightspace * 65536 - XY_origin_x)*poly.textureWidthInverse); + dXY_xdirection_y = (int)((tempVector2.screenY_lightspace * 65536 - XY_origin_y)*poly.textureWidthInverse); + dXY_ydirection_x = (int)((tempVector3.screenX_lightspace * 65536 - XY_origin_x)*poly.textureHeightInverse); + dXY_ydirection_y = (int)((tempVector3.screenY_lightspace * 65536 - XY_origin_y)*poly.textureHeightInverse); + + + + for(int i = start; i <= end; i++){ + x_left=xLeft[i]; + x_right=xRight[i]; + dx = x_right - x_left; + if(dx <= 0) + continue; + + depth = zTop + i*zDelta; + + W.set(x_left-383, -i + 256, 650); + aDotW = A.dot(W); + bDotW = B.dot(W); + cDotW = C.dot(W); + + //find the texture coordinate for the start pixel of the scanline + cDotWInverse = 1/cDotW; + X = (int)(aDotW*cDotWInverse); + Y = (int)(bDotW*cDotWInverse); + + + index = x_left + 768*i; + int offset = x_right - x_left; + Aoffset = A.x*offset; + Boffset = B.x*offset; + Coffset = C.x*offset; + + aDotW+=Aoffset; + bDotW+=Boffset; + cDotW+=Coffset; + cDotWInverse = 1/cDotW; + X1 = (int)(aDotW*cDotWInverse); + Y1 = (int)(bDotW*cDotWInverse); + dx = ((X1 - X) <<8 )/offset; + dy = ((Y1 - Y) << 8)/offset; + + + for( k = offset, d_x = 0, d_y = 0; k >0; k--, d_x+=dx, d_y+=dy, index++){ + if(zBuffer[index] < depth && zBuffer[index] != 1){ + + xPos = (d_x>>8) + X; + yPos = (d_y>>8) + Y; + textureIndex = (xPos&widthMask) + ((yPos&heightMask)<> 16; + screenY_lightspace = (XY_origin_y + dXY_xdirection_y * xPos + dXY_ydirection_y * yPos) >> 16; + + int size = (screenX_lightspace + (screenY_lightspace << 10)) & 1048575; + + if(z_lightspace - shadowBuffer[size] < 1){ + shadowBitmap[index] = 32; + }else{ + shadowBitmap[index] = 15; + } + } + + } + + } + + + } + } + + //redner basic texture mapped polygon + public static void renderLakeBottomPolygon(){ + + short[] texture = poly.myTexture.pixelData; + diffuse_I = poly.diffuse_I&127; + int[] colorTable = gameData.colorTable[diffuse_I]; + + int index, z_lightspace, screenX_lightspace, screenY_lightspace, xPos, yPos; + + double Aoffset,Boffset,Coffset; + + tempVector1.set(poly.origin); + tempVector1.subtract(sunLight.position); + tempVector1.rotate_XZ(sunLight.XZ_angle); + tempVector1.rotate_YZ(sunLight.YZ_angle); + tempVector1.updateLocationOrthognal(); + tempVector1.z_lightspace = tempVector1.z; + + tempVector2.set(poly.rightEnd); + tempVector2.subtract(sunLight.position); + tempVector2.rotate_XZ(sunLight.XZ_angle); + tempVector2.rotate_YZ(sunLight.YZ_angle); + tempVector2.updateLocationOrthognal(); + tempVector2.z_lightspace = tempVector2.z; + + tempVector3.set(poly.bottomEnd); + tempVector3.subtract(sunLight.position); + tempVector3.rotate_XZ(sunLight.XZ_angle); + tempVector3.rotate_YZ(sunLight.YZ_angle); + tempVector3.updateLocationOrthognal(); + tempVector3.z_lightspace = tempVector3.z; + + + z_origin = (int)(tempVector1.z_lightspace * 1048576); + dz_xdirection = (int)((tempVector2.z_lightspace * 1048576 - z_origin)*poly.textureWidthInverse); + dz_ydirection = (int)((tempVector3.z_lightspace * 1048576 - z_origin)*poly.textureHeightInverse); + + XY_origin_x = (int)(65536 * tempVector1.screenX_lightspace); + XY_origin_y = (int)(65536* tempVector1.screenY_lightspace); + dXY_xdirection_x = (int)((tempVector2.screenX_lightspace * 65536 - XY_origin_x)*poly.textureWidthInverse); + dXY_xdirection_y = (int)((tempVector2.screenY_lightspace * 65536 - XY_origin_y)*poly.textureWidthInverse); + dXY_ydirection_x = (int)((tempVector3.screenX_lightspace * 65536 - XY_origin_x)*poly.textureHeightInverse); + dXY_ydirection_y = (int)((tempVector3.screenY_lightspace * 65536 - XY_origin_y)*poly.textureHeightInverse); + + + + for(int i = start; i <= end; i++){ + x_left=xLeft[i]; + x_right=xRight[i]; + dx = x_right - x_left; + if(dx <= 0) + continue; + + W.set(x_left-383, -i + 256, 650); + aDotW = A.dot(W); + bDotW = B.dot(W); + cDotW = C.dot(W); + + //find the texture coordinate for the start pixel of the scanline + cDotWInverse = 1/cDotW; + X = (int)(aDotW*cDotWInverse); + Y = (int)(bDotW*cDotWInverse); + + + index = x_left + 768*i; + int offset = x_right - x_left; + Aoffset = A.x*offset; + Boffset = B.x*offset; + Coffset = C.x*offset; + + aDotW+=Aoffset; + bDotW+=Boffset; + cDotW+=Coffset; + cDotWInverse = 1/cDotW; + X1 = (int)(aDotW*cDotWInverse); + Y1 = (int)(bDotW*cDotWInverse); + dx = ((X1 - X) <<8 )/offset; + dy = ((Y1 - Y) << 8)/offset; + + + for( k = offset, d_x = 0, d_y = 0; k >0; k--, d_x+=dx, d_y+=dy, index++){ + if(zBuffer[index] <=1){ + zBuffer[index] = 2; + xPos = (d_x>>8) + X; + yPos = (d_y>>8) + Y; + textureIndex = (xPos&widthMask) + ((yPos&heightMask)<> 16; + screenY_lightspace = (XY_origin_y + dXY_xdirection_y * xPos + dXY_ydirection_y * yPos) >> 16; + + int size = (screenX_lightspace + (screenY_lightspace << 10)) & 1048575; + + if(z_lightspace - shadowBuffer[size] < 1){ + shadowBitmap[index] = 32; + }else{ + shadowBitmap[index] = 15; + } + screen[index] = colorTable[texture[textureIndex]]; + + } + + } + + + } + } + + + //render water polygon + public static void renderWaterPolygon(){ + short[] displacementMap = poly.myTexture.displacementMap; + byte[] waterHeightMap = poly.myTexture.waterHeightMap; + int index; + double Aoffset,Boffset,Coffset; + + + for(int i = start; i <= end; i++){ + x_left=xLeft[i]; + x_right=xRight[i]; + dx = x_right - x_left; + if(dx <= 0) + continue; + + W.set(x_left-383, -i + 256, 650); + aDotW = A.dot(W); + bDotW = B.dot(W); + cDotW = C.dot(W); + + //find the texture coordinate for the start pixel of the scanline + cDotWInverse = 1/cDotW; + X = (int)(aDotW*cDotWInverse); + Y = (int)(bDotW*cDotWInverse); + + z_left = (int)(C_unit.dot(W)*w); + dz = (int)(C_unit.x*w); + + index = x_left + 768*i; + int offset = x_right - x_left; + Aoffset = A.x*offset; + Boffset = B.x*offset; + Coffset = C.x*offset; + + aDotW+=Aoffset; + bDotW+=Boffset; + cDotW+=Coffset; + cDotWInverse = 1/cDotW; + X1 = (int)(aDotW*cDotWInverse); + Y1 = (int)(bDotW*cDotWInverse); + dx = ((X1 - X) <<8 )/offset; + dy = ((Y1 - Y) << 8)/offset; + + for( k = offset, d_x = 0, d_y = 0; k >0; k--, d_x+=dx, d_y+=dy, index++){ + if(zBuffer[index] < z_left){ + textureIndex = (((d_x>>8) + X)&widthMask) + ((((d_y>>8) + Y)&heightMask)<>1; + + for(int i = start; i <= end; i++){ + x_left = xLeft[i] ; + x_right = xRight[i]; + dx = x_right - x_left; + + if(dx == 0) + continue; + + int temp = i * 768; + x_left+=temp; + x_right+=temp; + + for(int j = x_left; j < x_right; j++){ + screen[j] = ((screen[j]&0xFEFEFE)>>1) + soildColor2; + } + } + + } + + + + //set the zbuffer value within the silhouette of the polygon to zero + public static void renderZbufferRemoverPolygon(){ + for(int i = start; i <= end; i++){ + x_left = xLeft[i] ; + x_right = xRight[i]; + dx = x_right - x_left; + + W.set(x_left-383, -i + 256, 650); + + z_left = (int)(C_unit.dot(W)*w); + dz = (int)(C_unit.x*w); + + if(dx == 0) + continue; + + int temp = i * 768; + x_left+=temp; + x_right+=temp; + + for(int j = x_left; j < x_right; j++, z_left+=dz){ + if(zBuffer[j] < z_left){ + zBuffer[j] = 1; //set the distance of the pixel in camera space to infinite away + } + } + } + + } + + //redner basic texture mapped polygon + public static void renderCloakedPolygon(){ + + short[] texture = poly.myTexture.pixelData; + diffuse_I = poly.diffuse_I&127; + int[] colorTable = gameData.colorTable[diffuse_I]; + + int index, z_lightspace, screenX_lightspace, screenY_lightspace, xPos, yPos; + byte shadowLevel = 13; + float diffuse_intensity = gameData.intensityTable[diffuse_I]; + float ambient_intensity = gameData.intensityTable[poly.Ambient_I]; + float shadow_intensity = diffuse_intensity * 13f/32f; + + float difference = shadow_intensity - ambient_intensity; + if(difference < 0){ + if(difference < -0.2) + shadowLevel = (byte)((ambient_intensity * 32f / diffuse_intensity) - 127); + else + shadowLevel = (byte)((ambient_intensity * 32f / diffuse_intensity)); + } + int shadowBias = poly.shadowBias; + + + + A_offset = A.x*16; + B_offset = B.x*16; + C_offset = C.x*16; + + float Aoffset,Boffset,Coffset; + + + //recalculate the screen position of orgin, rightEnd, bottomEnd in light space + //if they dont fit the corners of the polygon + if(!poly.textureFitPolygon){ + tempVector1.set(poly.origin); + tempVector1.subtract(sunLight.position); + tempVector1.rotate_XZ(sunLight.XZ_angle); + tempVector1.rotate_YZ(sunLight.YZ_angle); + tempVector1.updateLocationOrthognal(); + tempVector1.z_lightspace = tempVector1.z; + + tempVector2.set(poly.rightEnd); + tempVector2.subtract(sunLight.position); + tempVector2.rotate_XZ(sunLight.XZ_angle); + tempVector2.rotate_YZ(sunLight.YZ_angle); + tempVector2.updateLocationOrthognal(); + tempVector2.z_lightspace = tempVector2.z; + + tempVector3.set(poly.bottomEnd); + tempVector3.subtract(sunLight.position); + tempVector3.rotate_XZ(sunLight.XZ_angle); + tempVector3.rotate_YZ(sunLight.YZ_angle); + tempVector3.updateLocationOrthognal(); + tempVector3.z_lightspace = tempVector3.z; + + + }else{ + tempVector1.z_lightspace = poly.origin.z_lightspace; + tempVector2.z_lightspace = poly.rightEnd.z_lightspace; + tempVector3.z_lightspace = poly.bottomEnd.z_lightspace; + tempVector1.screenX_lightspace = poly.origin.screenX_lightspace; + tempVector2.screenX_lightspace = poly.rightEnd.screenX_lightspace; + tempVector3.screenX_lightspace = poly.bottomEnd.screenX_lightspace; + tempVector1.screenY_lightspace = poly.origin.screenY_lightspace; + tempVector2.screenY_lightspace = poly.rightEnd.screenY_lightspace; + tempVector3.screenY_lightspace = poly.bottomEnd.screenY_lightspace; + } + + + z_origin = (int)(tempVector1.z_lightspace * 1048576); + dz_xdirection = (int)((tempVector2.z_lightspace * 1048576 - z_origin)*poly.textureWidthInverse); + dz_ydirection = (int)((tempVector3.z_lightspace * 1048576 - z_origin)*poly.textureHeightInverse); + + XY_origin_x = (int)(65536 * tempVector1.screenX_lightspace); + XY_origin_y = (int)(65536* tempVector1.screenY_lightspace); + dXY_xdirection_x = (int)((tempVector2.screenX_lightspace * 65536 - XY_origin_x)*poly.textureWidthInverse); + dXY_xdirection_y = (int)((tempVector2.screenY_lightspace * 65536 - XY_origin_y)*poly.textureWidthInverse); + dXY_ydirection_x = (int)((tempVector3.screenX_lightspace * 65536 - XY_origin_x)*poly.textureHeightInverse); + dXY_ydirection_y = (int)((tempVector3.screenY_lightspace * 65536 - XY_origin_y)*poly.textureHeightInverse); + + + + + for(int i = start; i <= end; i++){ + x_left=xLeft[i]; + x_right=xRight[i]; + dx = x_right - x_left; + if(dx <= 0) + continue; + + W.set(x_left-383, -i + 256, 650); + aDotW = A.dot(W); + bDotW = B.dot(W); + cDotW = C.dot(W); + + //find the texture coordinate for the start pixel of the scanline + cDotWInverse = 1/cDotW; + X = (int)(aDotW*cDotWInverse); + Y = (int)(bDotW*cDotWInverse); + X1 = X; + Y1 = Y; + + int temp = 768*i; + + + z_left = (int)(C_unit.dot(W)*w); + dz = (int)(C_unit.x*w); + + + for(int j = x_left; j < x_right; j+=16){ + X = X1; + Y = Y1; + + index = j + temp; + if(x_right - j > 15){ + //find the correct texture coordinate every 16 pixels. + //Use the interpolation values for the pixels in between. + aDotW+=A_offset; + bDotW+=B_offset; + cDotW+=C_offset; + cDotWInverse = 1/cDotW; + X1 = (int)(aDotW*cDotWInverse); + Y1 = (int)(bDotW*cDotWInverse); + dx = X1 - X; + dy = Y1 - Y; + + for( k = 0, d_x = 0, d_y = 0; k <16; k++, d_x+=dx, d_y+=dy, index++, z_left+=dz){ + if(zBuffer[index] < z_left){ + + cloaked_x = 32 + (j + k) - modelCenterX; + cloaked_y = 32 + (i - modelCenterY); + + temp1 = cloaked_x + cloaked_y*64; + if(temp1 < 0 || temp1 >=4096) + temp1 = 0; + + if(cloakTexture[temp1] < cloakedThreshold){ + continue; + } + + zBuffer[index] = z_left; + xPos = (d_x>>4) + X; + yPos = (d_y>>4) + Y; + textureIndex = (xPos&widthMask) + ((yPos&heightMask)<> 16; + screenY_lightspace = (XY_origin_y + dXY_xdirection_y * xPos + dXY_ydirection_y * yPos) >> 16; + + + int size = (screenX_lightspace + (screenY_lightspace << 10)) & 1048575; + + + if(z_lightspace - shadowBuffer[size] < shadowBias){ + shadowBitmap[index] = 32; + }else{ + shadowBitmap[index] = shadowLevel; + + } + screen[index] = colorTable[texture[textureIndex]]; + + } + } + continue; + } + + int offset = x_right - j; + Aoffset = A.x*offset; + Boffset = B.x*offset; + Coffset = C.x*offset; + + aDotW+=Aoffset; + bDotW+=Boffset; + cDotW+=Coffset; + cDotWInverse = 1/cDotW; + X1 = (int)(aDotW*cDotWInverse); + Y1 = (int)(bDotW*cDotWInverse); + dx = X1 - X; + dy = Y1 - Y; + + for( k = 0, d_x = 0, d_y = 0; k < offset; k++, d_x+=dx, d_y+=dy, index++, z_left+=dz){ + + if(zBuffer[index] < z_left){ + + cloaked_x = 32 + (j + k) - modelCenterX; + cloaked_y = 32 + (i - modelCenterY); + + temp1 = cloaked_x + cloaked_y*64; + if(temp1 < 0 || temp1 >=4096) + temp1 = 0; + + if(cloakTexture[temp1] < cloakedThreshold){ + continue; + } + + zBuffer[index] = z_left; + xPos = (d_x/offset) + X; + yPos = (d_y/offset) + Y; + textureIndex = (xPos&widthMask) + ((yPos&heightMask)<> 16; + screenY_lightspace = (XY_origin_y + dXY_xdirection_y * xPos + dXY_ydirection_y * yPos) >> 16; + + int size = (screenX_lightspace + (screenY_lightspace << 10)) & 1048575; + + if(z_lightspace - shadowBuffer[size] < shadowBias){ + shadowBitmap[index] = 32; + }else{ + shadowBitmap[index] = shadowLevel; + } + screen[index] = colorTable[texture[textureIndex]]; + + } + } + + break; + } + } + } + +} \ No newline at end of file diff --git a/core/sunLight.java b/core/sunLight.java new file mode 100644 index 0000000..fd6ca19 --- /dev/null +++ b/core/sunLight.java @@ -0,0 +1,50 @@ +package core; + +//directional light from the sun +public class sunLight { + + public static int XZ_angle, YZ_angle; + + public static float sinXZ_angle, cosXZ_angle, sinYZ_angle, cosYZ_angle; + + public static vector position; + + public static int[] shadowBuffer; + + public static vector lightDirection; + + + public static void init(){ + + shadowBuffer = new int[1024*1024]; + + XZ_angle = 225; + YZ_angle = 316; + sinXZ_angle = gameData.sin[XZ_angle]; + cosXZ_angle = gameData.cos[XZ_angle]; + sinYZ_angle = gameData.sin[YZ_angle]; + cosYZ_angle = gameData.cos[YZ_angle]; + + lightDirection = new vector(0,0,1); + lightDirection.rotate_YZ(YZ_angle); + lightDirection.rotate_XZ(XZ_angle); + lightDirection.y*=-1; + lightDirection.x*=-1; + + + position = new vector(0,0,0); + } + + public static void update(){ + position.set(mainThread.my2Dto3DFactory.get3DLocation(mainThread.theAssetManager.Terrain.ground[0], 384, 208)); + position.add(lightDirection, -5); + + //reset shadow buffer + shadowBuffer[0] = Integer.MAX_VALUE; + for(int i = 1; i < 1048576; i+=i){ + System.arraycopy(shadowBuffer, 0, shadowBuffer, i, 1048576 - i >= i ? i : 1048576 - i); + + } + + } +} diff --git a/core/terrain.java b/core/terrain.java new file mode 100644 index 0000000..b03a9e4 --- /dev/null +++ b/core/terrain.java @@ -0,0 +1,910 @@ +package core; + +import entity.*; + +// this class store the geometry for terrain objects +public class terrain { + + public polygon3D[] ground; + + public int[] lakeObstacleIndex; + public int lakeObstacleCount; + + public static int index; + + public int Ambient_I = 25; + public int reflectance = 70; + + //lake1 + public polygon3D water1; + public polygon3D groundRemover1; + public polygon3D[] lake1; + public vector lakeCenter1; + public vector lakeCenterTemp1; + public boolean lake1Visible; + public int lake1PolyCount; + public palmTree lake1Tree, lake1Tree2; + + //lake2 + public polygon3D water2; + public polygon3D groundRemover2; + public polygon3D[] lake2; + public vector lakeCenter2; + public vector lakeCenterTemp2; + public boolean lake2Visible; + public int lake2PolyCount; + public goldMine goldMine2; + + //lake3 + public polygon3D water3; + public polygon3D groundRemover3; + public polygon3D[] lake3; + public vector lakeCenter3; + public vector lakeCenterTemp3; + public boolean lake3Visible; + public int lake3PolyCount; + + //lake 4 + public polygon3D water4; + public polygon3D groundRemover4; + public polygon3D[] lake4; + public vector lakeCenter4; + public vector lakeCenterTemp4; + public boolean lake4Visible; + public int lake4PolyCount; + + public tokenObject theToken; + + //road + public polygon3D[] road; + public vector roadDirection; + public vector roadNormal; + public vector roadSideDirection; + public vector roadCorner1, roadCorner2, roadCorner3, roadCorner4; + public vector roadCentre; + public int roadPolygonIndex; + public vector roadMarkCorner1, roadMarkCorner2, roadMarkCorner3, roadMarkCorner4; + public vector roadSideCorner1, roadSideCorner2, roadSideCorner3, roadSideCorner4; + + //light poles + public lightPole[] lightPoles; + public int numOfLightPoles; + + public int curveAngle; + + + public terrain(){ + ground = new polygon3D[1]; + vector[] v = new vector[]{new vector(-3f,-0.5001f,35f), new vector(35f,-0.5001f,35f), new vector(35f,-0.5001f,-3f), new vector(-3f,-0.5001f, -3f)}; + ground[0] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[0], 39f,38.15f, 2); + ground[0].Ambient_I = Ambient_I; + ground[0].reflectance = reflectance; + ground[0].findDiffuse(); + ground[0].textureFitPolygon = true; + lakeObstacleIndex = new int[1000]; + + + float x_start = 3.5f; + float z_start = 8; + float l = 3; + + float h = 3f/128*(128 - 17 - 12); + float w = 3f/128*(128 - 25 - 20); + float dx = 3f/128*25; + float dz = -3f/128*17; + + theToken = new tokenObject(-1, -1, -1, 0x00ffff); + theToken.withinViewScreen = true; + + int waveAngle = 320; + + //create lake1 + v = new vector[]{new vector(x_start+dx,-0.54f,z_start + dz), new vector(x_start + dx + w,-0.54f,z_start + dz), new vector(x_start + dx + w,-0.54f,z_start + dz-h), new vector(x_start+dx,-0.54f, z_start + dz-h)}; + + vector a1 = v[0].myClone(); + vector b1 = v[1].myClone(); + vector c1 = v[3].myClone(); + + a1.rotate_XZ(waveAngle); + b1.rotate_XZ(waveAngle); + c1.rotate_XZ(waveAngle); + + + water1 = new polygon3D(v, a1, b1, c1, mainThread.textures[54],w*1.2f,h*1.1f, 6); + + v = new vector[]{new vector(x_start+dx,-0.5001f,z_start + dz), new vector(x_start + dx + w,-0.5001f,z_start + dz), new vector(x_start + dx + w,-0.5001f,z_start + dz-h), new vector(x_start+dx,-0.5001f, z_start + dz-h)}; + groundRemover1 = new polygon3D(v, v[0], v[1], v[3], null,l,l, 4); + + lake1 = createLake(mainThread.textures[55].heightmap, x_start, z_start, l , 128, 17, 12, 25, 20); + lake1PolyCount = index + 1; + lakeCenter1 = new vector(5f, -0.5001f, 6.5f); + lakeCenterTemp1 = new vector(0,0,0); + lake1Tree = new palmTree(4.983713f,-0.3028361f,6.419566f,-0.03152565f,0.03608194f,-0.030372922f,0.19448919f,-0.11764373f,187,64,148,205,281,352); + lake1Tree2 = new palmTree(4.983713f,-0.3028361f,6.389566f,-0.03152565f,0.11608194f,-0.010372922f,-0.29448919f,-0.11764373f,187,64,148,205,281,352); + + + //create lake2 + x_start = 26; + z_start = 25.25f; + l = 3; + + h = 3f/128*(128 - 2 - 4); + w = 3f/128*(128 - 35 - 43); + dx = 3f/128*35; + dz = -3f/128*2; + + v = new vector[]{new vector(x_start+dx,-0.55f,z_start + dz), new vector(x_start + dx + w,-0.55f,z_start + dz), new vector(x_start + dx + w,-0.55f,z_start + dz-h), new vector(x_start+dx,-0.55f, z_start + dz-h)}; + + vector a2 = v[0].myClone(); + vector b2 = v[1].myClone(); + vector c2 = v[3].myClone(); + + a2.rotate_XZ(waveAngle); + b2.rotate_XZ(waveAngle); + c2.rotate_XZ(waveAngle); + + water2 = new polygon3D(v,a2, b2, c2, mainThread.textures[54],w*1.2f,h*1.1f, 6); + + v = new vector[]{new vector(x_start+dx,-0.5001f,z_start + dz), new vector(x_start + dx + w,-0.5001f,z_start + dz), new vector(x_start + dx + w,-0.5001f,z_start + dz-h), new vector(x_start+dx,-0.5001f, z_start + dz-h)}; + groundRemover2 = new polygon3D(v, v[0], v[1], v[3], null,l,l, 4); + + lake2 = createLake(mainThread.textures[57].heightmap, x_start, z_start, l , 128, 2, 4, 35, 43); + lake2PolyCount = index + 1; + lakeCenter2 = new vector(x_start+1.5f, -0.5001f, z_start-1.5f); + lakeCenterTemp2 = new vector(0,0,0); + goldMine2 = new goldMine(27.5f,-0.80f, 23.75f, 30000); + + + //create lake3 + x_start = 9; + z_start = 27f; + l = 3.5f; + + w = l/128*(128 - 18 - 20); + h = l/128*(128 - 17 - 27); + dx = l/128*18; + dz = -l/128*17; + + v = new vector[]{new vector(x_start+dx,-0.55f,z_start + dz), new vector(x_start + dx + w,-0.55f,z_start + dz), new vector(x_start + dx + w,-0.55f,z_start + dz-h), new vector(x_start+dx,-0.55f, z_start + dz-h)}; + vector a3 = v[0].myClone(); + vector b3 = v[1].myClone(); + vector c3 = v[3].myClone(); + + a3.rotate_XZ(waveAngle); + b3.rotate_XZ(waveAngle); + c3.rotate_XZ(waveAngle); + + water3 = new polygon3D(v, a3, b3, c3, mainThread.textures[54],w*1.2f,h*1.1f, 6); + + v = new vector[]{new vector(x_start+dx,-0.5001f,z_start + dz), new vector(x_start + dx + w,-0.5001f,z_start + dz), new vector(x_start + dx + w,-0.5001f,z_start + dz-h), new vector(x_start+dx,-0.5001f, z_start + dz-h)}; + groundRemover3 = new polygon3D(v, v[0], v[1], v[3], null,l,l, 4); + + lake3 = createLake(mainThread.textures[58].heightmap, x_start, z_start, l , 128, 17, 27, 18, 20); + lake3PolyCount = index + 1; + lakeCenter3 = new vector(x_start+1.5f, -0.5001f, z_start-1.5f); + lakeCenterTemp3 = new vector(0,0,0); + + + //create lake 4 + x_start = 25; + z_start = 13f; + l = 3f; + + w = l/128*(128 - 1 - 2); + h = l/128*(128 - 4 - 0); + dx = l/128*1; + dz = -l/128*4; + + v = new vector[]{new vector(x_start+dx,-0.55f,z_start + dz), new vector(x_start + dx + w,-0.55f,z_start + dz), new vector(x_start + dx + w,-0.55f,z_start + dz-h), new vector(x_start+dx,-0.55f, z_start + dz-h)}; + vector a4 = v[0].myClone(); + vector b4 = v[1].myClone(); + vector c4 = v[3].myClone(); + + a4.rotate_XZ(waveAngle); + b4.rotate_XZ(waveAngle); + c4.rotate_XZ(waveAngle); + + water4 = new polygon3D(v, a4, b4, c4, mainThread.textures[54],w*1.2f,h*1.1f, 6); + + v = new vector[]{new vector(x_start+dx,-0.5001f,z_start + dz), new vector(x_start + dx + w,-0.5001f,z_start + dz), new vector(x_start + dx + w,-0.5001f,z_start + dz-h), new vector(x_start+dx,-0.5001f, z_start + dz-h)}; + groundRemover4 = new polygon3D(v, v[0], v[1], v[3], null,l,l, 4); + + lake4 = createLake(mainThread.textures[59].heightmap, x_start, z_start, l , 128, 4, 0, 1, 2); + lake4PolyCount = index + 1; + lakeCenter4 = new vector(x_start+1.5f, -0.5001f, z_start-1.5f); + lakeCenterTemp4 = new vector(0,0,0); + + + //create road + road = new polygon3D[600]; + roadCorner1 = new vector(4f,-0.500f, -3f); + roadCorner2 = new vector(4.36f,-0.500f,-3f); + roadCorner3 = new vector(4f,-0.500f, -3f); + roadCorner4 = new vector(4.36f,-0.500f,-3f); + roadDirection = new vector(0, 0, 1); + roadSideDirection = new vector(-1,0,0); + roadNormal = new vector(0,1,0); + roadCentre = new vector(0,0,0); + roadMarkCorner1 = new vector(0,0,0); + roadMarkCorner2 = new vector(0,0,0); + roadMarkCorner3 = new vector(0,0,0); + roadMarkCorner4 = new vector(0,0,0); + + roadSideCorner1 = new vector(0,0,0); + roadSideCorner2 = new vector(0,0,0); + roadSideCorner3 = new vector(0,0,0); + roadSideCorner4 = new vector(0,0,0); + + lightPoles = new lightPole[100]; + + + createStrightRoadSection(4.5f); + createCurvedRoadSection(0.25f,80,-4); + createCurvedRoadSection(0.25f,40,4); + createStrightRoadSection(5); + createCurvedRoadSection(0.25f,40,4); + createStrightRoadSection(0.5f); + createCurvedRoadSection(0.25f,88,-4); + createStrightRoadSection(1.5f); + createCurvedRoadSection(0.25f,72,4); + createStrightRoadSection(5f); + createCurvedRoadSection(0.25f,64,-4); + createCurvedRoadSection(0.25f,80,5); + createStrightRoadSection(5f); + + lightPoles[5].vanish(); + lightPoles[18].vanish(); + lightPoles[21].vanish(); + lightPoles[28].vanish(); + lightPoles[40].vanish(); + } + + + public void createStrightRoadSection(float l){ + roadCorner1.set(roadCorner3); + roadCorner2.set(roadCorner4); + roadCentre.set(roadCorner1); + roadCentre.add(roadCorner2); + roadCentre.scale(0.5f); + roadCentre.add(roadDirection, l); + roadCorner3.set(roadCentre); + roadCorner3.add(roadSideDirection, 0.18f); + roadCorner4.set(roadCentre); + roadCorner4.add(roadSideDirection, -0.18f); + vector[] v = new vector[]{roadCorner3.myClone(), roadCorner4.myClone(), roadCorner2.myClone(), roadCorner1.myClone()}; + road[roadPolygonIndex] = new polygon3D(v, new vector(4f,-0.500f,35f), new vector(4.5f,-0.500f,35f), new vector(4f,-0.500f, -3f), mainThread.textures[61], 1f,80f, 2); + roadPolygonIndex++; + + roadSideCorner1.set(roadCorner3); + roadSideCorner1.add(roadSideDirection, 0.03f); + roadSideCorner4.set(roadCorner1); + roadSideCorner4.add(roadSideDirection, 0.03f); + v = new vector[]{roadSideCorner1.myClone(), roadCorner3.myClone(), roadCorner1.myClone(), roadSideCorner4.myClone()}; + road[roadPolygonIndex] = new polygon3D(v,v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[62], 0.2f, l, 8); + roadPolygonIndex++; + + roadSideCorner2.set(roadCorner4); + roadSideCorner2.add(roadSideDirection, -0.03f); + roadSideCorner3.set(roadCorner2); + roadSideCorner3.add(roadSideDirection, -0.03f); + v = new vector[]{roadCorner4.myClone(), roadSideCorner2.myClone(), roadSideCorner3.myClone(), roadCorner2.myClone()}; + road[roadPolygonIndex] = new polygon3D(v,v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[63], 1f, l, 8); + roadPolygonIndex++; + + + int numberOfSegments = (int)(l/0.25f); + roadCentre.y+=0.001f; + for(int i = 0; i < numberOfSegments; i++){ + + roadMarkCorner1.set(roadCentre); + roadMarkCorner1.add(roadSideDirection, 0.008f); + roadMarkCorner2.set(roadMarkCorner1); + roadMarkCorner2.add(roadSideDirection, -0.016f); + roadMarkCorner3.set(roadMarkCorner2); + roadMarkCorner3.add(roadDirection, -0.1f); + roadMarkCorner4.set(roadMarkCorner1); + roadMarkCorner4.add(roadDirection, -0.1f); + roadCentre.add(roadDirection, -0.25f); + + v = new vector[]{roadMarkCorner1.myClone(), roadMarkCorner2.myClone(), roadMarkCorner3.myClone(), roadMarkCorner4.myClone()}; + road[roadPolygonIndex] = new polygon3D(v, v[0], v[1], v[3] , mainThread.textures[60], 1f,1f, 1); + roadPolygonIndex++; + + if(i%4 ==0){ + + + if(numOfLightPoles == 29) + lightPoles[numOfLightPoles] = new lightPole(roadCentre.x-roadSideDirection.x*0.26f + 0.5f, roadCentre.y, roadCentre.z - roadSideDirection.z*0.26f,(curveAngle + 90)%360); + else + if(numOfLightPoles%2==0) + lightPoles[numOfLightPoles] = new lightPole(roadCentre.x+roadSideDirection.x*0.26f, roadCentre.y, roadCentre.z + roadSideDirection.z*0.26f,(curveAngle + 270)%360); + else + lightPoles[numOfLightPoles] = new lightPole(roadCentre.x-roadSideDirection.x*0.26f, roadCentre.y, roadCentre.z - roadSideDirection.z*0.26f,(curveAngle + 90)%360); + numOfLightPoles++; + } + } + } + + + public void createCurvedRoadSection(float l, int angle, int turnRate){ + for(int i = 0; i < angle; i+=Math.abs(turnRate)){ + roadCorner1.set(roadCorner3); + roadCorner2.set(roadCorner4); + roadCentre.set(roadCorner1); + roadCentre.add(roadCorner2); + roadCentre.scale(0.5f); + int realTurnRate = turnRate; + if(realTurnRate < 0) + realTurnRate = (360 + realTurnRate)%360; + roadDirection.rotate_XZ(realTurnRate); + + curveAngle = (curveAngle + turnRate + 360)%360; + + roadCentre.add(roadDirection, l); + roadSideDirection.rotate_XZ(realTurnRate); + roadCorner3.set(roadCentre); + roadCorner3.add(roadSideDirection, 0.18f); + roadCorner4.set(roadCentre); + roadCorner4.add(roadSideDirection, -0.18f); + vector[] v = new vector[]{roadCorner3.myClone(), roadCorner4.myClone(), roadCorner2.myClone(), roadCorner1.myClone()}; + road[roadPolygonIndex] = new polygon3D(v, new vector(4f,-0.5f,35f), new vector(4.5f,-0.5f,35f), new vector(4f,-0.5f, -3f), mainThread.textures[61], 1f,80f, 2); + roadPolygonIndex++; + + roadSideCorner1.set(roadCorner3); + roadSideCorner1.add(roadSideDirection, 0.03f); + roadSideCorner4.set(roadCorner1); + roadSideCorner4.add(roadSideDirection, 0.03f); + v = new vector[]{roadSideCorner1.myClone(), roadCorner3.myClone(), roadCorner1.myClone(), roadSideCorner4.myClone()}; + road[roadPolygonIndex] = new polygon3D(v,v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[62], 0.2f, l*1.5f, 8); + roadPolygonIndex++; + + + roadSideCorner2.set(roadCorner4); + roadSideCorner2.add(roadSideDirection, -0.03f); + roadSideCorner3.set(roadCorner2); + roadSideCorner3.add(roadSideDirection, -0.03f); + v = new vector[]{roadCorner4.myClone(), roadSideCorner2.myClone(), roadSideCorner3.myClone(), roadCorner2.myClone()}; + road[roadPolygonIndex] = new polygon3D(v,v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[63], 1f, l*1.5f, 8); + roadPolygonIndex++; + + roadCentre.y+=0.0001f; + roadMarkCorner1.set(roadCentre); + roadMarkCorner1.add(roadSideDirection, 0.008f); + roadMarkCorner2.set(roadMarkCorner1); + roadMarkCorner2.add(roadSideDirection, -0.016f); + roadMarkCorner3.set(roadMarkCorner2); + roadMarkCorner3.add(roadDirection, -0.1f); + roadMarkCorner4.set(roadMarkCorner1); + roadMarkCorner4.add(roadDirection, -0.1f); + + v = new vector[]{roadMarkCorner1.myClone(), roadMarkCorner2.myClone(), roadMarkCorner3.myClone(), roadMarkCorner4.myClone()}; + road[roadPolygonIndex] = new polygon3D(v, v[0], v[1], v[3] , mainThread.textures[60], 1f,1f, 1); + roadPolygonIndex++; + + if((i/Math.abs(turnRate))%4 ==0){ + if(numOfLightPoles%2==0) + lightPoles[numOfLightPoles] = new lightPole(roadCentre.x+roadSideDirection.x*0.26f, roadCentre.y, roadCentre.z + roadSideDirection.z*0.26f,(curveAngle + 270)%360); + else + lightPoles[numOfLightPoles] = new lightPole(roadCentre.x-roadSideDirection.x*0.26f, roadCentre.y, roadCentre.z - roadSideDirection.z*0.26f,(curveAngle + 90)%360); + numOfLightPoles++; + } + + + } + } + + public polygon3D[] createLake(int[] hm, float x_start, float z_start, float l, int blocks, int xBlockStart, int xBlockEnd, int yBlockStart, int yBlockEnd){ + + polygon3D[] lake = new polygon3D[blocks*blocks*2]; + + //load height map + float[] heightmap = new float[(blocks+1)*(blocks+1)]; + + int interval = (int)(Math.sqrt(hm.length) - 1)/blocks; + + float baseHeight = -0.5001f; + float heightScale = -0.001f; + int widthPluseOne = (int)(Math.sqrt(hm.length)); + for(int i = 0; i < (blocks+1); i++){ + for(int j =0; j< (blocks+1); j++){ + if(hm[j*interval + i*interval*widthPluseOne] < 2) + hm[j*interval + i*interval*widthPluseOne] = 0; + heightmap[j + i * (blocks+1)] = ((float)hm[j*interval + i*interval*widthPluseOne])*heightScale +baseHeight; + + } + } + + float dx = l/ blocks; + float dz = -l/ blocks; + + vector tempVector0 = new vector(0,0,0); + vector tempVector1 = new vector(0,0,0); + vector tempVector2 = new vector(0,0,0); + vector tempVector3 = new vector(0,0,0); + + vector deltaX = new vector(0,0,0); + vector deltaZ = new vector(0,0,0); + vector origin = new vector(0,0,0); + vector top = new vector(0,0,0); + vector bot = new vector(0,0,0); + vector[] v; + + + + + index = 0; + + + byte[] diffuses = new byte[blocks * blocks * 2]; + + for(int i = 0; i < diffuses.length; i++) + diffuses[i] = 73; + + for(int i = xBlockStart; i < blocks-xBlockEnd; i++){ + for(int j = yBlockStart; j < blocks - yBlockEnd; j++){ + int block1 = j + i*(blocks+1); + int block2 = j + 1 + i*(blocks+1); + int block3 = j + 1 + (i +1)*(blocks+1); + int block4 = j + (i +1)*(blocks+1); + + tempVector0.set(x_start + dx*j, heightmap[block1], z_start + dz*i); + tempVector1.set(x_start + dx*(j+1), heightmap[block2], z_start + dz*i); + tempVector2.set(x_start + dx*(j+1), heightmap[block3], z_start + dz*(i+1)); + tempVector3.set(x_start + dx*j, heightmap[block4], z_start + dz*(i+1)); + + + boolean sameHeight = heightmap[block1] == heightmap[block2] && + heightmap[block2] == heightmap[block3] && + heightmap[block3] == heightmap[block4]; + + boolean belowWaterLevel = heightmap[block1] < -0.55f && heightmap[block2] < -0.55f && heightmap[block3] < -0.55f && heightmap[block4] < -0.55f; + + + boolean belowGround = tempVector0.y < -0.5801f && tempVector1.y < -0.5801f && tempVector2.y < -0.5801f && tempVector3.y < -0.5801f; + + if(belowGround){ + + tokenObject t = new tokenObject(((int)(tempVector0.x/0.25f)) * 0.25f + 0.125f,tempVector0.y, ((int)(tempVector0.z/0.25f)) * 0.25f + 0.125f, 64 << 16 | 64 << 8 | 255); + if(!t.noNeedForThisToken){ + lakeObstacleIndex[lakeObstacleCount] = t.tileIndex; + lakeObstacleCount++; + } + + } + + + if(sameHeight){ + if(heightmap[block1] == -0.7551f) + continue; + + if(heightmap[block1] == -0.5001f){ + + v = new vector[]{tempVector0.myClone(), tempVector1.myClone(), tempVector2.myClone(), tempVector3.myClone()}; + deltaX.set(tempVector0); + deltaX.subtract(tempVector1); + + deltaZ.set(tempVector0); + deltaZ.subtract(tempVector3); + + origin.set(tempVector0); + origin.add(deltaX, j); + origin.add(deltaZ, i); + + top.set(origin); + top.add(deltaX, -blocks); + + bot.set(origin); + bot.add(deltaZ, -blocks); + + lake[index] = new polygon3D(v, origin.myClone(), top.myClone(), bot.myClone(), mainThread.textures[0], l,l,1); + lake[index].Ambient_I = Ambient_I; + lake[index].reflectance = reflectance; + lake[index].findDiffuse(); + + diffuses[j*2 + i*(blocks)*2] = (byte)lake[index].diffuse_I; + diffuses[j*2+1 + i*(blocks)*2] = (byte)lake[index].diffuse_I; + + index++; + continue; + } + } + + + if(belowWaterLevel){ + + v = new vector[]{tempVector0.myClone(), tempVector1.myClone(), tempVector2.myClone(), tempVector3.myClone()}; + deltaX.set(tempVector0); + deltaX.subtract(tempVector1); + + deltaZ.set(tempVector0); + deltaZ.subtract(tempVector3); + + origin.set(tempVector0); + origin.add(deltaX, j); + origin.add(deltaZ, i); + + top.set(origin); + top.add(deltaX, -blocks); + + bot.set(origin); + bot.add(deltaZ, -blocks); + + lake[index] = new polygon3D(v, origin.myClone(), top.myClone(), bot.myClone(), mainThread.textures[0], l,l,1); + lake[index].Ambient_I = Ambient_I; + lake[index].reflectance = reflectance; + lake[index].findDiffuse(); + + diffuses[j*2 + i*(blocks)*2] = (byte)lake[index].diffuse_I; + diffuses[j*2+1 + i*(blocks)*2] = (byte)lake[index].diffuse_I; + + index++; + continue; + } + + + v = new vector[]{tempVector0.myClone(), tempVector1.myClone(), tempVector3.myClone()}; + deltaX.set(tempVector0); + deltaX.subtract(tempVector1); + + deltaZ.set(tempVector0); + deltaZ.subtract(tempVector3); + + origin.set(tempVector0); + origin.add(deltaX, j); + origin.add(deltaZ, i); + + top.set(origin); + top.add(deltaX, -blocks); + + bot.set(origin); + bot.add(deltaZ, -blocks); + + lake[index] = new polygon3D(v, origin.myClone(), top.myClone(), bot.myClone(), mainThread.textures[0], l,l,5); + lake[index].Ambient_I = Ambient_I; + lake[index].reflectance = reflectance; + lake[index].findDiffuse(); + + diffuses[j*2 + i*(blocks)*2] = (byte)lake[index].diffuse_I; + + deltaX.set(tempVector3); + deltaX.subtract(tempVector2); + + deltaZ.set(tempVector1); + deltaZ.subtract(tempVector2); + + origin.set(tempVector2); + origin.add(deltaX); + origin.add(deltaZ); + origin.add(deltaX, j); + origin.add(deltaZ, i); + + top.set(origin); + top.add(deltaX, -blocks); + + bot.set(origin); + bot.add(deltaZ, -blocks); + + v = new vector[]{tempVector1.myClone(), tempVector2.myClone(), tempVector3.myClone()}; + lake[index+1] = new polygon3D(v, origin.myClone(), top.myClone(), bot.myClone(), mainThread.textures[0], l,l,5); + lake[index+1].Ambient_I = Ambient_I; + lake[index+1].reflectance = reflectance; + lake[index+1].findDiffuse(); + diffuses[j*2 +1 + i*(blocks)*2] = (byte)lake[index+1].diffuse_I; + + index+=2; + } + } + + v = new vector[]{new vector(x_start,-0.7551f,z_start), new vector(x_start + l,-0.7551f,z_start), new vector(x_start + l,-0.7551f,z_start - l), new vector(x_start,-0.7551f, z_start - l)}; + lake[index] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[0],l,l, 7); + lake[index].Ambient_I = Ambient_I; + lake[index].reflectance = reflectance; + lake[index].findDiffuse(); + + + for(int i = 0; i < index; i++){ + lake[i].parentObject = theToken; + } + + //create smooth lake ledges + int polygonIndex = 0; + for(int i = xBlockStart; i < blocks-xBlockEnd; i++){ + for(int j = yBlockStart; j < blocks - yBlockEnd; j++){ + int block1 = j + i*(blocks+1); + int block2 = j + 1 + i*(blocks+1); + int block3 = j + 1 + (i +1)*(blocks+1); + int block4 = j + (i +1)*(blocks+1); + + tempVector0.set(x_start + dx*j, heightmap[block1], z_start + dz*i); + tempVector1.set(x_start + dx*(j+1), heightmap[block2], z_start + dz*i); + tempVector2.set(x_start + dx*(j+1), heightmap[block3], z_start + dz*(i+1)); + tempVector3.set(x_start + dx*j, heightmap[block4], z_start + dz*(i+1)); + + + boolean sameHeight = heightmap[block1] == heightmap[block2] && + heightmap[block2] == heightmap[block3] && + heightmap[block3] == heightmap[block4]; + + boolean belowWaterLevel = heightmap[block1] < -0.55f && heightmap[block2] < -0.55f && heightmap[block3] < -0.55f && heightmap[block4] < -0.55f; + + + + if(sameHeight){ + if(heightmap[block1] == -0.7551f) + continue; + + if(heightmap[block1] == -0.5001f){ + polygonIndex++; + continue; + } + } + + if(belowWaterLevel){ + polygonIndex++; + continue; + } + + int currentBlockIndex = j*2 + i*(blocks)*2; + + lake[polygonIndex].diffuse[0] = (byte)((diffuses[currentBlockIndex]+ + diffuses[currentBlockIndex - 1] + + diffuses[currentBlockIndex - 2] + + diffuses[currentBlockIndex - 1 - blocks*2] + + diffuses[currentBlockIndex - blocks*2] + + diffuses[currentBlockIndex - blocks*2 + 1])/6); + + lake[polygonIndex].diffuse[1] = (byte)((diffuses[currentBlockIndex] + + diffuses[currentBlockIndex + 1]+ + diffuses[currentBlockIndex + 2]+ + diffuses[currentBlockIndex + 3 - blocks*2]+ + diffuses[currentBlockIndex + 2 - blocks*2]+ + diffuses[currentBlockIndex + 1 - blocks*2])/6); + + + try{ + lake[polygonIndex].diffuse[2] = (byte)((diffuses[currentBlockIndex]+ + diffuses[currentBlockIndex+1]+ + diffuses[currentBlockIndex+blocks*2]+ + diffuses[currentBlockIndex+blocks*2 - 1]+ + diffuses[currentBlockIndex+blocks*2 - 2]+ + diffuses[currentBlockIndex-1])/6); + }catch(Exception e){ + lake[polygonIndex].diffuse[2] = 73; + } + + + lake[polygonIndex+1].diffuse[0] = lake[polygonIndex].diffuse[1]; + + try{ + lake[polygonIndex+1].diffuse[1] = (byte)((diffuses[currentBlockIndex+1] + + diffuses[currentBlockIndex + 2] + + diffuses[currentBlockIndex + 3] + + diffuses[currentBlockIndex + 2 + blocks*2]+ + diffuses[currentBlockIndex + 1 + blocks*2]+ + diffuses[currentBlockIndex + blocks*2])/6); + }catch(Exception e){ + lake[polygonIndex+1].diffuse[1] = 73; + } + + lake[polygonIndex + 1].diffuse[2] = lake[polygonIndex].diffuse[2]; + + + polygonIndex+=2; + + } + } + + return lake; + + } + + public void update(){ + for(int i = 0; i < ground.length; i++){ + if(ground[i] != null){ + ground[i].update(); + } + } + + for(int i = 0; i < lakeObstacleCount; i++){ + mainThread.gridMap.currentObstacleMap[lakeObstacleIndex[i]] = false; + } + + + //update lake1 + lake1Visible = true; + lakeCenterTemp1.set(lakeCenter1); + lakeCenterTemp1.subtract(camera.position); + lakeCenterTemp1.rotate_XZ(camera.XZ_angle); + lakeCenterTemp1.rotate_YZ(camera.YZ_angle); + lakeCenterTemp1.updateLocation(); + + if(lakeCenterTemp1.screenX > 1118 || lakeCenterTemp1.screenX < - 350 || lakeCenterTemp1.screenY < - 140 || lakeCenterTemp1.screenY > 1062){ + lake1Visible = false; + } + + if(lake1Visible){ + water1.origin.x-=0.0015f; + water1.rightEnd.x-=0.0015f; + water1.bottomEnd.x -= 0.0015f; + water1.origin.z-=0.0015f; + water1.rightEnd.z-=0.0015f; + water1.bottomEnd.z -= 0.0015f; + + water1.update(); + groundRemover1.update(); + for(int i = 0; i < lake1PolyCount; i++){ + lake1[i].update(); + lake1[i].update_lightspace_withoutDrawing(); + } + + lake1Tree.update(); + lake1Tree2.update(); + } + + //update lake 2 + lake2Visible = true; + lakeCenterTemp2.set(lakeCenter2); + lakeCenterTemp2.subtract(camera.position); + lakeCenterTemp2.rotate_XZ(camera.XZ_angle); + lakeCenterTemp2.rotate_YZ(camera.YZ_angle); + lakeCenterTemp2.updateLocation(); + + if(lakeCenterTemp2.screenX > 1118 || lakeCenterTemp2.screenX < - 350 || lakeCenterTemp2.screenY < - 160 || lakeCenterTemp2.screenY > 1062){ + lake2Visible = false; + } + + if(lake2Visible){ + water2.origin.x-=0.0015f; + water2.rightEnd.x-=0.0015f; + water2.bottomEnd.x -= 0.0015f; + water2.origin.z-=0.0015f; + water2.rightEnd.z-=0.0015f; + water2.bottomEnd.z -= 0.0015f; + + water2.update(); + groundRemover2.update(); + for(int i = 0; i < lake2PolyCount; i++){ + lake2[i].update(); + lake2[i].update_lightspace_withoutDrawing(); + } + + goldMine2.update(); + } + + //update lake3 + lake3Visible = true; + lakeCenterTemp3.set(lakeCenter3); + lakeCenterTemp3.subtract(camera.position); + lakeCenterTemp3.rotate_XZ(camera.XZ_angle); + lakeCenterTemp3.rotate_YZ(camera.YZ_angle); + lakeCenterTemp3.updateLocation(); + + if(lakeCenterTemp3.screenX > 1118 || lakeCenterTemp3.screenX < - 350 || lakeCenterTemp3.screenY < - 150 || lakeCenterTemp3.screenY > 962){ + lake3Visible = false; + } + + + if(lake3Visible){ + water3.origin.x-=0.0015f; + water3.rightEnd.x-=0.0015f; + water3.bottomEnd.x -= 0.0015f; + water3.origin.z-=0.0015f; + water3.rightEnd.z-=0.0015f; + water3.bottomEnd.z -= 0.0015f; + + water3.update(); + groundRemover3.update(); + for(int i = 0; i < lake3PolyCount; i++){ + lake3[i].update(); + lake3[i].update_lightspace_withoutDrawing(); + } + } + + //update lake 4 + lake4Visible = true; + lakeCenterTemp4.set(lakeCenter4); + lakeCenterTemp4.subtract(camera.position); + lakeCenterTemp4.rotate_XZ(camera.XZ_angle); + lakeCenterTemp4.rotate_YZ(camera.YZ_angle); + lakeCenterTemp4.updateLocation(); + + if(lakeCenterTemp4.screenX > 1418 || lakeCenterTemp4.screenX < - 400 || lakeCenterTemp4.screenY < - 150 || lakeCenterTemp4.screenY > 1102){ + lake4Visible = false; + } + + + + if(lake4Visible){ + water4.origin.x-=0.0015f; + water4.rightEnd.x-=0.0015f; + water4.bottomEnd.x -= 0.0015f; + water4.origin.z-=0.0015f; + water4.rightEnd.z-=0.0015f; + water4.bottomEnd.z -= 0.0015f; + + water4.update(); + groundRemover4.update(); + for(int i = 0; i < lake4PolyCount; i++){ + lake4[i].update(); + lake4[i].update_lightspace_withoutDrawing(); + } + } + + //animate water surface + mainThread.textures[54].waterHeightMap = mainThread.textures[54].waterHeightMaps[(mainThread.frameIndex)%48]; + + for(int i = 0; i < roadPolygonIndex; i++){ + road[i].update(); + if(road[i].type == 1) + road[i].update_lightspace_withoutDrawing(); + } + + for(int i = 0; i < numOfLightPoles; i++){ + lightPoles[i].update(); + } + } + + public void draw(){ + if(lake1Visible) + groundRemover1.draw(); + + if(lake2Visible) + groundRemover2.draw(); + + if(lake3Visible) + groundRemover3.draw(); + + if(lake4Visible) + groundRemover4.draw(); + + + for(int i = 0; i < numOfLightPoles; i++){ + lightPoles[i].draw(); + } + + for(int i = 0; i < roadPolygonIndex; i++) + road[i].draw(); + + for(int i = 0; i < ground.length; i++) + ground[i].draw(); + + + + if(lake1Visible){ + for(int i = 0; i < lake1PolyCount; i++) + lake1[i].draw(); + + lake1Tree.draw(); + lake1Tree2.draw(); + water1.draw(); + } + + if(lake2Visible){ + for(int i = 0; i < lake2PolyCount; i++) + lake2[i].draw(); + + goldMine2.draw(); + water2.draw(); + + } + + if(lake3Visible){ + for(int i = 0; i < lake3PolyCount; i++) + lake3[i].draw(); + + water3.draw(); + + } + + if(lake4Visible){ + for(int i = 0; i < lake4PolyCount; i++){ + lake4[i].draw(); + } + + water4.draw(); + + } + + } + +} diff --git a/core/textRenderer.java b/core/textRenderer.java new file mode 100644 index 0000000..6875b28 --- /dev/null +++ b/core/textRenderer.java @@ -0,0 +1,242 @@ +package core; + +import java.awt.Image; +import java.awt.image.PixelGrabber; + +import javax.imageio.ImageIO; + +//handle text rendering + + +public class textRenderer { + + public int[] fontBuffer, star, halfStar; + public int[][] chars; + + public void init(){ + fontBuffer = new int[665*16]; + star = new int[12*12]; + halfStar = new int[12*12]; + + //load font image + Image img = null; + try{ + img = ImageIO.read(getClass().getResource("../images/" + "font.jpg")); + }catch(Exception e){ + e.printStackTrace(); + } + + + PixelGrabber pg = new PixelGrabber(img, 0, 0, 665, 16, fontBuffer, 0, 665); + try { + pg.grabPixels(); + }catch(Exception e){ + e.printStackTrace(); + } + + //create character bitmaps + chars = new int[93][16*7]; + for(int i = 0; i < 93; i++){ + for(int j = 0; j < 16; j++){ + for(int k = 0; k < 7; k++){ + chars[i][k+ j*7] = fontBuffer[i*7 + k + j*665]; + } + } + } + + //load half star images + try{ + img = ImageIO.read(getClass().getResource("../images/" + "84.jpg")); + }catch(Exception e){ + e.printStackTrace(); + } + + pg = new PixelGrabber(img, 0, 0, 12, 12, halfStar, 0, 12); + try { + pg.grabPixels(); + }catch(Exception e){ + e.printStackTrace(); + } + + + //load star images + try{ + img = ImageIO.read(getClass().getResource("../images/" + "85.jpg")); + }catch(Exception e){ + e.printStackTrace(); + } + + pg = new PixelGrabber(img, 0, 0, 12, 12, star, 0, 12); + try { + pg.grabPixels(); + }catch(Exception e){ + e.printStackTrace(); + } + + } + + public void drawFlashingText(int xPos, int yPos, String text, int[] screen){ + int pixel, SpriteValue, screenValue, overflow, screenIndex; + int MASK7Bit = 0xFEFEFF; + + char[] theText = text.toCharArray(); + + int t = (int)(35 * Math.sin((double)mainThread.frameIndex/7)) + 35; + if(t > 64) + t = 64; + + + + for(int i = 0; i < theText.length; i++){ + for(int j = 0; j < 16; j++){ + for(int k = 0; k < 7; k++){ + screenIndex = 768*yPos + xPos + i*7 + k + j*768; + + screenValue = screen[screenIndex]; + SpriteValue = chars[theText[i] - 32][k+ j*7]&255; + SpriteValue = SpriteValue * t / 64; + SpriteValue = SpriteValue << 16 | SpriteValue << 8 | SpriteValue; + + + pixel=(SpriteValue&MASK7Bit)+(screenValue&MASK7Bit); + overflow=pixel&0x1010100; + overflow=overflow-(overflow>>8); + screen[screenIndex] = overflow|pixel; + } + } + } + + } + + public void drawText(int xPos, int yPos, String text, int[] screen, int r, int g, int b){ + int pixel, SpriteValue, screenValue, overflow, screenIndex; + int MASK7Bit = 0xFEFEFF; + + char[] theText = text.toCharArray(); + + for(int i = 0; i < theText.length; i++){ + for(int j = 0; j < 16; j++){ + for(int k = 0; k < 7; k++){ + screenIndex = 768*yPos + xPos + i*7 + k + j*768; + + screenValue = screen[screenIndex]; + SpriteValue = chars[theText[i] - 32][k+ j*7]&255; + SpriteValue = (r*SpriteValue/256) << 16 | (g*SpriteValue/256) << 8 | (b*SpriteValue/256); + + + pixel=(SpriteValue&MASK7Bit)+(screenValue&MASK7Bit); + overflow=pixel&0x1010100; + overflow=overflow-(overflow>>8); + screen[screenIndex] = overflow|pixel; + } + } + } + } + + public void drawText_outline(int xPos, int yPos, String text, int[] screen, int insideColor, int outlineColor){ + int SpriteValue, screenIndex, width, height; + + char[] theText = text.toCharArray(); + + //draw outline first + for(int i = 0; i < theText.length; i++){ + for(int j = 0; j < 16; j++){ + for(int k = 0; k < 7; k++){ + screenIndex = 768*yPos + xPos + i*7 + k + j*768; + + width = xPos + i*7 + k; + height = yPos + j; + + if(width < 1 || width > 766 || height < 1 || height > 510) + continue; + + SpriteValue = chars[theText[i] - 32][k+ j*7]&255; + if((SpriteValue & 0xff) > 100){ + screen[screenIndex+1] = outlineColor; + screen[screenIndex-1] = outlineColor; + screen[screenIndex+768] = outlineColor; + screen[screenIndex-768] = outlineColor; + screen[screenIndex+769] = outlineColor; + screen[screenIndex+767] = outlineColor; + screen[screenIndex-769] = outlineColor; + screen[screenIndex-767] = outlineColor; + + } + } + } + } + + //draw inside + for(int i = 0; i < theText.length; i++){ + for(int j = 0; j < 16; j++){ + for(int k = 0; k < 7; k++){ + screenIndex = 768*yPos + xPos + i*7 + k + j*768; + + width = xPos + i*7 + k; + height = yPos + j; + + if(width < 1 || width > 766 || height < 1 || height > 510) + continue; + + SpriteValue = chars[theText[i] - 32][k+ j*7]&255; + if((SpriteValue & 0xff) > 100){ + screen[screenIndex] = insideColor; + } + } + } + } + } + + + public void drawStarCharacter(int xPos, int yPos, int starShape, int[] screen, int insideColor, int outlineColor){ + //draw outline first + int[] starCharacter = star; + if(starShape == 1) + starCharacter = halfStar; + + int SpriteValue, screenIndex, width, height; + for(int j = 0; j < 12; j++){ + for(int k = 0; k < 12; k++){ + screenIndex = 768*yPos + xPos + k + j*768; + + width = xPos + k; + height = yPos + j; + + if(width < 1 || width > 766 || height < 1 || height > 510) + continue; + + SpriteValue = (starCharacter[k+ j*12]&0xff0000) >> 16; + if((SpriteValue & 0xff) > 30){ + screen[screenIndex+1] = outlineColor; + screen[screenIndex-1] = outlineColor; + screen[screenIndex+768] = outlineColor; + screen[screenIndex-768] = outlineColor; + screen[screenIndex+769] = outlineColor; + screen[screenIndex+767] = outlineColor; + screen[screenIndex-769] = outlineColor; + screen[screenIndex-767] = outlineColor; + + } + } + } + + for(int j = 0; j < 12; j++){ + for(int k = 0; k < 12; k++){ + screenIndex = 768*yPos + xPos + k + j*768; + + width = xPos+ k; + height = yPos + j; + + if(width < 1 || width > 766 || height < 1 || height > 510) + continue; + + SpriteValue = (starCharacter[k+ j*12]&0xff0000) >> 16; + if((SpriteValue & 0xff) > 30){ + screen[screenIndex] = insideColor; + } + } + } + + } + +} diff --git a/core/texture.java b/core/texture.java new file mode 100644 index 0000000..fb8e75e --- /dev/null +++ b/core/texture.java @@ -0,0 +1,389 @@ +package core; + +//the texture dimension should only be power of 2 +import java.awt.image.PixelGrabber; +import java.awt.*; + +public class texture { + //holds the pixel data in 16bits color format + public static int[] textureBuffer; + + //hold mipmaps of the original texture + public short[] pixelData; + + public byte[] pixelDataByte; + + //stores a sequence of explosion texture + public int[][] explosions; + + //stores a sequence of smoke texture + public int[][] smoke; + + //store height map + public int[] heightmap; + + //stores animated light maps created by an explosion + public short[][] explosionAura; + + //store displacement map + public short[] displacementMap; + + //store height map that associated with water texture + public byte[] waterHeightMap; + public byte[][] waterHeightMaps; + + + //store information that determine water surface movement direction (can be either up or down) + public boolean[] waterSurfaceDirections; + + //dimension of the texture + public int height, width, heightMask, widthMask, widthBits, heightBits; + + public String type; + + public int ID; + + + + + + + //produce texture based on input image + public texture(String type, Image img, int widthBits , int heightBits){ + this.widthBits = widthBits; + this.heightBits = heightBits; + + height = (int)Math.pow(2, heightBits); + width = (int)Math.pow(2, widthBits); + + heightMask = height -1; + widthMask = width - 1; + + this.type = type; + + + if(textureBuffer == null) + textureBuffer = new int[1024*1024]; //support a max texture size of 1024 * 1024 + + //load texture image and store it as an array of int + PixelGrabber pg = new PixelGrabber(img, 0, 0, width, height, textureBuffer, 0, width); + try { + pg.grabPixels(); + }catch(Exception e){ + e.printStackTrace(); + + } + + int r, g, b; + + + //create displacement map + if(type.equals("displacement")){ + displacementMap = new short[height*width]; + int dh = height; + int dw = width; + int i = 0; + + + for ( int y = 0; y < dh; y++ ) { + for ( int x = 0; x < dw; x++ ) { + int rgb = textureBuffer[i]; + r = (rgb >> 16) & 0xff; + g = (rgb >> 8) & 0xff; + b = rgb & 0xff; + textureBuffer[i] = (r+g+b) / 8; // An arbitrary scaling factor which gives a good range for "amount" + i++; + } + } + + + i = 0; + for ( int y = 0; y < dh; y++ ) { + int j1 = ((y+dh-1) % dh) * dw; + int j2 = y*dw; + int j3 = ((y+1) % dh) * dw; + for ( int x = 0; x < dw; x++ ) { + int k1 = (x+dw-1) % dw; + int k2 = x; + int k3 = (x+1) % dw; + int xMap = (textureBuffer[k1+j1] + textureBuffer[k1+j2] + textureBuffer[k1+j3] - textureBuffer[k3+j1] - textureBuffer[k3+j2] - textureBuffer[k3+j3]); + int yMap = (textureBuffer[k1+j3] + textureBuffer[k2+j3] + textureBuffer[k3+j3] - textureBuffer[k1+j1] - textureBuffer[k2+j1] - textureBuffer[k3+j1]); + + displacementMap[i] = (short)( ((textureBuffer[i] * 2 / 3) << 10) | ((xMap + 16) << 5) | (yMap + 16)); + + + i++; + } + } + + } + + + //create basic 15bits version of the original texture + if(type.equals("basic")){ + pixelData = new short[width*height]; + for(int i = 0; i < width*height; i ++){ + r = (textureBuffer[i] & 0x00ff0000)>>16; + g = (textureBuffer[i] & 0x0000ff00)>>8; + b = (textureBuffer[i] & 0x000000ff); + r = r/8; + g = g/8; + b = b/8; + pixelData[i] = (short)(r <<10 | g << 5 | b); + } + } + + //create a series of explosion texture + if(type.equals("explosion")){ + explosions = new int[16][64*64]; + + + Color temp = new Color(0,0,0); + for(int i = 0; i < 16; i++){ + int x = (i%4)*64; + int y = (i/4)*64; + + for(int j = 0; j < 64*64; j++){ + int color = textureBuffer[x+y*256 + j%64 + (j/64)*256]; + temp = new Color(color); + if(temp.getRed() < 40) + color = 0; + explosions[i][j] = color; + } + } + } + + + //create series of smoke texture + if(type.equals("smoke")){ + smoke = new int[40][64*64]; + Color temp = new Color(0,0,0); + for(int i = 0; i < 40; i++){ + int x = (i%8)*64; + int y = (i/8)*64; + + for(int j = 0; j < 64*64; j++){ + int color = textureBuffer[x+y*512 + j%64 + (j/64)*512]; + temp = new Color(color); + + r = ((color & 0xff0000) >> 16); + g = ((color & 0xff00) >> 8); + b = ((color & 0xff)); + + if(r < 0) + r = 0; + if(g < 0) + g = 0; + if(b < 0) + b = 0; + color = r; + if(r < 5) + color = 0; + + + smoke[i][j] = color ; + + } + } + } + + //create height map + if(type.equals("heightmap")){ + heightmap = new int[(width+1)*(height+1)]; + + for(int i = 0; i < height; i++){ + for(int j = 0; j < width; j++){ + r = (textureBuffer[j + i* width] & 0xff); + if(i ==0 || i == (height-1) || j == 0 || j == (width -1)) + r = 0; + heightmap[j + i * (width+1)] = r; + + } + } + } + + + //create a series of light maps to stimulate the illumination created during an explosion + if(type.equals("explosion aura")){ + explosionAura = new short[16][width*height]; + for(int j = 0; j < 16; j++){ + for(int i = 0; i < width*height; i ++){ + int I = (((textureBuffer[i] & 0x00ff0000)>>16) - 20) * 5/9; + if(I < 80) + I = I*I*I*I/80/80/80; + explosionAura[j][i] = (short)(I/2.5 - 4*j); + } + } + } + } + + + + //produce texture based on input image + public texture(String type, Image img, Image img2, int widthBits , int heightBits){ + this.widthBits = widthBits; + this.heightBits = heightBits; + + height = (int)Math.pow(2, heightBits); + width = (int)Math.pow(2, widthBits); + + heightMask = height -1; + widthMask = width - 1; + + this.type = type; + + if(textureBuffer == null) + textureBuffer = new int[1024*1024]; //support a max texture size of 1024 * 1024 + + //load texture image and store it as an array of int + PixelGrabber pg = new PixelGrabber(img, 0, 0, width, height, textureBuffer, 0, width); + try { + pg.grabPixels(); + }catch(Exception e){ + e.printStackTrace(); + + } + + int r, g, b; + + + //create displacement map + if(type.equals("water")){ + displacementMap = new short[height*width]; + waterHeightMap = new byte[height*width]; + waterHeightMaps = new byte[48][height*width]; + waterSurfaceDirections = new boolean[height*width]; + int dh = height; + int dw = width; + int i = 0; + + + for ( int y = 0; y < dh; y++ ) { + for ( int x = 0; x < dw; x++ ) { + int rgb = textureBuffer[i]; + r = (rgb >> 16) & 0xff; + g = (rgb >> 8) & 0xff; + b = rgb & 0xff; + textureBuffer[i] = (r+g+b) / 8; // An arbitrary scaling factor which gives a good range for "amount" + i++; + } + } + + + i = 0; + for ( int y = 0; y < dh; y++ ) { + int j1 = ((y+dh-1) % dh) * dw; + int j2 = y*dw; + int j3 = ((y+1) % dh) * dw; + for ( int x = 0; x < dw; x++ ) { + int k1 = (x+dw-1) % dw; + int k2 = x; + int k3 = (x+1) % dw; + int xMap = (textureBuffer[k1+j1] + textureBuffer[k1+j2] + textureBuffer[k1+j3] - textureBuffer[k3+j1] - textureBuffer[k3+j2] - textureBuffer[k3+j3]); + int yMap = (textureBuffer[k1+j3] + textureBuffer[k2+j3] + textureBuffer[k3+j3] - textureBuffer[k1+j1] - textureBuffer[k2+j1] - textureBuffer[k3+j1]); + + displacementMap[i] = (short)( ((xMap + 16) << 5) | (yMap + 16)); + + + i++; + } + } + + //load height map for the water surface + pg = new PixelGrabber(img2, 0, 0, width, height, textureBuffer, 0, width); + try { + pg.grabPixels(); + }catch(Exception e){ + e.printStackTrace(); + } + i = 0; + + for ( int y = 0; y < dh; y++ ) { + for ( int x = 0; x < dw; x++ ) { + int h = (int)(((textureBuffer[i]&0xff) - 160) * 0.9); + if(h < 0) + h = 0; + waterHeightMap[i] = (byte)(h); + if(waterHeightMap[i] > 63){ + System.out.println(waterHeightMap[i]); + waterHeightMap[i] = 63; + } + i++; + } + } + + for(i = 0; i < 256*256; i++){ + waterHeightMaps[0][i] = waterHeightMap[i]; + waterHeightMaps[15][i] = waterHeightMap[(3456 + 256*256-i-1)%(256*256)]; + waterHeightMaps[31][i] = waterHeightMap[i - i%256+ (255- i%256)]; + } + + for(int j = 1; j < 15; j++){ + for(i = 0; i < 256*256; i++ ){ + waterHeightMaps[j][i] = (byte)(waterHeightMaps[0][i] + (float)(waterHeightMaps[15][i] - waterHeightMaps[0][i])/15f*j); + } + } + + for(int j = 16; j < 31; j++){ + for(i = 0; i < 256*256; i++ ){ + waterHeightMaps[j][i] = (byte)(waterHeightMaps[15][i] + (float)(waterHeightMaps[31][i] - waterHeightMaps[15][i])/15f*(j-15)); + } + } + + for(int j = 32; j < 48; j++){ + for(i = 0; i < 256*256; i++ ){ + waterHeightMaps[j][i] = (byte)(waterHeightMaps[31][i] + (float)(waterHeightMaps[0][i] - waterHeightMaps[31][i])/16f*(j-31)); + } + } + + + } + + + } + + + //produce texture based on raw data + public texture(String type, short[] pixelData, int widthBits, int heightBits){ + this.widthBits = widthBits; + this.heightBits = heightBits; + + height = (int)Math.pow(2, heightBits); + width = (int)Math.pow(2, widthBits); + + heightMask = height -1; + widthMask = width - 1; + + this.pixelData = pixelData; + + this.type = type; + + } + + //produce texture based on a color + public texture(String type, int color, int widthBits, int heightBits){ + this.widthBits = widthBits; + this.heightBits = heightBits; + + height = (int)Math.pow(2, heightBits); + width = (int)Math.pow(2, widthBits); + + heightMask = height -1; + widthMask = width - 1; + + int r = ((color & 0xff0000) >> 16)/8; + int g = ((color & 0xff00) >> 8)/8; + int b = (color & 0xff)/8; + + short c = (short)(r <<10 | g << 5 | b); + + this.pixelData = new short[height * width]; + for(int i = 0; i < pixelData.length; i ++){ + pixelData[i] = c; + + } + + this.type = type; + + } +} diff --git a/core/vector.java b/core/vector.java new file mode 100644 index 0000000..1cfa54f --- /dev/null +++ b/core/vector.java @@ -0,0 +1,164 @@ +package core; + +public final class vector{ + //x, y, z component of the vector + public float x, y, z; + + //2d position on screen (from camera point of view) + public float screenX, screenY; + + //2d position on screen (from light point of view) + public float screenX_lightspace, screenY_lightspace; + + public final static int Z_length = 650; + + public final int orthogonalScale = 220; + + public static float old_X, old_Y, old_Z, zInverse, lengthInverse; + + //z component of the vector from light space + public float z_lightspace; + + public vector(float x, float y, float z){ + this.x = x; + this.y = y; + this.z = z; + + //calculate its 2D location on the screen + updateLocation(); + } + + public void add(vector v){ + x+=v.x; + y+=v.y; + z+=v.z; + } + + public void add(float a, float b, float c){ + x+=a; + y+=b; + z+=c; + } + + public void add(vector v, float scaler){ + x+=v.x*scaler; + y+=v.y*scaler; + z+=v.z*scaler; + } + + + public void subtract(vector v){ + x-=v.x; + y-=v.y; + z-=v.z; + } + + + //amplify each component of the vector by a number + public void scale(float d){ + x*=d; + y*=d; + z*=d; + } + + //normalize the vector + public void unit(){ + lengthInverse = 1/getLength(); + x = x*lengthInverse; + y = y*lengthInverse; + z = z*lengthInverse; + } + + + //find the magnitude of the vector + public float getLength(){ + return (float)Math.sqrt(x*x + y*y + z*z); + } + + //retrun the dot product of this vector with another vector + public float dot(vector v){ + return x*v.x + y*v.y + z*v.z; + } + + + public void cross(vector v1, vector v2){ + x = v1.y*v2.z - v1.z*v2.y; + y = v1.z*v2.x - v1.x*v2.z; + z = v1.x*v2.y - v1.y*v2.x; + } + + //rotate the vector along Y axis + public void rotate_XZ(int angle){ + float sin = gameData.sin[angle]; + float cos = gameData.cos[angle]; + old_X = x; + old_Z = z; + x = cos*old_X - sin*old_Z; + z = sin*old_X + cos*old_Z; + } + + //rotate the vector along X axis + public void rotate_YZ(int angle){ + float sin = gameData.sin[angle]; + float cos = gameData.cos[angle]; + old_Y = y; + old_Z = z; + y = cos*old_Y - sin*old_Z; + z = sin*old_Y + cos*old_Z; + } + + //rotate the vector along Z axis + public void rotate_XY(int angle){ + float sin = gameData.sin[angle]; + float cos = gameData.cos[angle]; + old_X = x; + old_Y = y; + x = cos*old_X - sin*old_Y; + y = sin*old_X + cos*old_Y; + } + + + //set all the component equal to the corresponding component of a given vector + public void set(vector v){ + x = v.x; + y = v.y; + z = v.z; + } + + public void set(float x, float y, float z){ + this.x = x; + this.y = y; + this.z = z; + } + + //set all the component to 0 + public void reset(){ + x = 0; + y = 0; + z = 0; + } + + public void updateLocation(){ + //find the 2D screen location of this vector + zInverse = Z_length/z; + screenX = x*zInverse + 384; + screenY = -y*zInverse + 256; + + } + + public void updateLocationOrthognal(){ + //find the 2D screen location of this vector in Orthographic projection + screenX_lightspace = x*orthogonalScale + 512; + screenY_lightspace = -y*orthogonalScale + 512; + } + + public vector myClone(){ + return new vector(x,y,z); + } + + public String toString(){ + return "(" + x + ", " + y + ", " + z + ")"; + } + + +} \ No newline at end of file diff --git a/enemyAI/.gitignore b/enemyAI/.gitignore new file mode 100644 index 0000000..4d78972 --- /dev/null +++ b/enemyAI/.gitignore @@ -0,0 +1,10 @@ +/baseExpensionAI.class +/buildingManagerAI.class +/combatManagerAI.class +/defenseManagerAI.class +/economyManagerAI.class +/enemyCommander.class +/mapAwarenessAI.class +/microManagementAI.class +/scoutingManagerAI.class +/unitProductionAI.class diff --git a/enemyAI/baseExpensionAI.java b/enemyAI/baseExpensionAI.java new file mode 100644 index 0000000..0b5cc96 --- /dev/null +++ b/enemyAI/baseExpensionAI.java @@ -0,0 +1,417 @@ +package enemyAI; + +import core.baseInfo; +import core.gameData; +import core.mainThread; +import core.vector; +import entity.*; + +public class baseExpensionAI { + public baseInfo theBaseInfo; + public int[] expensionPiorityList; + public stealthTank[] scouts; + public constructionVehicle myMCV; + public boolean isExpanding; + public int targetExpension; + public goldMine[] goldMines; + public goldMine expensionGoldMine; + public int numberOfActiveScout; + public int numberOfStealthTankScout; + public int frameAI; + public vector temp; + + + + public baseExpensionAI(baseInfo theBaseInfo){ + this.theBaseInfo = theBaseInfo; + frameAI = 0; + temp = new vector(0,0,0); + + //generate a expension piority list + expensionPiorityList = new int[5]; + + int randomeNumber = gameData.getRandom(); + + if(randomeNumber < 170) + expensionPiorityList = new int[]{5,6,2,3,7}; + else if(randomeNumber >= 170 && randomeNumber < 340) + expensionPiorityList = new int[]{5,6,3,2,7}; + else if(randomeNumber >= 340 && randomeNumber < 510) + expensionPiorityList = new int[]{5,2,6,3,7}; + else if(randomeNumber >= 510 && randomeNumber < 680) + expensionPiorityList = new int[]{5,2,3,6,7}; + else if(randomeNumber >= 680 && randomeNumber < 850) + expensionPiorityList = new int[]{5,3,6,2,7}; + else + expensionPiorityList = new int[]{5,3,2,6,7}; + + scouts = new stealthTank[3]; + + + } + + + public void processAI(){ + + + frameAI++; + + if(goldMines == null) + goldMines = mainThread.theAssetManager.goldMines; + + //find the next potential expansion location + for(int i = 0; i<5; i++){ + if(!hasRefineryNearTheGoldmine(goldMines[expensionPiorityList[i]]) && !hasConstructionYardNearGoldMine(goldMines[expensionPiorityList[i]]) && goldMines[expensionPiorityList[i]].goldDeposite > 17500){ + targetExpension = i; + break; + } + } + + expensionGoldMine = goldMines[expensionPiorityList[targetExpension]]; + + //produce a total of 3 scout units, check if there are any stealth tank in the production + numberOfActiveScout = 0; + numberOfStealthTankScout = 0; + for(int i = 0; i < scouts.length; i++){ + if(scouts[i] != null && scouts[i].currentHP >0){ + numberOfActiveScout++; + if(scouts[i].type == 6) + numberOfStealthTankScout++; + } + } + + int numberOfStealthTankOnQueue = 0; + for(int i = 0; i < mainThread.theAssetManager.factories.length; i++){ + if(mainThread.theAssetManager.factories[i] != null && mainThread.theAssetManager.factories[i].teamNo != 0){ + numberOfStealthTankOnQueue += mainThread.theAssetManager.factories[i].numOfStealthTankOnQueue; + } + } + + int numberOfUnassignedStealthTank = 0; + for(int i = 0; i < mainThread.theAssetManager.stealthTanks.length; i++){ + if(mainThread.theAssetManager.stealthTanks[i] != null && mainThread.theAssetManager.stealthTanks[i].teamNo != 0 && mainThread.ec.theMapAwarenessAI.mapAsset[mainThread.theAssetManager.stealthTanks[i].ID] == null) + numberOfUnassignedStealthTank++; + + } + + + int scoutsNumberLimit = scouts.length; + if(frameAI <= 800) + scoutsNumberLimit = scouts.length - 5; + + + + //pick an idle factory to produce stealth tank. If there is no idle factory, cancel the one that is building lightTank + if(numberOfActiveScout + numberOfStealthTankOnQueue + numberOfUnassignedStealthTank < scoutsNumberLimit && theBaseInfo.canBuildStealthTank){ + for(int i = 0; i < mainThread.theAssetManager.factories.length; i++){ + if(mainThread.theAssetManager.factories[i] != null && mainThread.theAssetManager.factories[i].teamNo != 0){ + if(mainThread.theAssetManager.factories[i].lightTankProgress < 240 || mainThread.theAssetManager.factories[i].isIdle()){ + mainThread.theAssetManager.factories[i].cancelItemFromProductionQueue(factory.lightTankType); + mainThread.theAssetManager.factories[i].buildStealthTank(); + break; + } + } + } + + } + + //build a mcv when the current mine is running low + myMCV = null; + for(int i = 0; i < mainThread.theAssetManager.constructionVehicles.length; i++){ + if( mainThread.theAssetManager.constructionVehicles[i] != null && mainThread.theAssetManager.constructionVehicles[i].currentHP >0 && mainThread.theAssetManager.constructionVehicles[i].teamNo != 0){ + myMCV = mainThread.theAssetManager.constructionVehicles[i]; + } + } + + int lowGoldmineThreshold = 17500; + + + if(mainThread.ec.theEconomyManagerAI.preferedGoldMine == mainThread.theAssetManager.goldMines[4]) + lowGoldmineThreshold = 12500; + + if(myMCV == null && expensionGoldMine.goldDeposite >= 17500 && (mainThread.ec.theEconomyManagerAI.preferedGoldMine.goldDeposite < lowGoldmineThreshold || + (mainThread.ec.theEconomyManagerAI.preferedGoldMine == expensionGoldMine && !hasConstructionYardNearGoldMine(expensionGoldMine) && !hasRefineryNearTheGoldmine(expensionGoldMine)))){ + + int numberOfMCVOnQueue = 0; + for(int i = 0; i < mainThread.theAssetManager.factories.length; i++){ + if(mainThread.theAssetManager.factories[i] != null && mainThread.theAssetManager.factories[i].teamNo != 0){ + numberOfMCVOnQueue += mainThread.theAssetManager.factories[i].numOfMCVOnQueue; + } + } + + + + if(numberOfMCVOnQueue == 0 && theBaseInfo.canBuildMCV){ + for(int i = 0; i < mainThread.theAssetManager.factories.length; i++){ + if(mainThread.theAssetManager.factories[i] != null && mainThread.theAssetManager.factories[i].teamNo != 0){ + //if(main.theAssetManager.factories[i].lightTankProgress < 240 || main.theAssetManager.factories[i].isIdle()){ + mainThread.theAssetManager.factories[i].cancelItemFromProductionQueue(factory.lightTankType); + mainThread.theAssetManager.factories[i].cancelItemFromProductionQueue(factory.rocketTankType); + mainThread.theAssetManager.factories[i].cancelItemFromProductionQueue(factory.stealthTankType); + mainThread.theAssetManager.factories[i].cancelItemFromProductionQueue(factory.heavyTankType); + mainThread.theAssetManager.factories[i].buildMCV(); + break; + //} + } + } + } + } + + //move mcv to the next expension location + if(myMCV != null){ + isExpanding = true; + if(myMCV.getDistance(expensionGoldMine) > 2 && !(myMCV.destinationX == expensionGoldMine.centre.x && myMCV.destinationY == expensionGoldMine.centre.z)){ + myMCV.moveTo(expensionGoldMine.centre.x, expensionGoldMine.centre.z); + myMCV.currentCommand = solidObject.move; + + }else if(frameAI%5 == 0 && myMCV.getDistance(expensionGoldMine) <=2){ + myMCV.moveTo(expensionGoldMine.centre.x + (float)(gameData.getRandom() -512) * 2 / 1024, expensionGoldMine.centre.z + (float)(gameData.getRandom() -512) * 2 / 1024); + myMCV.currentCommand = solidObject.move; + } + + //change the preferred gold mine to the one near the new expension once MCV is deployed + if(myMCV.getDistance(expensionGoldMine) < 2 && myMCV.getDistance(expensionGoldMine) > 0.75 && myMCV.canBeDeployed()){ + myMCV.expand(); + mainThread.ec.theEconomyManagerAI.preferedGoldMine = expensionGoldMine; + } + }else{ + isExpanding = false; + } + + + //send scouts to guard mining expansion + if(!isExpanding){ + boolean scoutReachesExpension = false; + for(int i = 0; i < scouts.length; i++){ + if(scouts[i] != null && scouts[i].currentHP >0){ + if(scouts[i].getDistance(expensionGoldMine) > 3){ + scouts[i].moveTo(expensionGoldMine.centre.x, expensionGoldMine.centre.z); + scouts[i].currentCommand = solidObject.move; + scouts[i].secondaryCommand = solidObject.StandBy; + }else{ + scoutReachesExpension = true; + } + + } + } + + //retaliate if the scouts are underattack while guarding the mine expansion. + //however if there are too many hostile units to deal with, then retreat and tell the expansion AI to find another gold expension + if(scoutReachesExpension){ + int overallThreatLevel = threatLevelNearTarget(expensionGoldMine); + int threatLevel = overallThreatLevel&0xfff; + boolean playerHasStaticDefence = ((overallThreatLevel&0xf000000) >> 24) >0; + int noneCombatID = ((overallThreatLevel&0xfff000) >> 12); + boolean isUnderAttack = false; + float targetX = 0; + float targetZ = 0; + for(int i = 0; i < scouts.length; i++){ + if(scouts[i] != null && scouts[i].underAttackCountDown > 0){ + isUnderAttack = true; + targetX = scouts[i].attacker.centre.x; + targetZ = scouts[i].attacker.centre.z; + if(scouts[i].currentHP<=0) + scouts[i] = null; + break; + } + } + + //attack if a non combat unit show up and the treatLevel if not high + if(threatLevel <= numberOfActiveScout*6 && noneCombatID > 0 && !playerHasStaticDefence){ + for(int i = 0; i < scouts.length; i++){ + if(scouts[i] != null && scouts[i].currentHP >0){ + scouts[i].attackMoveTo(mainThread.ec.theMapAwarenessAI.mapAsset[noneCombatID].centre.x,mainThread.ec.theMapAwarenessAI.mapAsset[noneCombatID].centre.z); + scouts[i].currentCommand = solidObject.attackMove; + scouts[i].secondaryCommand = solidObject.attackMove; + } + } + + } + + if(isUnderAttack){ + if(threatLevel <= numberOfActiveScout*6 && !playerHasStaticDefence){ + //retaliate if threatLevel is not high + for(int i = 0; i < scouts.length; i++){ + if(scouts[i] != null && scouts[i].currentHP >0){ + scouts[i].attackMoveTo(targetX, targetZ); + scouts[i].currentCommand = solidObject.attackMove; + scouts[i].secondaryCommand = solidObject.attackMove; + } + } + }else{ + //find a new potential expansion location when threatLevel is very high (except for natural expansion which is too valuable to give up) + if(expensionGoldMine != goldMines[5]) { + for(int i = 0; i<5; i++){ + if(!hasRefineryNearTheGoldmine(goldMines[expensionPiorityList[i]]) && !hasConstructionYardNearGoldMine(goldMines[expensionPiorityList[i]]) + && goldMines[expensionPiorityList[i]].goldDeposite > 17500 && goldMines[expensionPiorityList[i]] != expensionGoldMine){ + int t = expensionPiorityList[targetExpension]; + expensionPiorityList[targetExpension] = expensionPiorityList[i]; + expensionPiorityList[i] = t; + break; + } + } + expensionGoldMine = goldMines[expensionPiorityList[targetExpension]]; + } + } + } + } + + + }else{ + if(myMCV != null){ + + int threatLevel = threatLevelNearTarget(expensionGoldMine); + + if(threatLevel > 0 || hasRefineryNearTheGoldmine(expensionGoldMine) || hasConstructionYardNearGoldMine(expensionGoldMine)){ + + if((threatLevel&0xfff) <= numberOfActiveScout*5 && !hasRefineryNearTheGoldmine(expensionGoldMine) && !hasConstructionYardNearGoldMine(expensionGoldMine)){ + //attack if threatLevel is low + for(int i = 0; i < scouts.length; i++){ + if(scouts[i] != null && scouts[i].currentHP >0){ + scouts[i].attackMoveTo(expensionGoldMine.centre.x, expensionGoldMine.centre.z); + scouts[i].currentCommand = solidObject.attackMove; + scouts[i].secondaryCommand = solidObject.attackMove; + } + } + }else{ + //find a new potential expansion location when threatLevel is high (except for natural expansion which is too valuable to give up) + if(expensionGoldMine != goldMines[5]) { + for(int i = 0; i<5; i++){ + if(!hasRefineryNearTheGoldmine(goldMines[expensionPiorityList[i]]) && !hasConstructionYardNearGoldMine(goldMines[expensionPiorityList[i]]) + && goldMines[expensionPiorityList[i]].goldDeposite > 17500 && goldMines[expensionPiorityList[i]] != expensionGoldMine){ + int t = expensionPiorityList[targetExpension]; + expensionPiorityList[targetExpension] = expensionPiorityList[i]; + expensionPiorityList[i] = t; + break; + } + } + expensionGoldMine = goldMines[expensionPiorityList[targetExpension]]; + } + + + for(int i = 0; i < scouts.length; i++){ + if(scouts[i] != null && scouts[i].currentHP >0){ + if(scouts[i].getDistance(expensionGoldMine) > 3){ + scouts[i].moveTo(expensionGoldMine.centre.x, expensionGoldMine.centre.z); + scouts[i].currentCommand = solidObject.move; + scouts[i].secondaryCommand = solidObject.StandBy; + } + } + } + + } + }else{ + if(myMCV.underAttackCountDown > 0 && myMCV.attacker != null){ + for(int i = 0; i < scouts.length; i++){ + if(scouts[i] != null && scouts[i].currentHP >0){ + scouts[i].attackMoveTo(myMCV.attacker.centre.x, myMCV.attacker.centre.z); + scouts[i].currentCommand = solidObject.attackMove; + scouts[i].secondaryCommand = solidObject.attackMove; + } + } + }else{ + temp.set(expensionGoldMine.centre); + temp.subtract(myMCV.centre); + temp.unit(); + temp.scale(1.5f); + + for(int i = 1; i < scouts.length; i++){ + if(scouts[i] != null && scouts[i].currentHP >0){ + scouts[i].attackMoveTo(myMCV.centre.x + temp.x, myMCV.centre.z + temp.z); + scouts[i].currentCommand = solidObject.attackMove; + scouts[i].secondaryCommand = solidObject.attackMove; + } + } + } + + } + + } + } + } + + + //check if the scout units can fend off hostile aggression near a goldmine expension + public int threatLevelNearTarget(solidObject o){ + //the 0xfff bits store the treatLevel of hostile Unit + //the 0xfff000 bits store the id number of a nearby harvester/construction vehicle + //the 0xf000000 bit tells if the player has static defense setup near the target area + + solidObject[] playerUnitInMinimap = mainThread.ec.theMapAwarenessAI.playerUnitInMinimap; + solidObject[] playerStaticDefenceInMinimap = mainThread.ec.theMapAwarenessAI.playerStaticDefenceInMinimap; + boolean playerNoneCombatUnitDetected = false; + int threatLevel = 0; + for(int i = 0; i < playerUnitInMinimap.length; i++){ + if(playerUnitInMinimap[i] != null && playerUnitInMinimap[i].getDistance(o) < 3){ + if(playerUnitInMinimap[i].type == 0) + threatLevel+=3; + else if(playerUnitInMinimap[i].type == 1) + threatLevel+=2; + else if(playerUnitInMinimap[i].type == 6) + threatLevel+=5; + else if(playerUnitInMinimap[i].type == 7) + threatLevel+=20; + else if((playerUnitInMinimap[i].type == 2 || playerUnitInMinimap[i].type == 3) && !playerNoneCombatUnitDetected){ + playerNoneCombatUnitDetected = true; + threatLevel+=(playerUnitInMinimap[i].ID << 12); + } + } + } + + + + + for(int i = 0; i < playerStaticDefenceInMinimap.length; i++){ + if(playerStaticDefenceInMinimap[i] != null && playerStaticDefenceInMinimap[i].getDistance(expensionGoldMine) < 3){ + threatLevel += (1 << 24); //increase the threat level dramatically if player already has a base near the expension + break; + } + } + + return threatLevel; + } + + + //add a stealth tank to scouts + public void addStealthTank(stealthTank o){ + for(int i = 0; i < scouts.length; i++){ + if(scouts[i] == null || scouts[i].currentHP <=0){ + scouts[i] = o; + break; + } + } + } + + //3 stealth tanks will make a perfect scout team for the base expansion exploration + public boolean needStealthTank(){ + for(int i = 0; i < scouts.length; i++){ + if((scouts[i] == null || scouts[i].currentHP <=0) && frameAI > 800){ + return true; + } + } + return false; + } + + public boolean hasRefineryNearTheGoldmine(goldMine g){ + for(int j = 0; j < mainThread.theAssetManager.refineries.length; j++){ + if(mainThread.theAssetManager.refineries[j] != null){ + if(mainThread.theAssetManager.refineries[j].getDistance(g) < 2){ + return true; + } + } + } + return false; + } + + public boolean hasConstructionYardNearGoldMine(goldMine g){ + for(int j = 0; j < mainThread.theAssetManager.constructionYards.length; j++){ + if(mainThread.theAssetManager.constructionYards[j] != null){ + if(mainThread.theAssetManager.constructionYards[j].getDistance(g) < 3){ + return true; + } + } + } + return false; + } + +} diff --git a/enemyAI/buildingManagerAI.java b/enemyAI/buildingManagerAI.java new file mode 100644 index 0000000..2931dfd --- /dev/null +++ b/enemyAI/buildingManagerAI.java @@ -0,0 +1,536 @@ +//1. process building enquires from enemy commander +//2. manage building placement +//3 units production +//4. perform research + +package enemyAI; + +import core.baseInfo; +import core.gameData; +import core.mainThread; +import core.vector; +import entity.*; + +public class buildingManagerAI { + + public baseInfo theBaseInfo; + public int[] buildingPlacementCheckTiles, buildingPlacementCheckTiles_2x2, buildingPlacementCheckTiles_3x3; + public int placementTile; + public boolean powerPlantUnderConstruction; + public int frameIndex; + + + public buildingManagerAI (baseInfo theBaseInfo){ + this.theBaseInfo = theBaseInfo; + + buildingPlacementCheckTiles = solidObject.generateTileCheckList(13); + buildingPlacementCheckTiles_2x2 = new int[buildingPlacementCheckTiles.length]; + buildingPlacementCheckTiles_3x3 = new int[buildingPlacementCheckTiles.length]; + + for(int i = 0; i < buildingPlacementCheckTiles.length ; i++){ + buildingPlacementCheckTiles_2x2[i] = buildingPlacementCheckTiles[i]; + buildingPlacementCheckTiles_3x3[i] = buildingPlacementCheckTiles[i]; + + } + + + for(int i = 0; i < 400; i++){ + int temp = (gameData.getRandom() * 70) >> 10; + int temp1 = (gameData.getRandom() * 70) >> 10; + + int list = buildingPlacementCheckTiles_2x2[temp]; + buildingPlacementCheckTiles_2x2[temp] = buildingPlacementCheckTiles_2x2[temp1]; + buildingPlacementCheckTiles_2x2[temp1] = list; + } + + for(int i = 0; i < 400; i++){ + int temp = (gameData.getRandom() * 50 + 40*1024) >> 10; + int temp1 = (gameData.getRandom() * 50 + 40*1024) >> 10; + + int list = buildingPlacementCheckTiles_3x3[temp]; + buildingPlacementCheckTiles_3x3[temp] = buildingPlacementCheckTiles_3x3[temp1]; + buildingPlacementCheckTiles_3x3[temp1] = list; + } + + frameIndex = 0; + + } + + public void addBuildingToQueue(int buildingType){ + //if the additional building will result in a lower power, then build power plant first + if(buildingType != 101){ + if(theBaseInfo.currentPowerLevel <= constructionYard.getPowerConsumption(buildingType) + theBaseInfo.currentPowerConsumption && !powerPlantUnderConstruction){ + addBuildingToQueue(101); + return; + } + } + + //check if the building is already in the queue + boolean alreadyInQueue = false; + constructionYard[] constructionYards = mainThread.theAssetManager.constructionYards; + + //can only build one none defense structure at a time + //but can build more than defense structure at a time if there are more construction yards + + + for(int i = 0; i < constructionYards.length; i ++){ + if(constructionYards[i] != null && constructionYards[i].teamNo != 0){ + if(constructionYards[i].currentBuildingType == buildingType){ + if(buildingType < 150){ + alreadyInQueue = true; + break; + } + } + } + } + + + //if not in the queue then + if(!alreadyInQueue){ + for(int i = 0; i < constructionYards.length; i ++){ + if(constructionYards[i] != null && constructionYards[i].teamNo != 0 && constructionYards[i].isIdle()){ + constructionYards[i].build(buildingType); + break; + } + } + } + + } + + public void processAI(){ + frameIndex++; + + powerPlantUnderConstruction = buildingUnderProduction(101); + + + //build power plant, if the base is in lower power status or we have more money to spend on make extra one + if(theBaseInfo.canBuildRefinery == false || theBaseInfo.lowPower || (theBaseInfo.currentPowerConsumption >= (theBaseInfo.currentPowerLevel - 500) && theBaseInfo.currentCredit > 500 && theBaseInfo.numberOfPowerPlant >=2 && frameIndex > 300)){ + addBuildingToQueue(101); + } + + //build a refinery center if there isn't any + if(theBaseInfo.numberOfRefinery == 0 && theBaseInfo.canBuildRefinery){ + addBuildingToQueue(102); + } + + + + //build an additional refinery if there are more production building + //don't build more than 2 refinery around a goldmine + if(getNumberOfFunctionalRefinery() < theBaseInfo.numberOfConstructionYard*2 && theBaseInfo.numberOfFactory > 0 && theBaseInfo.canBuildRefinery && getNumberOfRefineriesNearPreferedGoldMine() < 2){ + addBuildingToQueue(102); + } + + //build a factory if there isnt any + if(theBaseInfo.numberOfFactory == 0 && theBaseInfo.canBuildFactory){ + addBuildingToQueue(105); + + } + + //build an addtional factory if we have enough harvester to sustain the production + if(mainThread.ec.theEconomyManagerAI.numberOfharvesters/2 > theBaseInfo.numberOfFactory && theBaseInfo.canBuildFactory && theBaseInfo.numberOfFactory < 2 && theBaseInfo.currentCredit > 1300){ + addBuildingToQueue(105); + } + + //build a communication center if there isnt any + if(theBaseInfo.numberOfCommunicationCenter == 0 && theBaseInfo.canBuildCommunicationCenter){ + addBuildingToQueue(106); + } + + //build a tech center if there isnt any + if(theBaseInfo.numberOfTechCenter == 0 && theBaseInfo.canBuildTechCenter){ + addBuildingToQueue(107); + } + + //build more factory if we have plenty of money in the bank + if(theBaseInfo.currentCredit > 2200 && theBaseInfo.canBuildFactory && theBaseInfo.numberOfFactory <= mainThread.ec.theEconomyManagerAI.numberOfharvesters/2){ + addBuildingToQueue(105); + } + + + //process structure building event + constructionYard[] constructionYards = mainThread.theAssetManager.constructionYards; + for(int i = 0; i < constructionYards.length; i++){ + if(constructionYards[i] != null && constructionYards[i].teamNo != 0){ + //deploy power plant + if(constructionYards[i].powerPlantProgress == 240){ + if(hasRoomForPlacement(101, -1)){ + int y = 127 - placementTile/128; + int x = placementTile%128 + 1; + powerPlant o = new powerPlant(x*0.25f, -1f, y*0.25f, 1); + mainThread.theAssetManager.addPowerPlant(o); + constructionYards[i].finishDeployment(); + } + } + + //deploy refinery + if(constructionYards[i].refineryProgress == 240){ + + + if(hasRoomForPlacement(102, mainThread.ec.theEconomyManagerAI.preferedGoldMineLocation)){ + int y = 127 - placementTile/128; + int x = placementTile%128 + 1; + refinery o = new refinery(x*0.25f + 0.125f, -1.43f, y*0.25f, 1); + mainThread.theAssetManager.addRefinery(o); + + harvester h = new harvester(new vector(x*0.25f + 0.125f,-0.3f, y*0.25f - 0.375f), 180, 1); + mainThread.theAssetManager.addHarvester(h); + h.goToTheNearestGoldMine(); + constructionYards[i].finishDeployment(); + } + } + + //deploy factory + if(constructionYards[i].factoryProgress == 240){ + + int factoryDeployLocation = findFactoryDeployLocation(); + if(hasRoomForPlacement(105, factoryDeployLocation)){ + int y = 127 - placementTile/128; + int x = placementTile%128 + 1; + factory o = new factory(x*0.25f + 0.125f, -1.13f, y*0.25f, 1); + mainThread.theAssetManager.addFactory(o); + + constructionYards[i].finishDeployment(); + + } + } + + //deploy communication center + if(constructionYards[i].communicationCenterProgress == 240){ + if(hasRoomForPlacement(106, communicationCenter.intendedDeployLocation)){ + int y = 127 - placementTile/128; + int x = placementTile%128 + 1; + communicationCenter o = new communicationCenter(x*0.25f, -1f, y*0.25f, 1); + mainThread.theAssetManager.addCommunicationCenter(o); + + constructionYards[i].finishDeployment(); + communicationCenter.intendedDeployLocation = -1; + } + } + + //deploy tech center + if(constructionYards[i].techCenterProgress == 240){ + if(hasRoomForPlacement(107, techCenter.intendedDeployLocation)){ + int y = 127 - placementTile/128; + int x = placementTile%128 + 1; + techCenter o = new techCenter(x*0.25f, -1f, y*0.25f, 1); + mainThread.theAssetManager.addTechCenter(o); + + constructionYards[i].finishDeployment(); + techCenter.intendedDeployLocation = -1; + } + } + + } + } + + } + + public boolean hasRoomForPlacement(int buildingType, int centerTile){ + + //check placement for power plant + if(buildingType == 101){ + constructionYard[] constructionYards = mainThread.theAssetManager.constructionYards; + for(int i = 0; i < constructionYards.length; i++){ + if(constructionYards[i] == null) + continue; + + if(constructionYards[i].teamNo == 0) + continue; + + centerTile = (int)(constructionYards[i].centre.x*64)/16 + (127 - (int)(constructionYards[i].centre.z*64)/16)*128; + for(int j = 0; j < buildingPlacementCheckTiles.length; j++){ + if(buildingPlacementCheckTiles_2x2[j] != Integer.MAX_VALUE){ + + placementTile = centerTile + buildingPlacementCheckTiles_2x2[j]; + + if(!checkIfBlockIsFree(placementTile)){ continue;} + if(!checkIfBlockIsFree(placementTile+1)){ continue;} + if(!checkIfBlockIsFree(placementTile + 128)){ continue;} + if(!checkIfBlockIsFree(placementTile + 129)){ continue;} + if(!checkIfBlockIsFree(placementTile - 129)){ continue;} + if(!checkIfBlockIsFree(placementTile + 257)){ continue;} + if(!checkIfBlockIsFree(placementTile - 127)){ continue;} + if(!checkIfBlockIsFree(placementTile + 255)){ continue;} + if(!checkIfBlockIsFree(placementTile + 127)){ continue;} + + return true; + } + } + + } + } + + //check placement for refinery + if(buildingType == 102){ + + boolean foundSuitableTile = false; + int distance = 99999; + int idealPosition = 0; + + for(int j = 40; j < buildingPlacementCheckTiles.length; j++){ + if(buildingPlacementCheckTiles_3x3[j] != Integer.MAX_VALUE){ + placementTile = centerTile + buildingPlacementCheckTiles_3x3[j]; + + if(!checkIfBlockIsFree(placementTile)){ continue;} + if(!checkIfBlockIsFree(placementTile+1)){ continue;} + if(!checkIfBlockIsFree(placementTile+2)){ continue;} + if(!checkIfBlockIsFree(placementTile + 128)){ continue;} + if(!checkIfBlockIsFree(placementTile + 129)){ continue;} + if(!checkIfBlockIsFree(placementTile + 130)){ continue;} + if(!checkIfBlockIsFree(placementTile + 256)){ continue;} + if(!checkIfBlockIsFree(placementTile + 257)){ continue;} + if(!checkIfBlockIsFree(placementTile + 258)){ continue;} + + foundSuitableTile = true; + if(Math.abs(placementTile/128 - centerTile/128) + Math.abs(placementTile%128 - centerTile%128) < distance) { + idealPosition = placementTile; + distance = Math.abs(placementTile/128 - centerTile/128) + Math.abs(placementTile%128 - centerTile%128); + } + + if(placementTile/128 + 4< centerTile/128) + return true; + } + } + + if(foundSuitableTile) { + placementTile = idealPosition; + return true; + } + } + + //check placement for factory + if(buildingType == 105){ + for(int j = 40; j < buildingPlacementCheckTiles.length; j++){ + if(buildingPlacementCheckTiles_3x3[j] != Integer.MAX_VALUE){ + + placementTile = centerTile + buildingPlacementCheckTiles_3x3[j]; + + if(!checkIfBlockIsFree(placementTile - 128)){ continue;} + if(!checkIfBlockIsFree(placementTile - 127)){ continue;} + if(!checkIfBlockIsFree(placementTile - 126)){ continue;} + if(!checkIfBlockIsFree(placementTile)){ continue;} + if(!checkIfBlockIsFree(placementTile+1)){ continue;} + if(!checkIfBlockIsFree(placementTile+2)){ continue;} + if(!checkIfBlockIsFree(placementTile + 128)){ continue;} + if(!checkIfBlockIsFree(placementTile + 129)){ continue;} + if(!checkIfBlockIsFree(placementTile + 130)){ continue;} + if(!checkIfBlockIsFree(placementTile + 256)){ continue;} + if(!checkIfBlockIsFree(placementTile + 257)){ continue;} + if(!checkIfBlockIsFree(placementTile + 258)){ continue;} + + + return true; + } + } + } + + //check placement for communication center + if(buildingType == 106){ + if(centerTile == -1){ + constructionYard[] constructionYards = mainThread.theAssetManager.constructionYards; + for(int i = 0; i < constructionYards.length; i++){ + if(constructionYards[i] == null) + continue; + + if(constructionYards[i].teamNo == 0) + continue; + + centerTile = (int)(constructionYards[i].centre.x*64)/16 + (127 - (int)(constructionYards[i].centre.z*64)/16)*128; + for(int j = 0; j < buildingPlacementCheckTiles.length; j++){ + if(buildingPlacementCheckTiles_2x2[j] != Integer.MAX_VALUE){ + + placementTile = centerTile + buildingPlacementCheckTiles_2x2[j]; + + int x = placementTile%128; + int y = placementTile/128; + + boolean tooCloseToOtherCommunicationCenter = false; + for(int k = 0; k < mainThread.theAssetManager.communicationCenters.length; k++){ + if(mainThread.theAssetManager.communicationCenters[k] != null && mainThread.theAssetManager.communicationCenters[k].teamNo != 0){ + int x_ = mainThread.theAssetManager.communicationCenters[k].tileIndex[0]%128; + int y_ = mainThread.theAssetManager.communicationCenters[k].tileIndex[0]/128; + + if(Math.abs(x - x_) + Math.abs(y - y_) <= 14){ + tooCloseToOtherCommunicationCenter = true; + break; + } + + } + } + if(tooCloseToOtherCommunicationCenter){ + continue; + } + + if(!checkIfBlockIsFree(placementTile)){ continue;} + if(!checkIfBlockIsFree(placementTile+1)){ continue;} + if(!checkIfBlockIsFree(placementTile + 128)){ continue;} + if(!checkIfBlockIsFree(placementTile + 129)){ continue;} + if(!checkIfBlockIsFree(placementTile - 129)){ continue;} + if(!checkIfBlockIsFree(placementTile + 257)){ continue;} + if(!checkIfBlockIsFree(placementTile - 127)){ continue;} + if(!checkIfBlockIsFree(placementTile +255)){ continue;} + if(!checkIfBlockIsFree(placementTile + 127)){ continue;} + + + return true; + } + } + } + } + } + + //check placement for tech center + if(buildingType == 107){ + if(centerTile == -1){ + constructionYard[] constructionYards = mainThread.theAssetManager.constructionYards; + for(int i = 0; i < constructionYards.length; i++){ + if(constructionYards[i] == null) + continue; + + if(constructionYards[i].teamNo == 0) + continue; + + centerTile = (int)(constructionYards[i].centre.x*64)/16 + (127 - (int)(constructionYards[i].centre.z*64)/16)*128; + for(int j = 0; j < buildingPlacementCheckTiles.length; j++){ + if(buildingPlacementCheckTiles_2x2[j] != Integer.MAX_VALUE){ + + placementTile = centerTile + buildingPlacementCheckTiles_2x2[j]; + + if(!checkIfBlockIsFree(placementTile)){ continue;} + if(!checkIfBlockIsFree(placementTile+1)){ continue;} + if(!checkIfBlockIsFree(placementTile + 128)){ continue;} + if(!checkIfBlockIsFree(placementTile + 129)){ continue;} + if(!checkIfBlockIsFree(placementTile - 129)){ continue;} + if(!checkIfBlockIsFree(placementTile + 257)){ continue;} + if(!checkIfBlockIsFree(placementTile - 127)){ continue;} + if(!checkIfBlockIsFree(placementTile + 255)){ continue;} + if(!checkIfBlockIsFree(placementTile + 127)){ continue;} + + return true; + } + } + } + } + } + + return false; + } + + public boolean checkIfBlockIsFree(int index){ + int y = index/128; + int x = index%128; + + if(y > 0 && y < 127 && x > 0 && x < 127){ + solidObject[] tile = mainThread.gridMap.tiles[index]; + for(int j = 0; j < 5; j++){ + if(tile[j] != null){ + + return false; + } + } + + if(mainThread.ec.theEconomyManagerAI.preferedGoldMine != null){ + int location = mainThread.ec.theEconomyManagerAI.preferedGoldMine.tileIndex[1]; + + if( index == location - 128 || index == location - 129 || index == location - 130 || index == location - 2 || + index == location + 126 || index == location + 254 || index == location + 255 || index == location + 256 || + index == location + 257 || index == location + 129 || index == location + 1 || index == location-127){ + return false; + } + } + + constructionYard[] constructionYards = mainThread.theAssetManager.constructionYards; + for(int i = 0; i < constructionYards.length; i++){ + if(constructionYards[i] != null && constructionYards[i].teamNo != 0){ + float xPos = x * 0.25f + 0.125f; + float yPos = (127 - y)*0.25f + 0.125f; + + float distance = (float) Math.sqrt((constructionYards[i].centre.x - xPos)*(constructionYards[i].centre.x - xPos) + (constructionYards[i].centre.z - yPos)*(constructionYards[i].centre.z - yPos)); + if(distance <= 2.75){ + return true; + } + } + } + + return false; + + }else{ + return false; + } + } + + public boolean buildingUnderProduction(int buildingType){ + boolean alreadyInQueue = false; + constructionYard[] constructionYards = mainThread.theAssetManager.constructionYards; + for(int i = 0; i < constructionYards.length; i ++){ + if(constructionYards[i] != null && constructionYards[i].teamNo != 0){ + if(constructionYards[i].currentBuildingType == buildingType){ + alreadyInQueue = true; + break; + } + } + } + return alreadyInQueue; + } + + + + public int findFactoryDeployLocation(){ + constructionYard[] constructionYards = mainThread.theAssetManager.constructionYards; + factory[] factories = mainThread.theAssetManager.factories; + for(int i = 0; i < constructionYards.length; i++){ + if(constructionYards[i] == null || constructionYards[i].teamNo == 0) + continue; + + + + int numberOfFactories = 0; + for(int j= 0; j < factories.length; j++){ + if(factories[j] == null || factories[j].teamNo == 0) + continue; + + if(constructionYards[i].getDistance(factories[j]) < 3) + numberOfFactories++; + } + + if(numberOfFactories >= 2 && (Math.abs((constructionYards[i].centre.x /constructionYards[i].centre.z)) > 4 || Math.abs((constructionYards[i].centre.x /constructionYards[i].centre.z)) < 0.25)) + continue; + + if(numberOfFactories < 3){ + return (int)(constructionYards[i].centre.x*64)/16 + (127 - (int)(constructionYards[i].centre.z*64)/16)*128; + } + } + + return -1; + } + + public int getNumberOfRefineriesNearPreferedGoldMine(){ + int numberOfRefineriesNearPreferedGoldMine = 0; + refinery[] refineries = mainThread.theAssetManager.refineries; + for(int i = 0; i < refineries.length; i++){ + if(refineries[i] != null && refineries[i].teamNo != 0){ + if(mainThread.ec.theEconomyManagerAI.preferedGoldMine.getDistance(refineries[i]) < 2.5){ + numberOfRefineriesNearPreferedGoldMine++; + } + } + } + + return numberOfRefineriesNearPreferedGoldMine; + } + + public int getNumberOfFunctionalRefinery(){ + int numberOfFunctionalRefinery = 0; + + refinery[] refineries = mainThread.theAssetManager.refineries; + for(int i = 0; i < refineries.length; i++){ + if(refineries[i] != null && refineries[i].teamNo != 0 && refineries[i].nearestGoldMine != null && refineries[i].nearestGoldMine.goldDeposite > 10000){ + numberOfFunctionalRefinery++; + } + } + return numberOfFunctionalRefinery; + + } + + +} diff --git a/enemyAI/combatManagerAI.java b/enemyAI/combatManagerAI.java new file mode 100644 index 0000000..7a5b171 --- /dev/null +++ b/enemyAI/combatManagerAI.java @@ -0,0 +1,589 @@ +package enemyAI; + +import core.baseInfo; +import core.mainThread; +import core.vector; +import entity.goldMine; +import entity.solidObject; +import entity.techCenter; + +//this agent makes all the high level combat decisions +public class combatManagerAI { + public baseInfo theBaseInfo; + + public int frameAI; + + public int currentState; + public final int booming = 0; + public final int aggressing = 1; + public final int defending = 2; + + + public goldMine[] goldMines; + + float distanceToTarget; + + public vector gatherPoint, attackDirection, attackPosition; + + + public solidObject unNeutralizedEntity; + + public solidObject[] team; + + public int numberOfUnitInCombatRadius; + public int numberOfUnitOutsideCombatRadius; + public float unitInCombactRadiusPercentage; + + public solidObject[] unitInCombatRadius; + public solidObject[] unitOutsideCombatRadius; + public solidObject[] troopsControlledByCombatAI; + public solidObject[] playerUnitInMinimap; + public vector playerForceCenter; + public vector adjustedAttackDirection; + + public int withdrawUnitOutsideCombatRadiusCooldown; + public float maxPlayerForceStrengthRoundAttacker; + + public float combatCenterX, combatCenterZ; + public float myRallyPointX, myRallyPointZ; + public boolean rallyPointChanged; + boolean shouldDefenceAggressively; + + + public float offScreenPlayerForceStrength; + + + public combatManagerAI(baseInfo theBaseInfo){ + this.theBaseInfo = theBaseInfo; + + + goldMines = mainThread.theAssetManager.goldMines; + + gatherPoint = new vector(-1,-1,-1); + attackDirection = new vector(0,0,0); + attackPosition = new vector(0,0,0); + playerForceCenter = new vector(0,0,0); + adjustedAttackDirection = new vector(0,0,0); + + } + + //check if player has expansions + //if player has expansion(s) then find the one that is least defended + //compare player force with its own force + //if AI thinks its has a comparable or greater force than the player, attack player's expansion and switch to aggressing mode + //if AI is under significant threat, switch to defending mode + + public void processAI(){ + frameAI++; + + //assume player force gets stronger as time goes by + if(offScreenPlayerForceStrength < 0) + offScreenPlayerForceStrength = 0; + if(frameAI > 150) + offScreenPlayerForceStrength+=0.075f; + + + //checkIfAIHasBiggerForce(1); + + if(withdrawUnitOutsideCombatRadiusCooldown > 0){ + withdrawUnitOutsideCombatRadiusCooldown --; + }else{ + maxPlayerForceStrengthRoundAttacker = 0; + } + + team = mainThread.ec.theUnitProductionAI.troopsControlledByCombatAI; + numberOfUnitInCombatRadius = mainThread.ec.theUnitProductionAI.numberOfUnitInCombatRadius; + numberOfUnitOutsideCombatRadius = mainThread.ec.theUnitProductionAI.numberOfUnitOutsideCombatRadius; + unitInCombatRadius = mainThread.ec.theUnitProductionAI.unitInCombatRadius; + unitOutsideCombatRadius = mainThread.ec.theUnitProductionAI.unitOutsideCombatRadius; + troopsControlledByCombatAI = mainThread.ec.theUnitProductionAI.troopsControlledByCombatAI; + playerUnitInMinimap = mainThread.ec.theMapAwarenessAI.playerUnitInMinimap; + shouldDefenceAggressively = checkIfAIHasBiggerForce(1.6f); + + + + combatCenterX = mainThread.ec.theUnitProductionAI.combatAICenterX; + combatCenterZ = mainThread.ec.theUnitProductionAI.combatAICenterZ; + + if(Float.isNaN(combatCenterX) || Float.isNaN(combatCenterZ)) { + // combatCenterX = 0; + // combatCenterZ= 0; + } + + + boolean frontalTroopIverwhelmed = false; + boolean shouldAttack = false; + boolean playerHasBecomeStrongerThanAIDuringMarching = false; + + + rallyPointChanged = false; + if(myRallyPointX != mainThread.ec.theUnitProductionAI.rallyPoint.x){ + myRallyPointX = mainThread.ec.theUnitProductionAI.rallyPoint.x; + myRallyPointZ = mainThread.ec.theUnitProductionAI.rallyPoint.z; + rallyPointChanged = true; + } + + + if(currentState == booming){ + + //enemy AI compares its own force with player's force, then make a decision whether it should attack or not + //only start comparing after 6 minutes mark, or player is rushing with light tank delay attack mark to around 10 minutes mark + int attackTime = 360; + if(mainThread.ec.theMapAwarenessAI.playerIsRushingLightTank) + attackTime = 540; + else + attackTime = 360; + + int targetPlayerExpension = mainThread.ec.theMapAwarenessAI.targetPlayerExpension; + + if(frameAI > attackTime) { + if(targetPlayerExpension == 2 || targetPlayerExpension == 4 || targetPlayerExpension == 6 || targetPlayerExpension == 7) + shouldAttack = checkIfAIHasBiggerForce(1.2f); + else + shouldAttack = checkIfAIHasBiggerForce(0.9f); + } + + + if(shouldAttack){ + if(targetPlayerExpension != -1){ + currentState = aggressing; + attackDirection.set(goldMines[targetPlayerExpension].centre.x - combatCenterX, 0, goldMines[targetPlayerExpension].centre.z - combatCenterZ); + attackDirection.unit(); + attackPosition.set(goldMines[targetPlayerExpension].centre); + attackPosition.add(attackDirection); + return; + }else{ + //if no enemy structure found around gold mines, set attack position to a revealed enemy building or unit + solidObject[] playerStructures = mainThread.ec.theMapAwarenessAI.playerStructures; + solidObject[] playerUnitInMinimap = mainThread.ec.theMapAwarenessAI.playerUnitInMinimap; + attackDirection.set(0,0,0); + for(int i = 0; i < playerStructures.length; i++){ + if(playerStructures[i] != null && playerStructures[i].currentHP > 0){ + currentState = aggressing; + attackDirection.set(playerStructures[i].centre.x - combatCenterX, 0, playerStructures[i].centre.z - combatCenterZ); + attackDirection.unit(); + attackPosition.set(playerStructures[i].centre); + attackPosition.add(attackDirection); + return; + } + } + + if(attackDirection.x == 0 && attackDirection.z ==0){ + for(int i = 0; i < playerUnitInMinimap.length; i++){ + if(playerUnitInMinimap[i] != null && playerUnitInMinimap[i].currentHP > 0){ + currentState = aggressing; + attackDirection.set(playerUnitInMinimap[i].centre.x - combatCenterX, 0, playerUnitInMinimap[i].centre.z - combatCenterZ); + attackDirection.unit(); + attackPosition.set(playerUnitInMinimap[i].centre); + attackPosition.add(attackDirection); + return; + } + } + } + + + //if AI couldn't find a player base nor player's unit then set the attack position to the player spawning point + currentState = aggressing; + attackDirection.set(goldMines[0].centre.x - combatCenterX, 0, goldMines[0].centre.z - combatCenterZ); + attackDirection.unit(); + attackPosition.set(goldMines[0].centre); + attackPosition.add(attackDirection); + + } + }else { + + //check if there are any player units/structures near the combat center + solidObject[] playerUnitInMinimap = mainThread.ec.theMapAwarenessAI.playerUnitInMinimap; + solidObject[] playerStructures = mainThread.ec.theMapAwarenessAI.playerStructures; + + for(int i = 0; i < playerUnitInMinimap.length; i++) { + if(playerUnitInMinimap[i] != null && playerUnitInMinimap[i].currentHP > 0) { + double d = Math.sqrt((combatCenterX - playerUnitInMinimap[i].centre.x)*(combatCenterX - playerUnitInMinimap[i].centre.x) + (combatCenterZ - playerUnitInMinimap[i].centre.z)*(combatCenterZ - playerUnitInMinimap[i].centre.z)); + if(d < 5){ + currentState = aggressing; + attackDirection.set(playerUnitInMinimap[i].centre.x - combatCenterX, 0, playerUnitInMinimap[i].centre.z - combatCenterZ); + attackDirection.unit(); + attackPosition.set(playerUnitInMinimap[i].centre); + + if(shouldDefenceAggressively) + attackPosition.add(attackDirection); + + return; + } + } + } + } + + if(currentState != aggressing) { + if(rallyPointChanged || Math.abs(myRallyPointX - combatCenterX) > 1 || Math.abs(myRallyPointZ - combatCenterZ) > 1){ + for(int i =0 ; i < troopsControlledByCombatAI.length; i++){ + if(troopsControlledByCombatAI[i] != null && troopsControlledByCombatAI[i].currentHP > 0){ + troopsControlledByCombatAI[i].attackMoveTo(myRallyPointX, myRallyPointZ); + troopsControlledByCombatAI[i].currentCommand = solidObject.attackMove; + troopsControlledByCombatAI[i].secondaryCommand = solidObject.attackMove; + } + } + } + } + }else if(currentState == aggressing){ + + + attackDirection.set(attackPosition.x - combatCenterX, 0, attackPosition.z - combatCenterZ); + distanceToTarget = attackDirection.getLength(); + attackDirection.unit(); + + //check if the target position has been neutralized + solidObject[] playerUnitInMinimap = mainThread.ec.theMapAwarenessAI.playerUnitInMinimap; + solidObject[] playerStructures = mainThread.ec.theMapAwarenessAI.playerStructures; + unNeutralizedEntity = null; + + //look for revealed player building structures + for(int i = 0; i < playerStructures.length; i++){ + if(playerStructures[i] != null){ + if((playerStructures[i].centre.x - attackPosition.x)*(playerStructures[i].centre.x - attackPosition.x) + (playerStructures[i].centre.z - attackPosition.z)*(playerStructures[i].centre.z - attackPosition.z) < 16){ + unNeutralizedEntity = playerStructures[i]; + attackPosition.set(playerStructures[i].centre); + break; + } + } + } + + //if there is no player structure found, then look for player units + boolean needResetAttackPosition = false; + if(unNeutralizedEntity == null){ + for(int i = 0; i < playerUnitInMinimap.length; i++){ + if(playerUnitInMinimap[i] != null){ + unNeutralizedEntity = playerUnitInMinimap[i]; + needResetAttackPosition = true; + if((playerUnitInMinimap[i].centre.x - attackPosition.x)*(playerUnitInMinimap[i].centre.x - attackPosition.x) + (playerUnitInMinimap[i].centre.z - attackPosition.z)*(playerUnitInMinimap[i].centre.z - attackPosition.z) < 16){ + needResetAttackPosition = false; + break; + } + } + } + } + if(needResetAttackPosition) { + attackPosition.set(unNeutralizedEntity.centre); + } + + + //if front portion of the troops are under attack, set the attack position to the attacker + for(int i = 0; i < numberOfUnitInCombatRadius; i++){ + if(unitInCombatRadius[i].underAttackCountDown > 0){ + attackPosition.set(unitInCombatRadius[i].attacker.centre); + unNeutralizedEntity = unitInCombatRadius[i].attacker; + break; + } + } + + //check if the front portion of the troops are overwhelmed by player force + float playerForceStrengthNearCombatCenter = checkPlayerForceStrengthAroundOnePoint(playerUnitInMinimap, combatCenterX + attackDirection.x, combatCenterZ + attackDirection.z, 4); + if((playerForceStrengthNearCombatCenter+1)/(getAIForceStrength(unitInCombatRadius)+1) > 2f){ + frontalTroopIverwhelmed = true; + } + + + + //check if the player force has become stronger than the AI during the marching towards attack position + //System.out.println("distanceToTarget: " + distanceToTarget); + if(checkIfAIHasBiggerForce(1) == false && distanceToTarget > 5){ + playerHasBecomeStrongerThanAIDuringMarching = true; + } + + + + //check if the troops has encountered a concentration of enemy static defense + + + + //send units to attack-move to target position + if(!playerHasBecomeStrongerThanAIDuringMarching && !frontalTroopIverwhelmed && (unNeutralizedEntity != null || distanceToTarget > 2)){ + + //if the tail portion of the troops are under attack, send them back to base instead of throwing them into player's trap + float AIForceStrengthOutsideCombatRadius = getAIForceStrength(unitOutsideCombatRadius); + maxPlayerForceStrengthRoundAttacker = 0; + for(int i = 0; i < numberOfUnitOutsideCombatRadius; i++){ + if(unitOutsideCombatRadius[i].underAttackCountDown > 0 && unitOutsideCombatRadius[i].attacker != null){ + //check the number of hostile units around the attacker + playerForceStrengthNearCombatCenter = checkPlayerForceStrengthAroundOnePoint(playerUnitInMinimap, unitOutsideCombatRadius[i].attacker.centre.x, unitOutsideCombatRadius[i].attacker.centre.z, 4); + if(playerForceStrengthNearCombatCenter > maxPlayerForceStrengthRoundAttacker) + maxPlayerForceStrengthRoundAttacker = playerForceStrengthNearCombatCenter; + + } + + //check if there are too many hostile units + if(maxPlayerForceStrengthRoundAttacker > AIForceStrengthOutsideCombatRadius){ + if(withdrawUnitOutsideCombatRadiusCooldown == 0) + withdrawUnitOutsideCombatRadiusCooldown = 30; + break; + } + } + + if(withdrawUnitOutsideCombatRadiusCooldown > 0){ + team = unitInCombatRadius; //exclude the tail portion of the troops from the attack force + for(int i = 0; i < troopsControlledByCombatAI.length; i++){ + //send the tail portion of the troops to rally point + if(troopsControlledByCombatAI[i] != null && troopsControlledByCombatAI[i].currentHP > 0){ + troopsControlledByCombatAI[i].attackMoveTo(mainThread.ec.theUnitProductionAI.rallyPoint.x, mainThread.ec.theUnitProductionAI.rallyPoint.z); + troopsControlledByCombatAI[i].currentCommand = solidObject.attackMove; + troopsControlledByCombatAI[i].secondaryCommand = solidObject.attackMove; + } + } + } + + + if(unNeutralizedEntity != null){ + attackDirection.set(unNeutralizedEntity.centre.x - combatCenterX, 0, unNeutralizedEntity.centre.z - combatCenterZ); + distanceToTarget = attackDirection.getLength(); + attackDirection.unit(); + } + everyoneAttackTargetPosition(); + + }else{ + //if target position has been neutralized, change status to booming + currentState = booming; + + + float gatherPointX, gatherPointZ; + + //if the change of state is caused by heavy causality of the AI player then move move every unit back to rally point + if(frontalTroopIverwhelmed || playerHasBecomeStrongerThanAIDuringMarching){ + gatherPointX = mainThread.ec.theUnitProductionAI.rallyPoint.x; + gatherPointZ = mainThread.ec.theUnitProductionAI.rallyPoint.z; + }else { + //if the AI really couldn't find any targets then gather every units at the current combat center + gatherPointX = combatCenterX; + gatherPointZ = combatCenterZ; + + } + + for(int i = 0; i < numberOfUnitOutsideCombatRadius; i++){ + //send the tail portion of the troops to rally point + unitOutsideCombatRadius[i].attackMoveTo(gatherPointX, gatherPointZ); + unitOutsideCombatRadius[i].currentCommand = solidObject.attackMove; + unitOutsideCombatRadius[i].secondaryCommand = solidObject.attackMove; + } + + for(int i = 0; i < numberOfUnitInCombatRadius; i++){ + //send the tail portion of the troops to rally point + if(unitInCombatRadius[i].attackStatus != solidObject.isAttacking){ + unitInCombatRadius[i].attackMoveTo(gatherPointX, gatherPointZ); + unitInCombatRadius[i].currentCommand = solidObject.attackMove; + unitInCombatRadius[i].secondaryCommand = solidObject.attackMove; + } + } + } + } + } + + + //attack a target location with all the forces + public void everyoneAttackTargetPosition(){ + //Find a gather location for an attack. The attacking units will first try to gather around a location that in between the target location and the attack force's center point. + //When the majority attacking units arrive around the gather point, the attack will proceed towards the target location. + //The purpose of doing this is to keep the attack units together when across long distance, + + float teamRadius = (float)Math.sqrt(mainThread.ec.theUnitProductionAI.numberOfCombatUnit)/2.5f; + + if(distanceToTarget < 3 + teamRadius && unNeutralizedEntity != null){ + //adjust the attack location for better engagement + playerForceCenter.set(0,0,0); + int numOfPlayerUnitsInMinimap = 0; + for(int i = 0; i < playerUnitInMinimap.length; i++){ + if(playerUnitInMinimap[i] != null && playerUnitInMinimap[i].currentHP > 0){ + float playerCenterX = playerUnitInMinimap[i].centre.x; + float playerCenterZ = playerUnitInMinimap[i].centre.z; + + if((playerCenterX - combatCenterX)*(playerCenterX - combatCenterX) + (playerCenterZ - combatCenterZ)*(playerCenterZ - combatCenterZ) < 9){ + playerForceCenter.x+=playerCenterX; + playerForceCenter.z+=playerCenterZ; + numOfPlayerUnitsInMinimap++; + } + } + } + + if(numOfPlayerUnitsInMinimap >0){ + playerForceCenter.x/=numOfPlayerUnitsInMinimap; + playerForceCenter.z/=numOfPlayerUnitsInMinimap; + + }else{ + playerForceCenter.x= attackPosition.x; + playerForceCenter.z= attackPosition.z; + } + + + + adjustedAttackDirection.set(playerForceCenter.x - combatCenterX, 0, playerForceCenter.z - combatCenterZ); + adjustedAttackDirection.unit(); + adjustedAttackDirection.scale(20); + + for(int i = 0; i < mainThread.ec.theUnitProductionAI.numberOfCombatUnit; i++){ + if(team[i] != null && team[i].currentHP > 0){ + if(!((team[i].secondaryDestinationX == attackPosition.x && team[i].secondaryDestinationY == attackPosition.z) + || (team[i].secondaryDestinationX == unNeutralizedEntity.centre.x && team[i].secondaryDestinationY == unNeutralizedEntity.centre.z))){ + + if(team[i].attackStatus != solidObject.isAttacking){ + + team[i].attackMoveTo(playerForceCenter.x + adjustedAttackDirection.x, playerForceCenter.z + adjustedAttackDirection.z); + team[i].currentCommand = solidObject.attackMove; + team[i].secondaryCommand = solidObject.attackMove; + + } + + team[i].secondaryDestinationX = attackPosition.x; + team[i].secondaryDestinationY = attackPosition.z; + } + } + } + + }else{ + for(int i = 0; i < 3; i++){ + gatherPoint.set(combatCenterX + attackDirection.x*(teamRadius+1*i), 0, combatCenterZ + attackDirection.z*(teamRadius+ 1*i)); + //if the gather point is inside a water body them move the gather point forward + int tileIndex = (int)(gatherPoint.x*64)/16 + (127 - ((int)(gatherPoint.z*64))/16)*128; + if(tileIndex >= mainThread.gridMap.tiles.length || tileIndex < 0) + break; + if(mainThread.gridMap.tiles[tileIndex][0] != null && mainThread.gridMap.tiles[tileIndex][0].type == 4) + continue; + else + break; + } + + + + for(int i = 0; i < mainThread.ec.theUnitProductionAI.numberOfCombatUnit; i++){ + if(team[i] != null && team[i].currentHP > 0){ + //stop chasing player unit if it has got out of sight + if(team[i].targetObject != null && team[i].targetObject.currentHP >0) { + int targetPositionIndex = (int)(team[i].targetObject.centre.x*64)/16 + (127 - (int)(team[i].targetObject.centre.z*64)/16)*128; + + if(team[i].attackStatus != solidObject.isAttacking && team[i].underAttackCountDown == 0 && (!mainThread.ec.visionMap[targetPositionIndex] || team[i].targetObject.isCloaked)) + team[i].targetObject = null; + } + + //marching forward + if((team[i].targetObject == null || team[i].targetObject.currentHP <=0) && !(team[i].currentMovementStatus == solidObject.hugRight || team[i].currentMovementStatus == solidObject.hugLeft)){ + + double d = Math.sqrt((team[i].centre.x - combatCenterX)*(team[i].centre.x - combatCenterX) + (team[i].centre.z - combatCenterZ)*(team[i].centre.z - combatCenterZ))*3; + + if(d > teamRadius){ + team[i].attackMoveTo(gatherPoint.x, gatherPoint.z); + + }else{ + + team[i].attackMoveTo(team[i].centre.x + attackDirection.x*teamRadius, team[i].centre.z + attackDirection.z*teamRadius); + + } + + team[i].currentCommand = solidObject.attackMove; + team[i].secondaryCommand = solidObject.attackMove; + + } + } + } + } + + //make sure idle units are send to attack unNeutralized target + if(unNeutralizedEntity != null){ + for(int i = 0; i < mainThread.ec.theUnitProductionAI.numberOfCombatUnit; i++){ + if(team[i] != null && team[i].currentHP > 0){ + if(team[i].currentCommand == solidObject.StandBy || (team[i].targetObject == null && (team[i].secondaryDestinationX != unNeutralizedEntity.centre.x || team[i].secondaryDestinationY != unNeutralizedEntity.centre.z))){ + float d = (team[i].centre.x - attackPosition.x)*(team[i].centre.x - attackPosition.x) + (team[i].centre.z - attackPosition.z)*(team[i].centre.z - attackPosition.z); + if(d < 9){ + team[i].attackMoveTo(unNeutralizedEntity.centre.x, unNeutralizedEntity.centre.z); + team[i].currentCommand = solidObject.attackMove; + team[i].secondaryCommand = solidObject.attackMove; + + } + } + } + } + } + + } + + public float checkPlayerForceStrengthAroundOnePoint(solidObject[] listOfUnits, float x, float z, double distanceThreshold){ + float playerForceStrength = 0; + for(int j = 0; j < listOfUnits.length; j++){ + + if(listOfUnits[j] != null && listOfUnits[j].currentHP > 0){ + double d = (listOfUnits[j].centre.x - x)*(listOfUnits[j].centre.x - x) + + (listOfUnits[j].centre.z - z)*(listOfUnits[j].centre.z - z); + if(d < distanceThreshold){ + if(listOfUnits[j].type == 0 || listOfUnits[j].type == 1) + playerForceStrength+=1; + else if(listOfUnits[j].type == 6) + playerForceStrength+=1.5f; + else if(listOfUnits[j].type == 7) + playerForceStrength+=3; + } + } + } + return playerForceStrength; + } + + public float getAIForceStrength(solidObject[] listOfUnits){ + float AIForceStrength = 0; + for(int j = 0; j < listOfUnits.length; j++){ + if(listOfUnits[j] != null && listOfUnits[j].currentHP > 0){ + if(listOfUnits[j].type == 0 || listOfUnits[j].type == 1) + AIForceStrength+=1; + else if(listOfUnits[j].type == 6) + AIForceStrength+=1.5f; + else if(listOfUnits[j].type == 7) + AIForceStrength+=3; + } + } + return AIForceStrength; + } + + public boolean checkIfAIHasBiggerForce(float ratio){ + + int numberOfLightTanks_AI = mainThread.ec.theUnitProductionAI.numberOfLightTanksControlledByCombatAI; + int numberOfRocketTanks_AI = mainThread.ec.theUnitProductionAI.numberOfRocketTanksControlledByCombatAI; + int numberOfStealthTanks_AI = mainThread.ec.theUnitProductionAI.numberOfStealthTanksControlledByCombatAI; + int numberOfHeavyTanks_AI = mainThread.ec.theUnitProductionAI.numberOfHeavyTanksControlledByCombatAI; + + int numberOfLightTanks_player = mainThread.ec.theMapAwarenessAI.numberOfLightTanks_player; + int numberOfRocketTanks_player = mainThread.ec.theMapAwarenessAI.numberOfRocketTanks_player; + int numberOfStealthTanks_player = mainThread.ec.theMapAwarenessAI.numberOfStealthTanks_player; + int numberOfHeavyTanks_player = mainThread.ec.theMapAwarenessAI.numberOfHeavyTanks_player; + + float m3 = 1.5f; + + if(techCenter.stealthTankResearched_enemy == true && numberOfHeavyTanks_player < 4 && numberOfStealthTanks_AI > numberOfStealthTanks_player * 2) + m3+=0.5f; + + + if(techCenter.stealthTankResearched_enemy == true && mainThread.ec.theMapAwarenessAI.playerHasMostlyLightTanks){ + m3+=0.5f; + } + + float m1 = 1; + + + + if(mainThread.ec.theMapAwarenessAI.playerHasMostlyHeavyTanks){ + m1 = 1.2f; + + if(techCenter.lightTankResearched_enemy == true && numberOfStealthTanks_player < 5){ + m1=1.75f; + + } + } + + + double enemyAIForceStrength = m1*numberOfLightTanks_AI + 0.75f*numberOfRocketTanks_AI + m3*(numberOfStealthTanks_AI-mainThread.ec.theBaseExpentionAI.numberOfStealthTankScout) + 3* numberOfHeavyTanks_AI; + + double playerForceStrength = offScreenPlayerForceStrength + numberOfLightTanks_player + 0.75f*numberOfRocketTanks_player + 1.5*numberOfStealthTanks_player + 3* numberOfHeavyTanks_player; + + //System.out.println("offScreenPlayerForceStrength" + offScreenPlayerForceStrength + " " + "enemyAIForceStrength " + enemyAIForceStrength + " " + "playerForceStrength" + playerForceStrength); + + return enemyAIForceStrength > 0 && playerForceStrength/enemyAIForceStrength < ratio; + + + + } + + +} \ No newline at end of file diff --git a/enemyAI/defenseManagerAI.java b/enemyAI/defenseManagerAI.java new file mode 100644 index 0000000..634847a --- /dev/null +++ b/enemyAI/defenseManagerAI.java @@ -0,0 +1,166 @@ +package enemyAI; + +import core.baseInfo; +import core.mainThread; +import core.vector; +import entity.solidObject; +import entity.stealthTank; + +public class defenseManagerAI { + public baseInfo theBaseInfo; + + public int gameTime; + + public int currentState; + public final int booming = 0; + public final int aggressing = 1; + public final int defending = 2; + + public solidObject[] observers; + + public solidObject[] stealthTanksControlledByCombatAI; + + public vector direction; + + public defenseManagerAI(baseInfo theBaseInfo){ + this.theBaseInfo = theBaseInfo; + + observers = new solidObject[4]; + + direction = new vector(0,0,0); + + } + + + //at 500 seconds mark, send 2 observers to the 2 western and southern side of the main base. After grabbing the northwest (or southeast, depends on which expansion get grabbed first) expansion + //send 2 additional observers to look for player sneak attacks + + + public void processAI(){ + gameTime++; + + currentState = mainThread.ec.theCombatManagerAI.currentState; + + stealthTanksControlledByCombatAI = mainThread.ec.theUnitProductionAI.stealthTanksControlledByCombatAI; + + //after 500 seconds mark, borrow 2 stealth tanks from combat manager, and send them to guard western and southern side of the main base + if(gameTime >= 480) { + for(int i = 0; i < 2; i++) { + if(observers[i] == null || observers[i].currentHP <=0) { + for(int j = 0; j < stealthTanksControlledByCombatAI.length; j++) { + if(stealthTanksControlledByCombatAI[j] != null && stealthTanksControlledByCombatAI[j].currentHP == 80 && stealthTanksControlledByCombatAI[j].attackStatus != solidObject.isAttacking) { + observers[i] = stealthTanksControlledByCombatAI[j]; + stealthTanksControlledByCombatAI[j] = null; + float xPos = 21f; + float zPos = 30.5f; + + if(i == 1) { + xPos = 30f; + zPos = 20f; + } + observers[i].moveTo(xPos, zPos); + observers[i].currentCommand = solidObject.move; + observers[i].secondaryCommand = solidObject.StandBy; + break; + } + } + } + } + } + + //keep an eye on player units and avoid being detected + for(int i = 0; i < observers.length; i++) { + if(observers[i] != null) { + + if(!evadePlayerUnit(i)) { + float xPos = 0; + float zPos = 0; + + //if there is no player units in sight, return to patrol position + if(i == 0) { + if(gameTime%30 < 15) { + xPos = 19f; + zPos = 30.5f; + }else { + xPos = 19f; + zPos = 22.5f; + } + + } + + if(i == 1) { + + if(gameTime%20 < 10) { + xPos = 30f; + zPos = 20f; + }else { + xPos = 26f; + zPos = 20f; + } + + } + observers[i].moveTo(xPos, zPos); + observers[i].currentCommand = solidObject.move; + observers[i].secondaryCommand = solidObject.StandBy; + } + + } + } + + + } + + public boolean evadePlayerUnit(int observerIndex){ + //scan for hostile unit + int[] tileCheckList = stealthTank.tileCheckList; + + int currentOccupiedTile = (int)(observers[observerIndex].centre.x*64)/16 + (127 - (int)(observers[observerIndex].centre.z*64)/16)*128; + + + direction.set(0,0,0); + boolean directionSet = false; + + 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; + solidObject[] tile = mainThread.gridMap.tiles[index]; + + for(int j = 0; j < 4; j++){ + if(tile[j] != null){ + if(tile[j].teamNo != observers[observerIndex].teamNo && tile[j].teamNo != -1 && tile[j].currentHP > 0 && !tile[j].isCloaked){ + + + if(directionSet) + break; + + double d = Math.sqrt((tile[j].centre.x - observers[observerIndex].centre.x)*(tile[j].centre.x - observers[observerIndex].centre.x) + + (tile[j].centre.z - observers[observerIndex].centre.z)*(tile[j].centre.z - observers[observerIndex].centre.z)); + + if(d < 0.75) { + + direction.set(observers[observerIndex].centre); + direction.subtract(tile[j].centre); + direction.unit(); + + directionSet = true; + } + } + } + } + } + } + + + if(directionSet) { + observers[observerIndex].moveTo(observers[observerIndex].centre.x + direction.x , observers[observerIndex].centre.z + direction.z); + observers[observerIndex].currentCommand = solidObject.move; + observers[observerIndex].secondaryCommand = solidObject.StandBy; + } + + return directionSet; + + } + +} diff --git a/enemyAI/economyManagerAI.java b/enemyAI/economyManagerAI.java new file mode 100644 index 0000000..7b5375d --- /dev/null +++ b/enemyAI/economyManagerAI.java @@ -0,0 +1,161 @@ +package enemyAI; + +import core.baseInfo; +import core.mainThread; +import core.vector; +import entity.constructionYard; +import entity.goldMine; +import entity.harvester; + +public class economyManagerAI { + + //this represent the cloest gold mine to the enemy player's constructionyard + public goldMine preferedGoldMine; + public int preferedGoldMineLocation; + public baseInfo theBaseInfo; + + public int numberOfharvesters; + public vector evadeDirection; + + + public economyManagerAI(baseInfo theBaseInfo){ + this.theBaseInfo = theBaseInfo; + + evadeDirection = new vector(0,0,0); + + } + + public void processAI(){ + //find an ideal goldmine + goldMine[] goldMines = mainThread.theAssetManager.goldMines; + constructionYard[] constructionYards = mainThread.theAssetManager.constructionYards; + + if(preferedGoldMine == null || preferedGoldMine.goldDeposite <= 10){ + float distance = 100000; + for(int i = 0; i < constructionYards.length; i++){ + if(constructionYards[i] != null && constructionYards[i].teamNo != 0){ + for(int j = 0; j < goldMines.length; j++){ + if(goldMines[j] == null || goldMines[j].goldDeposite <=10) + continue; + + float newDistance = (goldMines[j].centre.x - constructionYards[i].centre.x)*(goldMines[j].centre.x - constructionYards[i].centre.x) + +(goldMines[j].centre.z - constructionYards[i].centre.z)*(goldMines[j].centre.z - constructionYards[i].centre.z); + + if( newDistance < distance){ + preferedGoldMine = goldMines[j]; + distance = newDistance; + } + } + + } + } + } + + preferedGoldMineLocation = (int)(preferedGoldMine.centre.x*64)/16 + (127 - (int)(preferedGoldMine.centre.z*64)/16)*128; + + + //count number of harvesters and prevent them from doing something stupid + int numberOfHarvesterOnQueue = 0; + for(int i = 0; i < mainThread.theAssetManager.factories.length; i++){ + if(mainThread.theAssetManager.factories[i] != null && mainThread.theAssetManager.factories[i].teamNo != 0){ + if(preferedGoldMine != null) + mainThread.theAssetManager.factories[i].targetGoldMine = preferedGoldMine; + numberOfHarvesterOnQueue += mainThread.theAssetManager.factories[i].numOfHarvesterOnQueue; + } + } + + for(int i = 0; i < mainThread.theAssetManager.constructionYards.length; i++){ + if(mainThread.theAssetManager.constructionYards[i] != null && mainThread.theAssetManager.constructionYards[i].teamNo != 0){ + if(mainThread.theAssetManager.constructionYards[i].currentBuildingType == 102) + numberOfHarvesterOnQueue += 1; + } + } + + numberOfharvesters = 0; + for(int i = 0; i < mainThread.theAssetManager.harvesters.length; i++){ + if(mainThread.theAssetManager.harvesters[i] != null && mainThread.theAssetManager.harvesters[i].teamNo != 0){ + numberOfharvesters++; + harvester o = mainThread.theAssetManager.harvesters[i]; + if(o.movement.x == 0 && o.movement.z == 0){ + if(o.cargoDeposite > 0 && o.jobStatus == 0){ + o.returnToRefinery(null); + } + } + + //when current gold mine run out of gold, direct harvester to the nearest goldmines which still have deposit + if(o.cargoDeposite == 0 && o.myGoldMine != null && o.myGoldMine.goldDeposite <= 1){ + if(preferedGoldMine != null){ + boolean hasRefineryNearby = false; + for(int j = 0; j < mainThread.theAssetManager.refineries.length; j++){ + if(mainThread.theAssetManager.refineries[j] != null && mainThread.theAssetManager.refineries[j].teamNo !=0){ + if(mainThread.theAssetManager.refineries[j].getDistance(preferedGoldMine) < 2){ + hasRefineryNearby = true; + break; + } + } + } + + int numberOfHarvestersOnTheMine = 0; + for(int j = 0; j < mainThread.theAssetManager.harvesters.length; j++){ + if(mainThread.theAssetManager.harvesters[j] != null && mainThread.theAssetManager.harvesters[j].teamNo !=0 && mainThread.theAssetManager.harvesters[j].myGoldMine == preferedGoldMine) + numberOfHarvestersOnTheMine++; + } + + //only go to the gold mine that has a refinery nearby and its not saturated with harvesters + if(numberOfHarvestersOnTheMine < 6) + o.myGoldMine = preferedGoldMine; + } + } + + //when harvester is under attack then temporarily move away from mining until the danger passes + if(o.underAttackCountDown > 0) { + o.isEvadingFromAttack = true; + if(o.attacker != null) { + evadeDirection.set(o.centre); + evadeDirection.subtract(o.attacker.centre); + evadeDirection.unit(); + + float desX = o.centre.x + evadeDirection.x*2; + float desZ = o.centre.z + evadeDirection.z*2; + + if(desX > 31) + desX = 31; + if(desX < 1) + desX = 1; + + if(desZ > 31) + desZ = 31; + if(desZ < 1) + desZ = 1; + + o.moveTo(desX, desZ); + } + }else { + if(o.isEvadingFromAttack == true) { + o.returnToRefinery(null); + o.isEvadingFromAttack = false; + } + } + + + } + } + numberOfharvesters+=numberOfHarvesterOnQueue; + + //the ration between harvester and refinery should be 2:1 + //economyManager has a higher priority than combat manager AI, so the enemy AI will always queue harvester first if lost any. + if(theBaseInfo.numberOfRefinery > 0 && numberOfharvesters < 4){ + if(numberOfharvesters/theBaseInfo.numberOfRefinery < 2){ + for(int i = 0; i < mainThread.theAssetManager.factories.length; i++){ + if(mainThread.theAssetManager.factories[i] != null && mainThread.theAssetManager.factories[i].teamNo != 0){ + if(mainThread.theAssetManager.factories[i].isIdle()){ + mainThread.theAssetManager.factories[i].buildHarvester(); + break; + } + } + } + } + } + } + +} diff --git a/enemyAI/enemyCommander.java b/enemyAI/enemyCommander.java new file mode 100644 index 0000000..1e779a1 --- /dev/null +++ b/enemyAI/enemyCommander.java @@ -0,0 +1,131 @@ +package enemyAI; + +import core.baseInfo; +import core.mainThread; + +public class enemyCommander { + + //vision map represents the vision of the enemy commander + public static boolean[] visionMap; + + public static boolean[] tempBitmap; + + public baseInfo theBaseInfo; + + public buildingManagerAI theBuildingManagerAI; + public economyManagerAI theEconomyManagerAI; + public mapAwarenessAI theMapAwarenessAI; + public unitProductionAI theUnitProductionAI; + public baseExpensionAI theBaseExpentionAI; + public scoutingManagerAI theScoutingManagerAI; + public defenseManagerAI theDefenseManagerAI; + public combatManagerAI theCombatManagerAI; + public microManagementAI theMicroManagementAI; + + public void init(){ + + //init vision map + visionMap = new boolean[128*128]; + + tempBitmap = new boolean[148 * 148]; + + theBaseInfo = new baseInfo(); + + theBuildingManagerAI = new buildingManagerAI(theBaseInfo); + theEconomyManagerAI = new economyManagerAI(theBaseInfo); + theMapAwarenessAI = new mapAwarenessAI(theBaseInfo, visionMap); + theUnitProductionAI = new unitProductionAI(theBaseInfo); + theBaseExpentionAI = new baseExpensionAI(theBaseInfo); + theScoutingManagerAI = new scoutingManagerAI(theBaseInfo); + theDefenseManagerAI = new defenseManagerAI(theBaseInfo); + theCombatManagerAI = new combatManagerAI(theBaseInfo); + theMicroManagementAI = new microManagementAI(theBaseInfo); + + } + + + public void update(){ + theBaseInfo.update(); + + + //generate visionMap based on the map information of the previous frame + for(int y = 0; y < 128; y++){ + for(int x = 0; x < 128; x++){ + visionMap[x + y*128] = tempBitmap[x + 10 + (y + 10)*148]; + } + } + + + //process high level enemy AI + thinkHardLikeHumanPlayer(); + + + drawVisionMap(); + + //reset tempBitmap; + for(int i = 0 ;i < tempBitmap.length; i++){ + tempBitmap[i] = false; + } + } + + public void drawVisionMap(){ + int pos = 2 + 20 * 768; + boolean tile; + int[] screen = mainThread.screen2; + for(int i = 0; i < 128; i++){ + for(int j = 0; j < 128; j++){ + tile = visionMap[j + i*128]; + if(!tile) + screen[pos + j + i*768] = 0; + + } + } + } + + + public void thinkHardLikeHumanPlayer(){ + + if(mainThread.frameIndex % 30 == 0){ + theMapAwarenessAI.processAI(); + } + + if(mainThread.frameIndex % 30 == 1){ + theBuildingManagerAI.processAI(); + } + + if(mainThread.frameIndex % 30 == 2){ + theEconomyManagerAI.processAI(); + } + + if(mainThread.frameIndex % 30 == 3){ + theScoutingManagerAI.processAI(); + } + + if(mainThread.frameIndex % 30 == 4){ + theUnitProductionAI.processAI(); + } + + if(mainThread.frameIndex % 30 == 5){ + theBaseExpentionAI.processAI(); + } + + if(mainThread.frameIndex % 30 == 6){ + theCombatManagerAI.processAI(); + } + + if(mainThread.frameIndex % 30 == 7){ + theDefenseManagerAI.processAI(); + } + + //if(mainThread.frameIndex % 5 == 0){ + theMicroManagementAI.processAI(); + //} + + + + + + + } + +} diff --git a/enemyAI/mapAwarenessAI.java b/enemyAI/mapAwarenessAI.java new file mode 100644 index 0000000..2bfcf13 --- /dev/null +++ b/enemyAI/mapAwarenessAI.java @@ -0,0 +1,515 @@ +package enemyAI; + +import core.AssetManager; +import core.baseInfo; +import core.mainThread; +import entity.goldMine; +import entity.solidObject; + +//1. scan revealed area for player's units and building +//2. keep track of player's units +//3. create strategic information based on the quantity/location of player's units + + +public class mapAwarenessAI { + + public baseInfo theBaseInfo; + + public int numberOfLightTanks_player, numberOfLightTanks_AI, numberOfLightTanksOnMinimap_player; + public int numberOfStealthTanks_player, numberOfStealthTanks_AI, numberOfStealthTanksOnMinimap_player; + public int numberOfRocketTanks_player, numberOfRocketTanks_AI, numberOfRocketTanksOnMinimap_player; + public int numberOfHeavyTanks_player, numberOfHeavyTanks_AI, numberOfHeavyTanksOnMinimap_player; + public int numberOfPlayerUnitsOnMinimap; + public int numberOfGunTurret_player; + public int numberOfMissileTurret_player; + public int numberOfFactory_player; + public int numberOfRefinery_player; + public int numberOfConstructionYard_player; + public int numberOfCommunicationCenter_player; + public int numberOfTechCenter_player; + public int numberOfPowerPlant_player; + + public int maxNumberOfStealthTanks_playerInLastFiveMinutes; + public int fiveMinuteTimer; + + public int numberOfPlayerUnitDestroyed; + public int numberOfPlayerBuildingDestroyed; + + public boolean playerHasMostlyLightTanks; + public boolean playerHasMostlyHeavyTanks; + public boolean playIsRushingHighTierUnits; + public boolean playerLikelyCanNotProduceHighTierUnits; + public boolean playerDoesntHaveMassHeavyTanks; + public boolean playerIsRushingLightTank; + public boolean playerHasManyLightTanksButNoHeavyTank; + + public solidObject[] mapAsset; + public boolean[] visionMap; + public AssetManager theAssetManager; + public solidObject[] playerUnitInMinimap; + public solidObject[] playerStaticDefenceInMinimap; + public solidObject[] playerStructures; + + public goldMine[] goldMines; + public int targetPlayerExpension; + public int[] playerExpensionInfo; + public int numberOfplayerMiningBases; + + + public mapAwarenessAI(baseInfo theBaseInfo, boolean[] visionMap){ + this.theBaseInfo = theBaseInfo; + this.visionMap = visionMap; + + mapAsset = new solidObject[1024]; + playerUnitInMinimap = new solidObject[128]; + playerStaticDefenceInMinimap = new solidObject[64]; + playerStructures = new solidObject[256]; + + goldMines = mainThread.theAssetManager.goldMines; + playerExpensionInfo = new int[goldMines.length]; + } + + public void processAI(){ + theAssetManager = mainThread.theAssetManager; + + //the number of player's military units in AI's vision + numberOfLightTanksOnMinimap_player = 0; + numberOfRocketTanksOnMinimap_player = 0; + numberOfStealthTanksOnMinimap_player = 0; + numberOfHeavyTanksOnMinimap_player = 0; + numberOfPlayerUnitsOnMinimap = 0; + + //the total number of player's unit that are detected by AI + numberOfLightTanks_player = 0; + numberOfRocketTanks_player = 0; + numberOfStealthTanks_player = 0; + numberOfHeavyTanks_player = 0; + numberOfGunTurret_player = 0; + numberOfMissileTurret_player = 0; + numberOfFactory_player = 0; + numberOfRefinery_player = 0; + numberOfConstructionYard_player = 0; + numberOfCommunicationCenter_player = 0; + numberOfTechCenter_player = 0; + + //the total number of AI military units + numberOfLightTanks_AI = 0; + numberOfRocketTanks_AI = 0; + numberOfStealthTanks_AI = 0; + numberOfHeavyTanks_AI = 0; + + //clear enemy info from previous frame + for(int i = 0; i < playerUnitInMinimap.length; i++) + playerUnitInMinimap[i] = null; + for(int i = 0; i < playerStaticDefenceInMinimap.length; i++) + playerStaticDefenceInMinimap[i] = null; + for(int i = 0; i < playerStructures.length; i++) + playerStructures[i] = null; + + + for(int i = 0; i < theAssetManager.lightTanks.length; i++){ + if(theAssetManager.lightTanks[i] != null && theAssetManager.lightTanks[i].teamNo ==0){ + if(visionMap[theAssetManager.lightTanks[i].occupiedTile0]){ + numberOfLightTanksOnMinimap_player++; + addPlayerUnitInMinimap(theAssetManager.lightTanks[i]); + if(mapAsset[theAssetManager.lightTanks[i].ID] == null) { + mapAsset[theAssetManager.lightTanks[i].ID] = theAssetManager.lightTanks[i]; + mainThread.ec.theCombatManagerAI.offScreenPlayerForceStrength-=1; + } + } + }else if(theAssetManager.lightTanks[i] != null && theAssetManager.lightTanks[i].teamNo !=0){ + numberOfLightTanks_AI++; + if(mapAsset[theAssetManager.lightTanks[i].ID] == null){ + mainThread.ec.theUnitProductionAI.addLightTank(theAssetManager.lightTanks[i]); + mapAsset[theAssetManager.lightTanks[i].ID] = theAssetManager.lightTanks[i]; + } + } + } + + for(int i = 0; i < theAssetManager.rocketTanks.length; i++){ + if(theAssetManager.rocketTanks[i] != null && theAssetManager.rocketTanks[i].teamNo ==0){ + if(visionMap[theAssetManager.rocketTanks[i].occupiedTile0]){ + numberOfRocketTanksOnMinimap_player++; + addPlayerUnitInMinimap(theAssetManager.rocketTanks[i]); + if(mapAsset[theAssetManager.rocketTanks[i].ID] == null) { + mapAsset[theAssetManager.rocketTanks[i].ID] = theAssetManager.rocketTanks[i]; + mainThread.ec.theCombatManagerAI.offScreenPlayerForceStrength-=1.5; + } + } + }else if(theAssetManager.rocketTanks[i] != null && theAssetManager.rocketTanks[i].teamNo !=0){ + numberOfRocketTanks_AI++; + if(mapAsset[theAssetManager.rocketTanks[i].ID] == null){ + mainThread.ec.theUnitProductionAI.addRocketTank(theAssetManager.rocketTanks[i]); + mapAsset[theAssetManager.rocketTanks[i].ID] = theAssetManager.rocketTanks[i]; + } + } + } + + for(int i = 0; i < theAssetManager.stealthTanks.length; i++){ + if(theAssetManager.stealthTanks[i] != null && theAssetManager.stealthTanks[i].teamNo ==0){ + if(visionMap[theAssetManager.stealthTanks[i].occupiedTile0] && !theAssetManager.stealthTanks[i].isCloaked){ + numberOfStealthTanksOnMinimap_player++; + addPlayerUnitInMinimap(theAssetManager.stealthTanks[i]); + if(mapAsset[theAssetManager.stealthTanks[i].ID] == null) { + mapAsset[theAssetManager.stealthTanks[i].ID] = theAssetManager.stealthTanks[i]; + mainThread.ec.theCombatManagerAI.offScreenPlayerForceStrength-=2; + } + } + }else if(theAssetManager.stealthTanks[i] != null && theAssetManager.stealthTanks[i].teamNo !=0){ + numberOfStealthTanks_AI++; + if(mapAsset[theAssetManager.stealthTanks[i].ID] == null){ + mainThread.ec.theUnitProductionAI.addStealthTank(theAssetManager.stealthTanks[i]); + mapAsset[theAssetManager.stealthTanks[i].ID] = theAssetManager.stealthTanks[i]; + } + } + + } + + for(int i = 0; i < theAssetManager.heavyTanks.length; i++){ + if(theAssetManager.heavyTanks[i] != null && theAssetManager.heavyTanks[i].teamNo ==0){ + if(visionMap[theAssetManager.heavyTanks[i].occupiedTile0]){ + numberOfHeavyTanksOnMinimap_player++; + addPlayerUnitInMinimap(theAssetManager.heavyTanks[i]); + if(mapAsset[theAssetManager.heavyTanks[i].ID] == null) { + mapAsset[theAssetManager.heavyTanks[i].ID] = theAssetManager.heavyTanks[i]; + mainThread.ec.theCombatManagerAI.offScreenPlayerForceStrength-=3.5; + } + } + }else if(theAssetManager.heavyTanks[i] != null && theAssetManager.heavyTanks[i].teamNo !=0){ + numberOfHeavyTanks_AI++; + if(mapAsset[theAssetManager.heavyTanks[i].ID] == null){ + mainThread.ec.theUnitProductionAI.addHeavyTank(theAssetManager.heavyTanks[i]); + mapAsset[theAssetManager.heavyTanks[i].ID] = theAssetManager.heavyTanks[i]; + } + } + } + + for(int i = 0; i < theAssetManager.harvesters.length; i++){ + if(theAssetManager.harvesters[i] != null && theAssetManager.harvesters[i].teamNo ==0){ + if(visionMap[theAssetManager.harvesters[i].occupiedTile0]){ + addPlayerUnitInMinimap(theAssetManager.harvesters[i]); + mapAsset[theAssetManager.harvesters[i].ID] = theAssetManager.harvesters[i]; + } + } + } + + for(int i = 0; i < theAssetManager.constructionVehicles.length; i++){ + if(theAssetManager.constructionVehicles[i] != null && theAssetManager.constructionVehicles[i].teamNo ==0){ + if(visionMap[theAssetManager.constructionVehicles[i].occupiedTile0]){ + addPlayerUnitInMinimap(theAssetManager.constructionVehicles[i]); + mapAsset[theAssetManager.constructionVehicles[i].ID] = theAssetManager.constructionVehicles[i]; + } + } + } + + + //add revealed player's building to mapAsset + for(int i = 0; i < theAssetManager.gunTurrets.length; i++){ + if(theAssetManager.gunTurrets[i] != null && theAssetManager.gunTurrets[i].teamNo ==0){ + if(visionMap[theAssetManager.gunTurrets[i].tileIndex[0]]){ + if(mapAsset[theAssetManager.gunTurrets[i].ID] == null) { + mapAsset[theAssetManager.gunTurrets[i].ID] = theAssetManager.gunTurrets[i]; + mainThread.ec.theCombatManagerAI.offScreenPlayerForceStrength-=1; + } + } + } + } + + for(int i = 0; i < theAssetManager.missileTurrets.length; i++){ + if(theAssetManager.missileTurrets[i] != null && theAssetManager.missileTurrets[i].teamNo ==0){ + if(visionMap[theAssetManager.missileTurrets[i].tileIndex[0]]){ + if(mapAsset[theAssetManager.missileTurrets[i].ID] == null) { + mapAsset[theAssetManager.missileTurrets[i].ID] = theAssetManager.missileTurrets[i]; + mainThread.ec.theCombatManagerAI.offScreenPlayerForceStrength-=2; + } + } + } + } + + for(int i = 0; i < theAssetManager.factories.length; i++){ + if(theAssetManager.factories[i] != null && theAssetManager.factories[i].teamNo ==0){ + for(int j = 0; j < 6; j++){ + if(visionMap[theAssetManager.factories[i].tileIndex[j]]){ + if(mapAsset[theAssetManager.factories[i].ID] == null) + mapAsset[theAssetManager.factories[i].ID] = theAssetManager.factories[i]; + break; + } + } + } + } + + for(int i = 0; i < theAssetManager.refineries.length; i++){ + if(theAssetManager.refineries[i] != null && theAssetManager.refineries[i].teamNo ==0){ + for(int j = 0; j < 6; j++){ + if(visionMap[theAssetManager.refineries[i].tileIndex[j]]){ + if(mapAsset[theAssetManager.refineries[i].ID] == null) + mapAsset[theAssetManager.refineries[i].ID] = theAssetManager.refineries[i]; + break; + } + } + } + } + + + for(int i = 0; i < theAssetManager.constructionYards.length; i++){ + if(theAssetManager.constructionYards[i] != null && theAssetManager.constructionYards[i].teamNo ==0){ + for(int j = 0; j < 9; j++){ + if(visionMap[theAssetManager.constructionYards[i].tileIndex[j]]){ + if(mapAsset[theAssetManager.constructionYards[i].ID] == null) + mapAsset[theAssetManager.constructionYards[i].ID] = theAssetManager.constructionYards[i]; + break; + } + } + } + } + + for(int i = 0; i < theAssetManager.communicationCenters.length; i++){ + if(theAssetManager.communicationCenters[i] != null && theAssetManager.communicationCenters[i].teamNo ==0){ + for(int j = 0; j < 4; j++){ + if(visionMap[theAssetManager.communicationCenters[i].tileIndex[j]]){ + if(mapAsset[theAssetManager.communicationCenters[i].ID] == null) + mapAsset[theAssetManager.communicationCenters[i].ID] = theAssetManager.communicationCenters[i]; + break; + } + } + } + } + + for(int i = 0; i < theAssetManager.techCenters.length; i++){ + if(theAssetManager.techCenters[i] != null && theAssetManager.techCenters[i].teamNo ==0){ + for(int j = 0; j < 4; j++){ + if(visionMap[theAssetManager.techCenters[i].tileIndex[j]]){ + if(mapAsset[theAssetManager.techCenters[i].ID] == null) + mapAsset[theAssetManager.techCenters[i].ID] = theAssetManager.techCenters[i]; + break; + } + } + } + } + + for(int i = 0; i < theAssetManager.powerPlants.length; i++){ + if(theAssetManager.powerPlants[i] != null && theAssetManager.powerPlants[i].teamNo ==0){ + for(int j = 0; j < 4; j++){ + if(visionMap[theAssetManager.powerPlants[i].tileIndex[j]]){ + if(mapAsset[theAssetManager.powerPlants[i].ID] == null) + mapAsset[theAssetManager.powerPlants[i].ID] = theAssetManager.powerPlants[i]; + break; + } + } + } + } + + + numberOfPlayerUnitDestroyed = 0; + numberOfPlayerBuildingDestroyed = 0; + + for(int i = 0; i < mapAsset.length; i++){ + if(mapAsset[i] != null && mapAsset[i].teamNo == 0){ + if(mapAsset[i].currentHP>0){ + if(mapAsset[i].type == 0 ) + numberOfLightTanks_player++; + else if(mapAsset[i].type == 1) + numberOfRocketTanks_player++; + else if(mapAsset[i].type == 6) + numberOfStealthTanks_player++; + else if(mapAsset[i].type == 7) + numberOfHeavyTanks_player++; + else{ + mapAsset[i].isRevealed_AI = true; + if(mapAsset[i].type == 200){ + numberOfGunTurret_player++; + addPlayerStaticDefenceInMinimap(mapAsset[i]); + addPlayerStructure(mapAsset[i]); + }else if(mapAsset[i].type == 199){ + addPlayerStaticDefenceInMinimap(mapAsset[i]); + addPlayerStructure(mapAsset[i]); + numberOfMissileTurret_player++; + }else if(mapAsset[i].type == 105){ + addPlayerStructure(mapAsset[i]); + numberOfFactory_player++; + }else if(mapAsset[i].type == 102){ + numberOfRefinery_player++; + addPlayerStructure(mapAsset[i]); + }else if(mapAsset[i].type == 104){ + addPlayerStructure(mapAsset[i]); + numberOfConstructionYard_player++; + }else if(mapAsset[i].type == 106){ + addPlayerStructure(mapAsset[i]); + numberOfCommunicationCenter_player++; + }else if(mapAsset[i].type == 107){ + addPlayerStructure(mapAsset[i]); + numberOfTechCenter_player++; + }else if(mapAsset[i].type == 101){ + addPlayerStructure(mapAsset[i]); + numberOfPowerPlant_player++; + } + } + }else{ + if(mapAsset[i].type < 100) + numberOfPlayerUnitDestroyed++; + else + numberOfPlayerBuildingDestroyed++; + } + } + + } + + //analyze the enemy units composition + + float lightTankRatio = (float)(numberOfLightTanks_player)/(numberOfLightTanks_player + numberOfRocketTanks_player + numberOfStealthTanks_player + numberOfHeavyTanks_player + 1); + + playerHasMostlyLightTanks = numberOfLightTanks_player > 5 && lightTankRatio > 0.8f; + playerHasMostlyHeavyTanks = numberOfHeavyTanks_player > 3 && (float)(numberOfHeavyTanks_player)/(numberOfLightTanks_player + numberOfRocketTanks_player + numberOfStealthTanks_player + numberOfHeavyTanks_player) > 0.6f; + playerHasManyLightTanksButNoHeavyTank = lightTankRatio > 0.5 && lightTankRatio <=0.8 && numberOfHeavyTanks_player < 3; + + playIsRushingHighTierUnits = mainThread.frameIndex/30 > 250 && mainThread.frameIndex/30 < 400 + && mainThread.ec.theMapAwarenessAI.numberOfTechCenter_player >0 + && mainThread.ec.theMapAwarenessAI.numberOfMissileTurret_player < 2 + && mainThread.ec.theMapAwarenessAI.numberOfGunTurret_player < 4 + && numberOfLightTanks_player + numberOfRocketTanks_player + numberOfStealthTanks_player < 5; + + playerLikelyCanNotProduceHighTierUnits = mainThread.ec.theMapAwarenessAI.numberOfTechCenter_player == 0 && mainThread.ec.theMapAwarenessAI.numberOfHeavyTanks_player == 0; + playerDoesntHaveMassHeavyTanks = (float)numberOfHeavyTanks_player/( 1 + numberOfLightTanks_AI + numberOfRocketTanks_player + numberOfStealthTanks_player) < 0.2f; + + playerIsRushingLightTank = mainThread.frameIndex/30 > 300 && mainThread.frameIndex/30 < 600 && ((playerLikelyCanNotProduceHighTierUnits && numberOfStealthTanks_player < 3) || playerHasMostlyLightTanks); + + + //advanced counting of player units + if(numberOfStealthTanks_player > maxNumberOfStealthTanks_playerInLastFiveMinutes) { + maxNumberOfStealthTanks_playerInLastFiveMinutes = numberOfStealthTanks_player; + fiveMinuteTimer = 300; + } + if(fiveMinuteTimer > 0) + fiveMinuteTimer--; + else + maxNumberOfStealthTanks_playerInLastFiveMinutes = 0; + + + findTheMostVulnerablePlayerBase(); + + } + + + public void addPlayerUnitInMinimap(solidObject o){ + for(int i = 0; i < playerUnitInMinimap.length; i++){ + if(playerUnitInMinimap[i] == null){ + playerUnitInMinimap[i] = o; + numberOfPlayerUnitsOnMinimap++; + break; + } + } + } + + public void addPlayerStaticDefenceInMinimap(solidObject o){ + for(int i = 0; i < playerStaticDefenceInMinimap.length; i++){ + if(playerStaticDefenceInMinimap[i] == null){ + playerStaticDefenceInMinimap[i] = o; + break; + } + } + } + + public void addPlayerStructure(solidObject o){ + for(int i = 0; i < playerStructures.length; i++){ + if(playerStructures[i] == null){ + playerStructures[i] = o; + break; + } + } + } + + public void findTheMostVulnerablePlayerBase(){ + + //check if there are any player's structure around each gold mine. + for(int i = 0; i < goldMines.length; i++){ + playerExpensionInfo[i] = findplayexpensionDefenseScore(goldMines[i], 3); + } + + //compute the target player expansion defense score + targetPlayerExpension = -1; + int playExpensionDefenseScore = 999999; + + + numberOfplayerMiningBases = 0; + for(int i = 0; i < playerExpensionInfo.length; i++){ + if(goldMines[i] != null && goldMines[i].goldDeposite > 5000 && playerExpensionInfo[i] != 0){ + numberOfplayerMiningBases++; + if(playerExpensionInfo[i] < playExpensionDefenseScore){ + playExpensionDefenseScore = playerExpensionInfo[i]; + targetPlayerExpension = i; + } + + } + } + + + //if a player expansion exists on the path to the target expansion is already been taken by player's force, + //then mark it as the target expansion instead + if(targetPlayerExpension == 0){ + if(playerExpensionInfo[5] >0) + targetPlayerExpension = 5; + else if(playerExpensionInfo[6] >0) + targetPlayerExpension = 6; + else if(playerExpensionInfo[7] >0) + targetPlayerExpension = 7; + else if(playerExpensionInfo[1] > 0) + targetPlayerExpension = 1; + }else if(targetPlayerExpension == 1){ + if(playerExpensionInfo[5] >0) + targetPlayerExpension = 5; + else if(playerExpensionInfo[6] >0) + targetPlayerExpension = 6; + else if(playerExpensionInfo[7] >0) + targetPlayerExpension = 7; + }else if(targetPlayerExpension == 7){ + if(playerExpensionInfo[5] >0) + targetPlayerExpension = 5; + else if(playerExpensionInfo[6] >0) + targetPlayerExpension = 6; + }else if(targetPlayerExpension == 6){ + if(playerExpensionInfo[5] >0) + targetPlayerExpension = 5; + } + + //if(targetPlayerExpension != -1) + // return playerExpensionInfo[targetPlayerExpension]; + + //return 0; + } + + public int findplayexpensionDefenseScore(goldMine g, float r){ + if(g == null) + return 0; + + solidObject[] playerStructures = mainThread.ec.theMapAwarenessAI.playerStructures; + solidObject[] playerStaticDefence = mainThread.ec.theMapAwarenessAI.playerStaticDefenceInMinimap; + + float x = g.centre.x; + float z = g.centre.z; + + int playexpensionDefenseScore = 0; + for(int i = 0 ; i < playerStructures.length; i++){ + if(playerStructures[i]!= null && Math.abs(playerStructures[i].centre.x - x) < r && Math.abs(playerStructures[i].centre.z - z) < r) + playexpensionDefenseScore++; + } + + for(int i = 0 ; i < playerStaticDefence.length; i++){ + if(playerStaticDefence[i]!= null && Math.abs(playerStructures[i].centre.x - x) < r && Math.abs(playerStructures[i].centre.z - z) < r){ + if(playerStaticDefence[i].type == 200) //gun turret will increase player base's defense score + playexpensionDefenseScore+=1000; + if(playerStaticDefence[i].type == 199) //missile turret will increase player base's defense score even futher + playexpensionDefenseScore+=3000; + } + } + + + //if the player already takes the expansion which the enemy AI plans to expand to, assign zero score to this expansion + if(g == mainThread.ec.theBaseExpentionAI.expensionGoldMine && playexpensionDefenseScore > 0){ + return -1; + } + + return playexpensionDefenseScore; + } + + +} diff --git a/enemyAI/microManagementAI.java b/enemyAI/microManagementAI.java new file mode 100644 index 0000000..3fca180 --- /dev/null +++ b/enemyAI/microManagementAI.java @@ -0,0 +1,226 @@ +package enemyAI; + +import core.baseInfo; +import core.mainThread; +import entity.solidObject; +import entity.techCenter; + +//micro manage the units on the battle field to trade units better against player + +public class microManagementAI { + + public baseInfo theBaseInfo; + + public int frameAI; + + 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(baseInfo theBaseInfo){ + this.theBaseInfo = theBaseInfo; + } + + public void processAI(){ + + frameAI++; + + 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) { + + //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*1.25f); + } + + unitInCombatRadius[i].targetObject.incomingDamage+=myDamage*2; + + }else { + + float myRange= unitInCombatRadius[i].attackRange * unitInCombatRadius[i].attackRange; + + //Prioritize searching for targets among static defenses + boolean suitableTargertFound = false; + 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 distanceToDesination = (x1 - x2)*(x1 - x2) + (z1 - z2)*(z1 - z2); + if(distanceToDesination < myRange){ + unitInCombatRadius[i].attack(playerStaticDefenceInMinimap[j]); + + unitInCombatRadius[i].currentCommand = solidObject.attackCautiously; + + suitableTargertFound = true; + + + int myDamage = unitInCombatRadius[i].myDamage; + if(techCenter.rocketTankResearched_enemy) { + myDamage*=2; + } + myDamage = (int)(myDamage*1.25f); + + playerStaticDefenceInMinimap[j].incomingDamage+=myDamage*2; + break; + } + } + } + + if(suitableTargertFound) + continue; + + + //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; + float 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; + 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 && !(unitInCombatRadius[i].targetObject!= null && unitInCombatRadius[i].targetObject.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; + } + +} diff --git a/enemyAI/scoutingManagerAI.java b/enemyAI/scoutingManagerAI.java new file mode 100644 index 0000000..e3f758c --- /dev/null +++ b/enemyAI/scoutingManagerAI.java @@ -0,0 +1,338 @@ +package enemyAI; + +import core.Rect; +import core.baseInfo; +import core.mainThread; +import core.vector; +import entity.lightTank; +import entity.solidObject; + +public class scoutingManagerAI { + + public baseInfo theBaseInfo; + + public int gameTime; + + public int scoutingMode; + + public final int patrolling = 0; + public final int exploring = 1; + + public float[][] patrolNodes; + public float[][] exploringNodes; + + public int destinationNode; + + public boolean movementOrderIssued; + + public vector tempVector1, tempVector2, tempVector3; + + public int avoidingIncomingPlayerUnitCooldown; + + //scout unit consists a sole light tank + public solidObject scout; + + public scoutingManagerAI(baseInfo theBaseInfo){ + this.theBaseInfo = theBaseInfo; + + patrolNodes = new float[][]{ + {16, 30}, {2, 29}, {15, 17}, {16, 14}, {27f, 1}, {30, 16}, {16, 14}, {15, 17} + }; + + exploringNodes = new float[][]{ + {9, 3.5f}, {2,2}, {14, 14} + }; + + destinationNode = 0; + + tempVector1 = new vector(0,0,0); + tempVector2 = new vector(0,1,0); + tempVector3 = new vector(0,0,0); + + } + + public void processAI(){ + + gameTime++; + + if(avoidingIncomingPlayerUnitCooldown > 0) + avoidingIncomingPlayerUnitCooldown--; + + if(gameTime%275 > 235 && gameTime%275 < 275 && gameTime < 600 && scoutingMode == patrolling){ + scoutingMode = exploring; + destinationNode = 0; + movementOrderIssued = false; + } + + //produce a scout unit if there is no scout unit on the map or the scout unit has been destroyed + + int numberOfLightTankOnQueue = 0; + for(int i = 0; i < mainThread.theAssetManager.factories.length; i++){ + if(mainThread.theAssetManager.factories[i] != null && mainThread.theAssetManager.factories[i].teamNo != 0){ + numberOfLightTankOnQueue += mainThread.theAssetManager.factories[i].numOfLightTankOnQueue; + } + } + if(numberOfLightTankOnQueue == 0 && needLightTank()){ + for(int i = 0; i < mainThread.theAssetManager.factories.length; i++){ + if(mainThread.theAssetManager.factories[i] != null && mainThread.theAssetManager.factories[i].teamNo != 0){ + if(mainThread.theAssetManager.factories[i].isIdle()){ + mainThread.theAssetManager.factories[i].buildLightTank(); + break; + } + } + } + } + + int numberOfStealthTankOnQueue = 0; + for(int i = 0; i < mainThread.theAssetManager.factories.length; i++){ + if(mainThread.theAssetManager.factories[i] != null && mainThread.theAssetManager.factories[i].teamNo != 0){ + numberOfStealthTankOnQueue += mainThread.theAssetManager.factories[i].numOfStealthTankOnQueue; + } + } + if(numberOfStealthTankOnQueue == 0 && needStealthTank()){ + for(int i = 0; i < mainThread.theAssetManager.factories.length; i++){ + if(mainThread.theAssetManager.factories[i] != null && mainThread.theAssetManager.factories[i].teamNo != 0){ + if(mainThread.theAssetManager.factories[i].isIdle()){ + mainThread.theAssetManager.factories[i].buildStealthTank(); + break; + } + } + } + } + + if(scout == null || scout.currentHP <=0){ + scout = null; + movementOrderIssued= false; + scoutingMode = patrolling; + destinationNode = (int)(Math.random()*patrolNodes.length); + } + + if(scout != null){ + + + + if(avoidingIncomingPlayerUnitCooldown == 0){ + + if(scoutingMode == patrolling){ + destinationNode = destinationNode%patrolNodes.length; + if(!scountReachedDestination(scout, patrolNodes, destinationNode)){ + + if(!movementOrderIssued){ + + scout.moveTo(patrolNodes[destinationNode][0], patrolNodes[destinationNode][1]); + scout.currentCommand = solidObject.move; + scout.secondaryCommand = solidObject.StandBy; + + if(scout.leftFactory) + movementOrderIssued = true; + + } + + }else{ + destinationNode++; + movementOrderIssued = false; + + } + } + + if(scoutingMode == exploring){ + + + if(!scountReachedDestination(scout, exploringNodes, destinationNode)){ + + if(!movementOrderIssued){ + + scout.moveTo(exploringNodes[destinationNode][0], exploringNodes[destinationNode][1]); + scout.currentCommand = solidObject.move; + scout.secondaryCommand = solidObject.StandBy; + + + if(scout.leftFactory) + movementOrderIssued = true; + } + + }else{ + destinationNode++; + movementOrderIssued = false; + } + + if(destinationNode >0 && destinationNode %exploringNodes.length == 0){ + scoutingMode = patrolling; + destinationNode = 0; + + } + } + + + if(scout.type == 0) + return; + + //try to avoid collision with player units + int xPos_old = scout.boundary2D.x1; + int yPos_old = scout.boundary2D.y1; + + int xPos = xPos_old; + int yPos = yPos_old; + + if(scout.movement.x != 0 || scout.movement.z != 0){ + tempVector1.set(scout.movement); + tempVector1.unit(); + tempVector1.scale(0.1f); + + for(int i = 1; i < 20; i ++){ + xPos = (int)((scout.centre.x + tempVector1.x*i)*64) - 8; + yPos = (int)((scout.centre.z + tempVector1.z*i)*64) + 8; + + scout.boundary2D.setOrigin(xPos, yPos); + + //increased size of the 2D boundary of the scount for better collision detection. + scout.boundary2D.expand(8); + + solidObject obstacle = checkForCollision(scout.boundary2D); + + scout.boundary2D.shrink(8); + + + //ignore harvesters + if(obstacle != null && obstacle.type == 2) + continue; + + + if(obstacle != null && !(i > 10 && ((obstacle.movement.x == 0 && obstacle.movement.z == 0) || (tempVector1.dot(obstacle.movement) > 0)))){ + + tempVector3.cross(tempVector1, tempVector2); + tempVector3.unit(); + tempVector3.scale(2); + + if(tempVector3.dot(obstacle.movement) > 0) + tempVector3.scale(-1); + + avoidingIncomingPlayerUnitCooldown = 2; + + scout.moveTo(scout.centre.x + tempVector3.x, scout.centre.z + tempVector3.z); + scout.currentCommand = solidObject.move; + scout.secondaryCommand = solidObject.StandBy; + movementOrderIssued = false; + break; + } + + } + } + scout.boundary2D.setOrigin(xPos_old, yPos_old); + } + + + + + } + + + } + + public solidObject checkForCollision(Rect myRect){ + + //check if the tank collide with the border + if(myRect.x1 < 0 || myRect.x2 > 2047 || myRect.y2 < 1 || myRect.y1 > 2048){ + return null; + } + + + int newOccupiedTile0= myRect.x1/16 + (127 - myRect.y1/16)*128; + int newOccupiedTile1 = newOccupiedTile0 + 1; + int newOccupiedTile2 = newOccupiedTile0 + 128; + int newOccupiedTile3 = newOccupiedTile0 + 129; + + solidObject tempObstacle = null; + solidObject[] tile; + + if(newOccupiedTile0 >= 0 && newOccupiedTile0 < 16384){ + tile = mainThread.gridMap.tiles[newOccupiedTile0]; + for(int i = 0; i < 5; i++){ + if(tile[i] != null){ + if(tile[i].boundary2D.intersect(myRect) && tile[i].teamNo == 0 && tile[i].type < 100 && !tile[i].isCloaked) + return tile[i]; + } + } + } + + if(newOccupiedTile1 >= 0 && newOccupiedTile1 < 16384){ + tile = mainThread.gridMap.tiles[newOccupiedTile1]; + for(int i = 0; i < 5; i++){ + if(tile[i] != null){ + if(tile[i].boundary2D.intersect(myRect) && tile[i].teamNo == 0 && tile[i].type < 100 && !tile[i].isCloaked) + return tile[i]; + } + } + } + + if(newOccupiedTile2 >= 0 && newOccupiedTile2 < 16384){ + tile = mainThread.gridMap.tiles[newOccupiedTile2]; + for(int i = 0; i < 5; i++){ + if(tile[i] != null){ + if(tile[i].boundary2D.intersect(myRect) && tile[i].teamNo == 0 && tile[i].type < 100 && !tile[i].isCloaked) + return tile[i]; + } + } + } + + if(newOccupiedTile3 >= 0 && newOccupiedTile3 < 16384){ + tile = mainThread.gridMap.tiles[newOccupiedTile3]; + for(int i = 0; i < 5; i++){ + if(tile[i] != null){ + if(tile[i].boundary2D.intersect(myRect) && tile[i].teamNo == 0 && tile[i].type < 100 && !tile[i].isCloaked) + return tile[i]; + } + } + } + + return tempObstacle; + } + + public boolean scountReachedDestination(solidObject o, float[][] nodes, int nodeIndex){ + float distanceToDestination = (float)Math.sqrt((o.centre.x - nodes[nodeIndex][0]) * (o.centre.x - nodes[nodeIndex][0]) + (o.centre.z - nodes[nodeIndex][1]) * (o.centre.z - nodes[nodeIndex][1])); + + + if(distanceToDestination <= 0.1f) + return true; + + if(distanceToDestination <= 1.5f && (o.currentMovementStatus == o.hugLeft || o.currentMovementStatus == o.hugRight)) + return true; + + return false; + } + + + //build light tank as scout when stealth tank tech is locked + public boolean needLightTank(){ + //if((scout == null ) && !theBaseInfo.canBuildStealthTank){ + // return true; + //} + + return false; + } + + public boolean needStealthTank(){ + if(theBaseInfo.canBuildStealthTank){ + if(scout == null || scout.currentHP <= 0 || scout.type != 6){ + return true; + } + } + return false; + } + + public void addLightTank(solidObject o){ + scout = o; + } + + public void addStealthTank(solidObject o){ + if(scout != null && scout.currentHP > 0 && scout.type == 0){ + mainThread.ec.theUnitProductionAI.addLightTank((lightTank)scout); + scout.moveTo(mainThread.ec.theUnitProductionAI.rallyPoint.x, mainThread.ec.theUnitProductionAI.rallyPoint.z); + scout.currentCommand = solidObject.attackMove; + scout.secondaryCommand = solidObject.attackMove; + } + + scout = o; + movementOrderIssued = false; + } +} diff --git a/enemyAI/unitProductionAI.java b/enemyAI/unitProductionAI.java new file mode 100644 index 0000000..b9e29e1 --- /dev/null +++ b/enemyAI/unitProductionAI.java @@ -0,0 +1,478 @@ +package enemyAI; + +import core.baseInfo; +import core.gameData; +import core.mainThread; +import core.vector; +import entity.*; + +//decide which unit to produce to counter player's force +//keep track of the units that are under control by combatAI. + +public class unitProductionAI { + + public baseInfo theBaseInfo; + + public lightTank[] lightTanksControlledByCombatAI; + public rocketTank[] rocketTanksControlledByCombatAI; + public stealthTank[] stealthTanksControlledByCombatAI; + public heavyTank[] heavyTanksControlledByCombatAI; + public solidObject[] troopsControlledByCombatAI; + + public float combatAICenterX; + public float combatAICenterZ; + + //public int currentState; + //public final int booming = 0; + //public final int aggressing = 1; + //public final int defending = 2; + + public int currentProductionOrder; + public final int produceLightTank = 0; + public final int produceRocketTank = 1; + public final int produceStealthTank = 2; + public final int produceHeavyTank = 3; + + public vector rallyPoint; + public int unitProduced; + public int numberOfCombatUnit; + public int numberOfUnitInCombatRadius; + public int numberOfUnitOutsideCombatRadius; + public int numberOfCombatUnitsUnderAttack; + + public int numberOfLightTanksControlledByCombatAI; + public int numberOfRocketTanksControlledByCombatAI; + public int numberOfStealthTanksControlledByCombatAI; + public int numberOfHeavyTanksControlledByCombatAI; + + public solidObject[] unitInCombatRadius; + public solidObject[] unitOutsideCombatRadius; + + public int frameAI; + + public unitProductionAI(baseInfo theBaseInfo){ + this.theBaseInfo = theBaseInfo; + rallyPoint = new vector(0,0,0); + + lightTanksControlledByCombatAI = new lightTank[192]; + rocketTanksControlledByCombatAI = new rocketTank[72]; + stealthTanksControlledByCombatAI = new stealthTank[96]; + heavyTanksControlledByCombatAI = new heavyTank[60]; + + troopsControlledByCombatAI = new solidObject[512]; + unitInCombatRadius = new solidObject[384]; + unitOutsideCombatRadius = new solidObject[128]; + + combatAICenterX = -1; + combatAICenterZ = -1; + + } + + + + public void processAI(){ + frameAI++; + + //set the rally point to near the construction yard which is closest to the player's starting position + float x = 0; + float z = 999999; + + int index = 0; + for(int i = 0; i < mainThread.theAssetManager.constructionYards.length; i++){ + if(mainThread.theAssetManager.constructionYards[i] != null && mainThread.theAssetManager.constructionYards[i].currentHP > 0 && mainThread.theAssetManager.constructionYards[i].teamNo != 0){ + index = i; + if(mainThread.theAssetManager.constructionYards[i].centre.z < z && mainThread.theAssetManager.constructionYards[i].centre.z > 5 && mainThread.theAssetManager.constructionYards[i].centre.x > 5){ + x = mainThread.theAssetManager.constructionYards[i].centre.x; + z = mainThread.theAssetManager.constructionYards[i].centre.z; + } + } + } + if(z != 999999) { + if(mainThread.ec.theCombatManagerAI.shouldDefenceAggressively) + rallyPoint.set(z - 2.5f, 0, z - 2.5f); + else + rallyPoint.set(x - 1.5f, 0, z - 1.5f); + }else { + if(mainThread.theAssetManager.constructionYards[index] != null) + rallyPoint.set(mainThread.theAssetManager.constructionYards[index].centre.x - 2.5f, 0, mainThread.theAssetManager.constructionYards[index].centre.z -2.5f); + } + + + + //make sure not to over produce when the resource is running low + int maxNumOfUnitCanBeProduced = theBaseInfo.currentCredit / 500 + 1; + + + for(int i = 0; i < mainThread.theAssetManager.factories.length; i++){ + factory f = mainThread.theAssetManager.factories[i]; + if(f != null && f.teamNo !=0){ + if(!f.isIdle()) + maxNumOfUnitCanBeProduced--; + } + } + + for(int i = 0; i < mainThread.theAssetManager.constructionYards.length; i++){ + constructionYard c = mainThread.theAssetManager.constructionYards[i]; + if(c != null && c.teamNo !=0){ + if(!c.isIdle()) + maxNumOfUnitCanBeProduced--; + } + } + + //make decision on what unit to produce + int numberOfLightTanks_AI = mainThread.ec.theMapAwarenessAI.numberOfLightTanks_AI; + int numberOfRocketTanks_AI = mainThread.ec.theMapAwarenessAI.numberOfRocketTanks_AI; + int numberOfStealthTanks_AI = mainThread.ec.theMapAwarenessAI.numberOfStealthTanks_AI; + int numberOfHeavyTanks_AI = mainThread.ec.theMapAwarenessAI.numberOfHeavyTanks_AI; + + int numberOfPlayerTurrets= mainThread.ec.theMapAwarenessAI.numberOfMissileTurret_player + mainThread.ec.theMapAwarenessAI.numberOfGunTurret_player; + int numberOfLightTanks_player = mainThread.ec.theMapAwarenessAI.numberOfLightTanks_player; + int numberOfRocketTanks_player = mainThread.ec.theMapAwarenessAI.numberOfRocketTanks_player; + int numberOfStealthTanks_player = mainThread.ec.theMapAwarenessAI.numberOfStealthTanks_player; + int numberOfHeavyTanks_player = mainThread.ec.theMapAwarenessAI.numberOfHeavyTanks_player; + int maxNumberOfStealthTanks_playerInLastFiveMinutes = mainThread.ec.theMapAwarenessAI.maxNumberOfStealthTanks_playerInLastFiveMinutes; + + boolean playerHasMostlyLightTanks = mainThread.ec.theMapAwarenessAI.playerHasMostlyLightTanks; + boolean playerHasMostlyHeavyTanks = mainThread.ec.theMapAwarenessAI.playerHasMostlyHeavyTanks; + boolean playIsRushingHighTierUnits = mainThread.ec.theMapAwarenessAI.playIsRushingHighTierUnits; + boolean playerLikelyCanNotProduceHighTierUnits = mainThread.ec.theMapAwarenessAI.playerLikelyCanNotProduceHighTierUnits; + boolean playerDoesntHaveMassHeavyTanks = mainThread.ec.theMapAwarenessAI.playerDoesntHaveMassHeavyTanks; + boolean playerHasManyLightTanksButNoHeavyTank = mainThread.ec.theMapAwarenessAI.playerHasManyLightTanksButNoHeavyTank; + + if(numberOfRocketTanks_AI < numberOfPlayerTurrets || (gameData.getRandom() > 925 && !playerHasMostlyLightTanks)){ + currentProductionOrder = produceRocketTank; + }else if(theBaseInfo.canBuildHeavyTank + && !playerHasManyLightTanksButNoHeavyTank + && !playerHasMostlyLightTanks + && !(numberOfHeavyTanks_player == 0 && maxNumberOfStealthTanks_playerInLastFiveMinutes < 3 && mainThread.frameIndex/30 > 600) + && !(playerHasMostlyHeavyTanks && numberOfStealthTanks_player < numberOfHeavyTanks_AI*2) + && (playIsRushingHighTierUnits || gameData.getRandom() > 985 || maxNumberOfStealthTanks_playerInLastFiveMinutes*4 > numberOfHeavyTanks_AI || (mainThread.frameIndex/30 > 400 && mainThread.frameIndex/30 < 600 && numberOfPlayerTurrets + numberOfLightTanks_player + numberOfRocketTanks_player + numberOfHeavyTanks_player*5 < 5))){ + currentProductionOrder = produceHeavyTank; + }else if(theBaseInfo.canBuildStealthTank && (playerHasMostlyLightTanks || playerLikelyCanNotProduceHighTierUnits || playerDoesntHaveMassHeavyTanks) && !playerHasMostlyHeavyTanks){ + currentProductionOrder = produceStealthTank; + }else{ + currentProductionOrder = produceLightTank; + } + + + + //make decision on what tech to research + if(mainThread.ec.theBuildingManagerAI.theBaseInfo.numberOfTechCenter > 0){ + + //Immediately start stealth tank upgrades when a tech center is built + if(!techCenter.stealthTankResearched_enemy){ + if(techCenter.stealthTankResearchProgress_enemy == 255){ + techCenter.cancelResearch(1); + techCenter.researchStealthTank(1); + System.out.println("----------------------------AI starts researching stealth tank------------------------------------"); + } + } + + + if(numberOfLightTanks_AI >= 15 && theBaseInfo.currentCredit > 1000){ + if(!techCenter.lightTankResearched_enemy){ + if(techCenter.lightTankResearchProgress_enemy >= 240 && techCenter.stealthTankResearchProgress_enemy >= 240 && techCenter.rocketTankResearchProgress_enemy >= 240 && techCenter.heavyTankResearchProgress_enemy >= 240){ + techCenter.researchLightTank(1); + System.out.println("----------------------------AI starts researching light tank------------------------------------"); + } + } + } + + + //System.out.println("enemy light tank count: " + numberOfLightTanks_player + " at " + mainThread.frameIndex/30); + if(currentProductionOrder == produceStealthTank) + System.out.println("should make stealth tank now"); + if(currentProductionOrder == produceHeavyTank){ + System.out.println("should make Heavy tank now-----------------"); + } + + + + if(numberOfRocketTanks_AI > 5 && theBaseInfo.currentCredit > 750){ + if(!techCenter.rocketTankResearched_enemy){ + if(techCenter.lightTankResearchProgress_enemy >= 240 && techCenter.stealthTankResearchProgress_enemy >= 240 && techCenter.rocketTankResearchProgress_enemy >= 240 && techCenter.heavyTankResearchProgress_enemy >= 240){ + + techCenter.researchRocketTank(1); + System.out.println("----------------------------AI starts researching rocket tank------------------------------------"); + } + } + } + + if(numberOfHeavyTanks_AI > 5 && theBaseInfo.currentCredit > 1000){ + if(!techCenter.heavyTankResearched_enemy){ + if(techCenter.lightTankResearchProgress_enemy >= 240 && techCenter.stealthTankResearchProgress_enemy >= 240 && techCenter.rocketTankResearchProgress_enemy >= 240 && techCenter.heavyTankResearchProgress_enemy >= 240){ + techCenter.researchHeavyTank(1); + System.out.println("----------------------------AI starts researching heavy tank------------------------------------"); + } + } + } + } + + + for(int i = 0; i < mainThread.theAssetManager.factories.length; i++){ + factory f = mainThread.theAssetManager.factories[i]; + if(f != null && f.teamNo !=0){ + f.moveTo(rallyPoint.x, rallyPoint.z); + if(f.isIdle()){ + if(theBaseInfo.canBuildLightTank && maxNumOfUnitCanBeProduced > 0){ + + if(currentProductionOrder == produceLightTank) + f.buildLightTank(); + else if(currentProductionOrder == produceRocketTank) + f.buildRocketTank(); + else if(currentProductionOrder == produceStealthTank) + f.buildStealthTank(); + else if(currentProductionOrder == produceHeavyTank) + f.buildHeavyTank(); + + maxNumOfUnitCanBeProduced--; + } + continue; + } + } + } + + + countTroopControlledByCombatAI(); + findCenterOfTroopControlledByCombatAI(); + + } + + public void addLightTank(lightTank o){ + //check if other AI agent need light tank + + if(mainThread.ec.theScoutingManagerAI.needLightTank()){ + mainThread.ec.theScoutingManagerAI.addLightTank(o); + + return; + } + + + //add the new light tank to combat AI's command + for(int i = 0; i < lightTanksControlledByCombatAI.length; i++){ + if(lightTanksControlledByCombatAI[i] == null || (lightTanksControlledByCombatAI[i] != null && lightTanksControlledByCombatAI[i].currentHP <=0)){ + lightTanksControlledByCombatAI[i] = o; + unitProduced++; + break; + } + } + + + } + + public void addRocketTank(rocketTank o){ + //check if other AI agent need rocket tank + + //add the new rocket tank to combat AI's command + for(int i = 0; i < rocketTanksControlledByCombatAI.length; i++){ + if(rocketTanksControlledByCombatAI[i] == null || (rocketTanksControlledByCombatAI[i] != null && rocketTanksControlledByCombatAI[i].currentHP <=0)){ + rocketTanksControlledByCombatAI[i] = o; + unitProduced++; + break; + } + } + } + + public void addStealthTank(stealthTank o){ + //check if other AI agent need stealth tank + + if(mainThread.ec.theScoutingManagerAI.needStealthTank()){ + mainThread.ec.theScoutingManagerAI.addStealthTank(o); + return; + } + + if(mainThread.ec.theBaseExpentionAI.needStealthTank()){ + mainThread.ec.theBaseExpentionAI.addStealthTank(o); + return; + } + + + + //add the new stealth tank to combat AI's command + for(int i = 0; i < stealthTanksControlledByCombatAI.length; i++){ + if(stealthTanksControlledByCombatAI[i] == null || (stealthTanksControlledByCombatAI[i] != null && stealthTanksControlledByCombatAI[i].currentHP <=0)){ + stealthTanksControlledByCombatAI[i] = o; + unitProduced++; + break; + } + } + } + + public void addHeavyTank(heavyTank o){ + //add the new heavy tank to combat AI's command + for(int i = 0; i < heavyTanksControlledByCombatAI.length; i++){ + if(heavyTanksControlledByCombatAI[i] == null || (heavyTanksControlledByCombatAI[i] != null && heavyTanksControlledByCombatAI[i].currentHP <=0)){ + heavyTanksControlledByCombatAI[i] = o; + unitProduced++; + break; + } + } + } + + + public void countTroopControlledByCombatAI(){ + numberOfCombatUnitsUnderAttack = 0; + + numberOfLightTanksControlledByCombatAI = 0; + numberOfRocketTanksControlledByCombatAI = 0; + numberOfStealthTanksControlledByCombatAI = 0; + numberOfHeavyTanksControlledByCombatAI = 0; + + for(int i = 0; i < troopsControlledByCombatAI.length; i++){ + troopsControlledByCombatAI[i] = null; + } + + numberOfCombatUnit = 0; + for(int i = 0; i < lightTanksControlledByCombatAI.length; i++){ + if(lightTanksControlledByCombatAI[i] != null && lightTanksControlledByCombatAI[i].currentHP > 0){ + troopsControlledByCombatAI[numberOfCombatUnit] = lightTanksControlledByCombatAI[i]; + if(troopsControlledByCombatAI[numberOfCombatUnit].underAttackCountDown > 0) + numberOfCombatUnitsUnderAttack++; + numberOfCombatUnit++; + numberOfLightTanksControlledByCombatAI++; + } + } + for(int i = 0; i < rocketTanksControlledByCombatAI.length; i++){ + if(rocketTanksControlledByCombatAI[i] != null && rocketTanksControlledByCombatAI[i].currentHP > 0){ + troopsControlledByCombatAI[numberOfCombatUnit] = rocketTanksControlledByCombatAI[i]; + if(troopsControlledByCombatAI[numberOfCombatUnit].underAttackCountDown > 0) + numberOfCombatUnitsUnderAttack++; + numberOfCombatUnit++; + numberOfRocketTanksControlledByCombatAI++; + } + } + for(int i = 0; i < stealthTanksControlledByCombatAI.length; i++){ + if(stealthTanksControlledByCombatAI[i] != null && stealthTanksControlledByCombatAI[i].currentHP > 0){ + troopsControlledByCombatAI[numberOfCombatUnit] = stealthTanksControlledByCombatAI[i]; + if(troopsControlledByCombatAI[numberOfCombatUnit].underAttackCountDown > 0) + numberOfCombatUnitsUnderAttack++; + numberOfCombatUnit++; + numberOfStealthTanksControlledByCombatAI++; + } + } + for(int i = 0; i < heavyTanksControlledByCombatAI.length; i++){ + if(heavyTanksControlledByCombatAI[i] != null && heavyTanksControlledByCombatAI[i].currentHP > 0){ + troopsControlledByCombatAI[numberOfCombatUnit] = heavyTanksControlledByCombatAI[i]; + if(troopsControlledByCombatAI[numberOfCombatUnit].underAttackCountDown > 0) + numberOfCombatUnitsUnderAttack++; + numberOfCombatUnit++; + numberOfHeavyTanksControlledByCombatAI++; + } + } + } + + public void findCenterOfTroopControlledByCombatAI(){ + float centerX = 0; + float centerZ = 0; + + vector centre; + double distance = 0; + + numberOfUnitInCombatRadius = 0; + numberOfUnitOutsideCombatRadius = 0; + + + //when there is no combat unit there is no point to calculate the center of the combat units + if(numberOfCombatUnit == 0){ + combatAICenterX = -1; + combatAICenterZ = -1; + return; + } + + for(int i = 0; i < unitInCombatRadius.length; i++){ + unitInCombatRadius[i] = null; + } + + for(int i = 0; i < unitOutsideCombatRadius.length; i++){ + unitOutsideCombatRadius[i] = null; + } + + + //calculate the center of the troops using the all the unites that are under the control of the combatAI + if(combatAICenterX == -1){ + combatAICenterX = 0; + combatAICenterZ = 0; + for(int i =0; i < numberOfCombatUnit; i++){ + centre = troopsControlledByCombatAI[i].centre; + combatAICenterX+=centre.x; + combatAICenterZ+=centre.z; + } + combatAICenterX /= numberOfCombatUnit; + combatAICenterZ /= numberOfCombatUnit; + } + + //exclude the units are too far away from the center of the troops, (i.e the unites that just come out of the factory), and recalculate the center + for(int i =0; i < numberOfCombatUnit; i++){ + centre = troopsControlledByCombatAI[i].centre; + distance = Math.sqrt((centre.x - combatAICenterX)*(centre.x - combatAICenterX) + (centre.z - combatAICenterZ)*(centre.z - combatAICenterZ)); + if(distance < 4.5){ + centerX += centre.x; + centerZ += centre.z; + if(numberOfUnitInCombatRadius < unitInCombatRadius.length) + unitInCombatRadius[numberOfUnitInCombatRadius] = troopsControlledByCombatAI[i]; + numberOfUnitInCombatRadius++; + }else{ + if(numberOfUnitOutsideCombatRadius < unitOutsideCombatRadius.length) + unitOutsideCombatRadius[numberOfUnitOutsideCombatRadius] = troopsControlledByCombatAI[i]; + numberOfUnitOutsideCombatRadius++; + } + } + + float unitInCombactRadiusPercentage = 1; + if(numberOfUnitInCombatRadius + numberOfUnitOutsideCombatRadius >0) + unitInCombactRadiusPercentage = (float)numberOfUnitInCombatRadius/(float)(numberOfUnitInCombatRadius + numberOfUnitOutsideCombatRadius); + + float unitInCombactRadiusPercentageThreshold = 0.7f; + if(numberOfCombatUnitsUnderAttack > 0) + unitInCombactRadiusPercentageThreshold = 0.25f; + + //System.out.println(unitInCombactRadiusPercentage + " :" + unitInCombactRadiusPercentageThreshold); + + + //need to recalculate the center if there is a significant amount of combat unites that are outside of the combat radius + if(unitInCombactRadiusPercentage < unitInCombactRadiusPercentageThreshold){ + + combatAICenterX = 0; + combatAICenterZ = 0; + for(int i =0; i < numberOfCombatUnit; i++){ + centre = troopsControlledByCombatAI[i].centre; + combatAICenterX+=centre.x; + combatAICenterZ+=centre.z; + } + combatAICenterX /= numberOfCombatUnit; + combatAICenterZ /= numberOfCombatUnit; + + for(int i = 0; i < unitInCombatRadius.length; i++){ + unitInCombatRadius[i] = null; + } + + for(int i = 0; i < unitOutsideCombatRadius.length; i++){ + unitOutsideCombatRadius[i] = null; + } + numberOfUnitInCombatRadius = 0; + numberOfUnitOutsideCombatRadius = 0; + centerX = 0; + centerZ = 0; + + for(int i =0; i < numberOfCombatUnit; i++){ + centre = troopsControlledByCombatAI[i].centre; + distance = Math.sqrt((centre.x - combatAICenterX)*(centre.x - combatAICenterX) + (centre.z - combatAICenterZ)*(centre.z - combatAICenterZ)); + if(distance < 10){ + centerX += centre.x; + centerZ += centre.z; + if(numberOfUnitInCombatRadius < unitInCombatRadius.length) + unitInCombatRadius[numberOfUnitInCombatRadius] = troopsControlledByCombatAI[i]; + numberOfUnitInCombatRadius++; + }else{ + if(numberOfUnitOutsideCombatRadius < unitOutsideCombatRadius.length) + unitOutsideCombatRadius[numberOfUnitOutsideCombatRadius] = troopsControlledByCombatAI[i]; + numberOfUnitOutsideCombatRadius++; + } + } + } + + combatAICenterX = centerX/numberOfUnitInCombatRadius; + combatAICenterZ = centerZ/numberOfUnitInCombatRadius; + + } +} diff --git a/entity/.gitignore b/entity/.gitignore new file mode 100644 index 0000000..149d688 --- /dev/null +++ b/entity/.gitignore @@ -0,0 +1,20 @@ +/communicationCenter.class +/constructionVehicle.class +/constructionYard.class +/drone.class +/factory.class +/goldMine.class +/gunTurret.class +/harvester.class +/heavyTank.class +/lightPole.class +/lightTank.class +/missileTurret.class +/palmTree.class +/powerPlant.class +/refinery.class +/rocketTank.class +/solidObject.class +/stealthTank.class +/techCenter.class +/tokenObject.class diff --git a/entity/communicationCenter.java b/entity/communicationCenter.java new file mode 100644 index 0000000..a3a4bea --- /dev/null +++ b/entity/communicationCenter.java @@ -0,0 +1,1278 @@ +package entity; + +import java.awt.Rectangle; + +import core.*; +import enemyAI.enemyCommander; + +//the communication center model + +public class communicationCenter extends solidObject{ + + //the polygons of the model + private polygon3D[] polygons; + + public static int maxHP = 550; + + public int countDownToDeath = 16; + + public vector tempVector = new vector(0,0,0); + public vector tempVector0 = new vector(0,0,0); + public vector tempVector1 = new vector(0,0,0); + public vector tempVector2 = new vector(0,0,0); + public vector tempVector3 = new vector(0,0,0); + public vector tempVector4 = new vector(0,0,0); + + public vector radarDiskCorner0, radarDiskCorner1, radarDiskCorner2, radarDiskCorner3; + + public int [] tileIndex = new int[9]; + public int[] tempInt; + + public float[] tempFloat; + + public vector shadowvertex0, tempshadowvertex0,shadowvertex1, tempshadowvertex1,shadowvertex2, tempshadowvertex2,shadowvertex3, tempshadowvertex3; + + //a screen space boundary which is used to test if the object is visible from camera point of view + public final static Rectangle visibleBoundary = new Rectangle(-85,-85,960, 762); + + //a screen space boundary which is used to test if the entire object is within the screen + public final static Rectangle screenBoundary = new Rectangle(60,60,648, 402); + + //screen space boundary which is used to test if the shadow of the object is within the screen + public final static Rectangle shadowBoundary1 = new Rectangle(0,0,768, 512); + + //a bitmap representation of the vision of the power plant for enemy commander + public static boolean[] bitmapVisionForEnemy; + + //Communication center never moves + public final static vector movenment = new vector(0,0,0); + + public int numOfPolygons; + + public static int rotationPartIndexStart, rotationPartIndexEnd, radarDiskIndexStart, radarDiskIndexEnd; + + //index of the tiles to scan for cloaked unitsl + public static int[] tileCheckList; + + public baseInfo theBaseInfo; + + public static boolean harvesterSpeedResearched_player, harvesterSpeedResearched_enemy; + public static boolean rapidfireResearched_player, rapidfireResearched_enemy; + public static int harvesterSpeedResearchProgress_player = 255, harvesterSpeedResearchProgress_enemy = 255; + public static int rapidfireResearchProgress_player = 255, rapidfireResearchProgress_enemy = 255; + public static int creditSpentOnResearching_player, creditSpentOnResearching_enemy; + + public static int intendedDeployLocation = -1; + + public communicationCenter(float x, float y, float z, int teamNo){ + //uncontrollable unit, but act as a big sized static collidable agent + type = 106; + + ID = globalUniqID++; + + + if(teamNo == 0){ + isRevealed = true; + theBaseInfo = mainThread.pc.theBaseInfo; + }else{ + theBaseInfo = mainThread.ec.theBaseInfo; + } + + theBaseInfo.numberOfCommunicationCenter++; + + currentHP = 550; + + this.teamNo = teamNo; + + currentCommand = StandBy; + + if(teamNo == 0){ + isRevealed = true; + } + + if(bitmapVisionForEnemy == null){ + bitmapVisionForEnemy = createBitmapVision(12); + } + + //create 2D boundary + boundary2D = new Rect((int)(x*64) - 16, (int)(z*64) + 16, 32, 32); + boundary2D.owner = this; + int centerX = (int)(x*64); + int centerY = (int)(z*64); + + tileIndex[0] = (centerX - 8)/16 + (127 - (centerY + 8)/16)*128; + tileIndex[1] = (centerX + 8)/16 + (127 - (centerY + 8)/16)*128; + tileIndex[2] = (centerX + 8)/16 + (127 - (centerY - 8)/16)*128; + tileIndex[3] = (centerX - 8)/16 + (127 - (centerY - 8)/16)*128; + + mainThread.gridMap.tiles[tileIndex[0]][0] = this; + mainThread.gridMap.tiles[tileIndex[1]][0] = this; + mainThread.gridMap.tiles[tileIndex[2]][0] = this; + mainThread.gridMap.tiles[tileIndex[3]][0] = this; + + mainThread.gridMap.tiles[tileIndex[0]][1] = this; + mainThread.gridMap.tiles[tileIndex[1]][1] = this; + mainThread.gridMap.tiles[tileIndex[2]][1] = this; + mainThread.gridMap.tiles[tileIndex[3]][1] = this; + + mainThread.gridMap.tiles[tileIndex[0]][2] = this; + mainThread.gridMap.tiles[tileIndex[1]][2] = this; + mainThread.gridMap.tiles[tileIndex[2]][2] = this; + mainThread.gridMap.tiles[tileIndex[3]][2] = this; + + mainThread.gridMap.tiles[tileIndex[0]][3] = this; + mainThread.gridMap.tiles[tileIndex[1]][3] = this; + mainThread.gridMap.tiles[tileIndex[2]][3] = this; + mainThread.gridMap.tiles[tileIndex[3]][3] = this; + + mainThread.gridMap.tiles[tileIndex[0]][4] = this; + mainThread.gridMap.tiles[tileIndex[1]][4] = this; + mainThread.gridMap.tiles[tileIndex[2]][4] = this; + mainThread.gridMap.tiles[tileIndex[3]][4] = this; + + if(teamNo != 0){ + tileIndex[4] = tileIndex[1] - 128; + tileIndex[5] = tileIndex[1] - 130; + tileIndex[6] = tileIndex[1] + 256; + tileIndex[7] = tileIndex[1] + 254; + tileIndex[8] = tileIndex[1] + 126; + + mainThread.gridMap.tiles[tileIndex[4]][4] = this; + mainThread.gridMap.tiles[tileIndex[5]][4] = this; + mainThread.gridMap.tiles[tileIndex[6]][4] = this; + mainThread.gridMap.tiles[tileIndex[7]][4] = this; + mainThread.gridMap.tiles[tileIndex[8]][4] = this; + } + + //init model + start = new vector(x,y,z); + iDirection = new vector(1f,0,0); + jDirection = new vector(0,1f,0); + kDirection = new vector(0,0,1f); + + + //define centre of the model in world coordinate + start = new vector(x,y,z); + centre = start.myClone(); + tempCentre = start.myClone(); + + shadowvertex0 =start.myClone(); + shadowvertex0.add(-0.5f,-0.2f, -0.5f); + tempshadowvertex0 = new vector(0,0,0); + + shadowvertex1 =start.myClone(); + shadowvertex1.add(-0.5f,-0.2f, 0.2f); + tempshadowvertex1 = new vector(0,0,0); + + shadowvertex2 =start.myClone(); + shadowvertex2.add(0.2f,-0.2f, -0.5f); + tempshadowvertex2 = new vector(0,0,0); + + shadowvertex3 =start.myClone(); + shadowvertex3.add(0.2f,-0.2f, 0.2f); + tempshadowvertex3 = new vector(0,0,0); + + + makePolygons(); + + if(tileCheckList == null){ + tileCheckList = generateTileCheckList(12f); + } + + } + + public void makePolygons(){ + polygons = new polygon3D[600]; + vector[] v; + vector[] v2; + vector[] v3; + int polygonIndex; + + int beamTexture = 44; + if(teamNo == 1) + beamTexture = 53; + + float delta = (float)Math.PI/6; + float r1 = 0.25f; + float r2 = 0.22f; + float r3 = 0.09f; + float r4 = 0.095f; + float r5 = 0.085f; + float r6 = 0.23f; + + + tempVector.set(0,0,0.005f); + tempVector4.set(-0.01f,0,0); + + tempVector.rotate_XZ(15); + tempVector4.rotate_XZ(15); + + for(int i = 0; i < 12; i++){ + v = new vector[]{put(r2*Math.cos(i*delta), -0.04, r2*Math.sin(i*delta)), + put(r2*Math.cos((i+1)*delta), -0.04, r2*Math.sin((i+1)*delta)), + put(r1*Math.cos((i+1)*delta), -0.2, r1*Math.sin((i+1)*delta)), + put(r1*Math.cos(i*delta), -0.2, r1*Math.sin(i*delta)) + }; + + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[13], 1f,1f,1)); + + + polygons[polygonIndex].shadowBias = 20000; + + + v = new vector[]{put(r3*Math.cos(i*delta), 0.02, r3*Math.sin(i*delta)), + put(r3*Math.cos((i+1)*delta), 0.02, r3*Math.sin((i+1)*delta)), + put(r2*Math.cos((i+1)*delta), -0.04, r2*Math.sin((i+1)*delta)), + put(r2*Math.cos(i*delta), -0.04, r2*Math.sin(i*delta)) + }; + + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[14], 1f,1f,1)); + + polygons[polygonIndex].shadowBias = 10000; + + v = new vector[]{ + put(r5*Math.cos(i*delta), 0.03, r5*Math.sin(i*delta)), + put(r5*Math.cos((i+1)*delta), 0.03, r5*Math.sin((i+1)*delta)), + put(r4*Math.cos((i+1)*delta), 0.03, r4*Math.sin((i+1)*delta)), + put(r4*Math.cos(i*delta), 0.03, r4*Math.sin(i*delta)) + + }; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 5f,5f,1)); + + v = new vector[]{ + put(r4*Math.cos(i*delta), 0.03, r4*Math.sin(i*delta)), + put(r4*Math.cos((i+1)*delta), 0.03, r4*Math.sin((i+1)*delta)), + put(r4*Math.cos((i+1)*delta), 0.01, r4*Math.sin((i+1)*delta)), + put(r4*Math.cos(i*delta), 0.01, r4*Math.sin(i*delta)), + }; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 5f,5f,1)); + + + v = new vector[]{ + + put(r5*Math.cos((i+1)*delta), 0.03, r5*Math.sin((i+1)*delta)), + put(r5*Math.cos(i*delta), 0.03, r5*Math.sin(i*delta)), + put(r5*Math.cos(i*delta), 0.02, r5*Math.sin(i*delta)), + put(r5*Math.cos((i+1)*delta), 0.02, r5*Math.sin((i+1)*delta)), + }; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 5f,5f,1)); + + + change((float)(r3*Math.cos(i*delta)), 0.03f, (float)(r3*Math.sin(i*delta)), tempVector0); + tempVector0.subtract(tempVector); + change((float)(r3*Math.cos(i*delta)), 0.03f, (float)(r3*Math.sin(i*delta)), tempVector1); + tempVector1.add(tempVector); + change((float)(r6*Math.cos(i*delta)), -0.03f, (float)(r6*Math.sin(i*delta)), tempVector2); + tempVector2.add(tempVector); + change((float)(r6*Math.cos(i*delta)), -0.03f, (float)(r6*Math.sin(i*delta)), tempVector3); + tempVector3.subtract(tempVector); + + v = new vector[]{tempVector0.myClone(), tempVector1.myClone(), tempVector2.myClone(), tempVector3.myClone()}; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 5f,5f,1)); + + v = new vector[4]; + v[0] = tempVector2.myClone(); + v[1] = tempVector1.myClone(); + v[2] = tempVector1.myClone(); + v[2].y-=0.01f; + v[3] = tempVector2.myClone(); + v[3].y-=0.01f; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 5f,5f,1)); + + v = new vector[4]; + v[0] = tempVector0.myClone(); + v[1] = tempVector3.myClone(); + v[2] = tempVector3.myClone(); + v[2].y-=0.01f; + v[3] = tempVector0.myClone(); + v[3].y-=0.01f; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 5f,5f,1)); + + v = new vector[4]; + v[0] = tempVector2.myClone(); + v[1] = tempVector2.myClone(); + v[1].add(tempVector4,2); + v[3] = tempVector2.myClone(); + v[3].y-=0.17f; + v[3].add(tempVector4, -3); + v[2]=v[3].myClone(); + v[2].add(tempVector4,2); + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 5f,5f,1)); + + v2 = new vector[4]; + v2[0] = v[3].myClone(); + v2[1] = v[2].myClone(); + v2[2] = v[1].myClone(); + v2[3] = v[0].myClone(); + v2[0].add(tempVector, -2); + v2[1].add(tempVector, -2); + v2[2].add(tempVector, -2); + v2[3].add(tempVector, -2); + polygonIndex = addPolygon(polygons, new polygon3D(v2, v2[0], v2[1], v2[3], mainThread.textures[beamTexture], 5f,5f,1)); + + v3 = new vector[4]; + v3[0] = v2[3].myClone(); + v3[1] = v[0].myClone(); + v3[2] = v[3].myClone(); + v3[3] = v2[0].myClone(); + polygonIndex = addPolygon(polygons, new polygon3D(v3, v3[0], v3[1], v3[3], mainThread.textures[beamTexture], 5f,5f,1)); + + tempVector.rotate_XZ(30); + tempVector4.rotate_XZ(30); + + } + + + + v = new vector[12]; + for(int i = 0; i < 12; i++){ + v[11 - i] = put(r3*Math.cos(i*delta), 0.02, r3*Math.sin(i*delta)); + } + + start.x-=0.005; + + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 10f,10f,1)); + polygons[polygonIndex].diffuse_I+=10; + + //radar disk support structure + rotationPartIndexStart = polygonIndex+1; + v = new vector[]{put(-0.045,0.1, -0.03), put(-0.02,0.1, -0.03), put(-0.02,0.02, -0.05), put(-0.045,0.02, -0.05)}; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 1f,2f,1)); + + v = new vector[]{put(-0.045,0.02, 0.05), put(-0.02,0.02, 0.05), put(-0.02,0.1, 0.03), put(-0.045,0.1, 0.03)}; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 1f,2f,1)); + + v = new vector[]{put(-0.045, 0.1, 0.03), put(-0.045,0.1, -0.03), put(-0.045,0.02, -0.05), put(-0.045,0.02, 0.05)}; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 1f,2f,1)); + + v = new vector[]{put(-0.02,0.02, 0.05), put(-0.02,0.02, -0.05), put(-0.02,0.1, -0.03), put(-0.02, 0.1, 0.03)}; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 1f,2f,1)); + + + float r = 0.03f; + delta = (float)Math.PI/16; + for(int i = 0; i < 16; i++){ + v = new vector[]{ + put(-0.02, r*Math.cos((i+25)*delta)+0.1,r*Math.sin((i+25)*delta)), + put(-0.02, r*Math.cos((i+24)*delta)+0.1, r*Math.sin((i+24)*delta)), + put(-0.045, r*Math.cos((i+24)*delta)+0.1, r*Math.sin((i+24)*delta)), + put(-0.045, r*Math.cos((i+25)*delta)+0.1, r*Math.sin((i+25)*delta)), + }; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 1f,2f,1)); + } + + v = new vector[17]; + for(int i = 0; i < 17; i++){ + v[16-i] = put(-0.045, r*Math.cos((i+24)*delta)+0.1, r*Math.sin((i+24)*delta)); + } + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 1f,2f,1)); + + v = new vector[17]; + for(int i = 0; i < 17; i++){ + v[i] = put(-0.02, r*Math.cos((i+24)*delta)+0.1, r*Math.sin((i+24)*delta)); + } + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 1f,2f,1)); + + start.x+=0.075; + + + v = new vector[]{put(-0.045,0.1, -0.03), put(-0.02,0.1, -0.03), put(-0.02,0.02, -0.05), put(-0.045,0.02, -0.05)}; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 1f,2f,1)); + + v = new vector[]{put(-0.045,0.02, 0.05), put(-0.02,0.02, 0.05), put(-0.02,0.1, 0.03), put(-0.045,0.1, 0.03)}; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 1f,2f,1)); + + v = new vector[]{put(-0.045, 0.1, 0.03), put(-0.045,0.1, -0.03), put(-0.045,0.02, -0.05), put(-0.045,0.02, 0.05)}; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 1f,2f,1)); + + v = new vector[]{put(-0.02,0.02, 0.05), put(-0.02,0.02, -0.05), put(-0.02,0.1, -0.03), put(-0.02, 0.1, 0.03)}; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 1f,2f,1)); + + for(int i = 0; i < 16; i++){ + v = new vector[]{ + put(-0.02, r*Math.cos((i+25)*delta)+0.1,r*Math.sin((i+25)*delta)), + put(-0.02, r*Math.cos((i+24)*delta)+0.1, r*Math.sin((i+24)*delta)), + put(-0.045, r*Math.cos((i+24)*delta)+0.1, r*Math.sin((i+24)*delta)), + put(-0.045, r*Math.cos((i+25)*delta)+0.1, r*Math.sin((i+25)*delta)), + }; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 1f,2f,1)); + } + + v = new vector[17]; + for(int i = 0; i < 17; i++){ + v[16-i] = put(-0.045, r*Math.cos((i+24)*delta)+0.1, r*Math.sin((i+24)*delta)); + } + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 1f,2f,1)); + + v = new vector[17]; + for(int i = 0; i < 17; i++){ + v[i] = put(-0.02, r*Math.cos((i+24)*delta)+0.1, r*Math.sin((i+24)*delta)); + } + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 1f,2f,1)); + + start.x-=0.07; + + v = new vector[]{put(-0.025,0.06, -0.04), put(0.025,0.06, -0.04), put(0.025,0.02, -0.05),put(-0.025,0.02, -0.05)}; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 2f,1f,1)); + + v = new vector[]{put(-0.025,0.02, 0.05), put(0.025,0.02, 0.05), put(0.025,0.06, 0.04),put(-0.025,0.06, 0.04)}; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 2f,1f,1)); + + v = new vector[]{put(0.025,0.06, -0.05), put(-0.025,0.06, -0.05), put(-0.025,0.06, 0.05), put(0.025,0.06, 0.05)}; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[beamTexture], 2f,1f,1)); + + + start.z-=0.03; + + v = new vector[]{put(-0.025, 0.27, -0.02), put(0.025, 0.27, -0.02), put(0.025, 0.08, -0.02), put(-0.025, 0.08, -0.02) }; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1f,1f,1)); + polygons[polygonIndex].shadowBias = 15000; + + v = new vector[]{put(-0.025, 0.08, 0.02), put(0.025, 0.08, 0.02), put(0.025, 0.27, 0.02), put(-0.025, 0.27, 0.02)}; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1f,1f,1)); + polygons[polygonIndex].shadowBias = 15000; + + v = new vector[]{put(0.025, 0.27, -0.02), put(0.025, 0.27, 0.02), put(0.025, 0.08, 0.02), put(0.025, 0.08, -0.02)}; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1f,1f,1)); + polygons[polygonIndex].shadowBias = 15000; + + v = new vector[]{put(-0.025, 0.08, -0.02), put(-0.025, 0.08, 0.02), put(-0.025, 0.27, 0.02), put(-0.025, 0.27, -0.02)}; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1f,1f,1)); + polygons[polygonIndex].shadowBias = 15000; + + r = 0.02f; + + for(int i = 0; i < 16; i++){ + v = new vector[]{ + put(0.025, r*Math.cos((i+25)*delta)+0.27,r*Math.sin((i+25)*delta)), + put(0.025, r*Math.cos((i+24)*delta)+0.27, r*Math.sin((i+24)*delta)), + put(-0.025, r*Math.cos((i+24)*delta)+0.27, r*Math.sin((i+24)*delta)), + put(-0.025, r*Math.cos((i+25)*delta)+0.27, r*Math.sin((i+25)*delta)), + }; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1f,2f,1)); + polygons[polygonIndex].shadowBias = 15000; + } + + v = new vector[17]; + for(int i = 0; i < 17; i++){ + v[16-i] = put(-0.025, r*Math.cos((i+24)*delta)+0.27, r*Math.sin((i+24)*delta)); + } + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1f,2f,1)); + + v = new vector[17]; + for(int i = 0; i < 17; i++){ + v[i] = put(0.025, r*Math.cos((i+24)*delta)+0.27, r*Math.sin((i+24)*delta)); + } + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1f,2f,1)); + + //radar antenna + start.z-=0.27f; + start.y+=0.25f; + delta = (float)Math.PI/8; + r = 0.015f; + + for(int i = 0; i < 16; i++){ + v = new vector[]{ + put(r*Math.sin(i*delta), r*Math.cos(i*delta), -0.005f), + put(r*Math.sin(i*delta), r*Math.cos(i*delta), 0.03f), + put(r*Math.sin((i+1)*delta), r*Math.cos((i+1)*delta), 0.03f), + put(r*Math.sin((i+1)*delta), r*Math.cos((i+1)*delta), -0.005f), + }; + + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 10f,10f,1)); + } + + v = new vector[16]; + for(int i = 0; i < 16; i++){ + v[i] = put(r*Math.sin(i*delta), r*Math.cos(i*delta), -0.005f); + } + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 10f,10f,1)); + + r = 0.004f; + int angle1 = 50; + int angle2 = 310; + + + float length = 0.24f; + + iDirection.rotate_XZ(angle1); + jDirection.rotate_XZ(angle1); + kDirection.rotate_XZ(angle1); + + for(int i = 0; i < 16; i++){ + v = new vector[]{ + put(r*Math.sin(i*delta), r*Math.cos(i*delta), 0f), + put(r*Math.sin(i*delta), r*Math.cos(i*delta), length), + put(r*Math.sin((i+1)*delta), r*Math.cos((i+1)*delta), length), + put(r*Math.sin((i+1)*delta), r*Math.cos((i+1)*delta), 0f), + }; + + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 10f,10f,1)); + } + + iDirection.rotate_XZ(angle2); + jDirection.rotate_XZ(angle2); + kDirection.rotate_XZ(angle2); + + + iDirection.rotate_XZ(angle2); + jDirection.rotate_XZ(angle2); + kDirection.rotate_XZ(angle2); + + for(int i = 0; i < 16; i++){ + v = new vector[]{ + put(r*Math.sin(i*delta), r*Math.cos(i*delta), 0f), + put(r*Math.sin(i*delta), r*Math.cos(i*delta), length), + put(r*Math.sin((i+1)*delta), r*Math.cos((i+1)*delta), length), + put(r*Math.sin((i+1)*delta), r*Math.cos((i+1)*delta), 0f), + }; + + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 10f,10f,1)); + } + + iDirection.rotate_XZ(angle1); + jDirection.rotate_XZ(angle1); + kDirection.rotate_XZ(angle1); + + iDirection.rotate_YZ(angle2); + jDirection.rotate_YZ(angle2); + kDirection.rotate_YZ(angle2); + + for(int i = 0; i < 16; i++){ + v = new vector[]{ + put(r*Math.sin(i*delta), r*Math.cos(i*delta), 0f), + put(r*Math.sin(i*delta), r*Math.cos(i*delta),length), + put(r*Math.sin((i+1)*delta), r*Math.cos((i+1)*delta), length), + put(r*Math.sin((i+1)*delta), r*Math.cos((i+1)*delta), 0f), + }; + + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 10f,10f,1)); + } + + iDirection.rotate_YZ(angle1); + jDirection.rotate_YZ(angle1); + kDirection.rotate_YZ(angle1); + + iDirection.rotate_YZ(angle1); + jDirection.rotate_YZ(angle1); + kDirection.rotate_YZ(angle1); + + for(int i = 0; i < 16; i++){ + v = new vector[]{ + put(r*Math.sin(i*delta), r*Math.cos(i*delta), 0f), + put(r*Math.sin(i*delta), r*Math.cos(i*delta), length), + put(r*Math.sin((i+1)*delta), r*Math.cos((i+1)*delta), length), + put(r*Math.sin((i+1)*delta), r*Math.cos((i+1)*delta), 0f), + }; + + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 10f,10f,1)); + } + + iDirection.rotate_YZ(angle2); + jDirection.rotate_YZ(angle2); + kDirection.rotate_YZ(angle2); + + + start.z+=0.27f; + start.y-=0.25f; + + rotationPartIndexEnd=polygonIndex; + + //radar disk front + + radarDiskIndexStart = polygonIndex+1; + delta = (float)Math.PI/12; + r = 0f; + float h = 0.25f; + float l = -0.03f; + float dl = 0; + + //init radar disk corners + radarDiskCorner0 = start.myClone(); + radarDiskCorner0.y+=(h + 0.038f*5); + radarDiskCorner0.x-=(0.038f*5); + + + radarDiskCorner1 = start.myClone(); + radarDiskCorner1.y+=(h + 0.038f*5); + radarDiskCorner1.x+=(0.038f*5); + + + radarDiskCorner3 = start.myClone(); + radarDiskCorner3.y+=(h - 0.038f*5); + radarDiskCorner3.x-=(0.038f*5); + + + + for(int j = 0; j < 5; j++){ + for(int i = 0; i < 24; i++){ + //most inner circle + dl = (float)Math.sin(delta*(j+1))/36; + if(j==0){ + v = new vector[]{ + put(0, 0 + h, l), + put(0.038*Math.sin(i*delta), 0.038*Math.cos(i*delta) + h, l - dl), + put(0.038*Math.sin((i+1)*delta), 0.038*Math.cos((i+1)*delta) + h, l-dl), + }; + polygonIndex = createRadarDiskPolygon(v, mainThread.textures[65], 1f,1f,1); + polygons[polygonIndex].Ambient_I+=5; + polygons[polygonIndex].reflectance -=45; + polygons[polygonIndex].findDiffuse(); + + }else{ + v = new vector[]{ + put(r*Math.sin(i*delta), r*Math.cos(i*delta) + h, l), + put((r+0.038)*Math.sin(i*delta), (r+0.038)*Math.cos(i*delta) + h, l-dl), + put((r+0.038)*Math.sin((i+1)*delta), (r+0.038)*Math.cos((i+1)*delta) + h, l-dl), + put(r*Math.sin((i+1)*delta), r*Math.cos((i+1)*delta) + h, l), + }; + polygonIndex = createRadarDiskPolygon(v, mainThread.textures[65], 1f,1f,1); + polygons[polygonIndex].Ambient_I+=5; + polygons[polygonIndex].reflectance -=45; + polygons[polygonIndex].findDiffuse(); + + if(j == 4 && (i%6 == 0 || i%6 ==1 || i%6 ==5)) + polygons[polygonIndex].shadowBias = 15000; + else + polygons[polygonIndex].shadowBias = 30000; + } + + } + r+=0.038f; + l-=dl; + } + + //radar disk back + r = 0f; + h = 0.25f; + l = -0.02f; + dl = 0; + + for(int j = 0; j < 5; j++){ + for(int i = 0; i < 24; i++){ + //most inner circle + dl = (float)Math.sin(delta*(j+1))/36; + if(j==0){ + v = new vector[]{ + put(0.038*Math.sin((i+1)*delta), 0.038*Math.cos((i+1)*delta) + h, l-dl), + put(0.038*Math.sin(i*delta), 0.038*Math.cos(i*delta) + h, l - dl), + put(0, 0 + h, l), + + + }; + + polygonIndex = createRadarDiskPolygon(v, mainThread.textures[65], 1f,1f,1); + polygons[polygonIndex].Ambient_I+=5; + polygons[polygonIndex].reflectance -=45; + polygons[polygonIndex].findDiffuse(); + + + }else{ + v = new vector[]{ + put(r*Math.sin((i+1)*delta), r*Math.cos((i+1)*delta) + h, l), + put((r+0.038)*Math.sin((i+1)*delta), (r+0.038)*Math.cos((i+1)*delta) + h, l-dl), + put((r+0.038)*Math.sin(i*delta), (r+0.038)*Math.cos(i*delta) + h, l-dl), + put(r*Math.sin(i*delta), r*Math.cos(i*delta) + h, l), + + + + }; + polygonIndex = createRadarDiskPolygon(v, mainThread.textures[65], 1f,1f,1); + polygons[polygonIndex].Ambient_I+=5; + polygons[polygonIndex].reflectance -=45; + polygons[polygonIndex].findDiffuse(); + polygons[polygonIndex].shadowBias = 70000; + } + + } + r+=0.038f; + l-=dl; + } + + //radar disk side + for(int i = 0; i < 24; i++){ + v = new vector[]{ + put(r*Math.sin((i+1)*delta), r*Math.cos((i+1)*delta) + h, l), + put((r)*Math.sin((i+1)*delta), (r)*Math.cos((i+1)*delta) + h, l-0.01f), + put((r)*Math.sin(i*delta), (r)*Math.cos(i*delta) + h, l-0.01f), + put(r*Math.sin(i*delta), r*Math.cos(i*delta) + h, l), + + + }; + polygonIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 1f,2f,1)); + polygons[polygonIndex].Ambient_I+=20; + polygons[polygonIndex].reflectance = 64; + polygons[polygonIndex].findDiffuse(); + } + + start.z+=0.03; + + radarDiskIndexEnd = polygonIndex; + + for(int i = 180; i <= rotationPartIndexEnd; i++){ + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + polygons[i].vertex3D[j].subtract(start); + polygons[i].vertex3D[j].rotate_YZ(30); + polygons[i].vertex3D[j].add(start); + polygons[i].findNormal(); + polygons[i].findDiffuse(); + } + } + + for(int i = radarDiskIndexStart; i <= radarDiskIndexEnd; i++){ + polygons[i].origin.subtract(start); + polygons[i].origin.rotate_YZ(30); + polygons[i].origin.add(start); + + polygons[i].rightEnd.subtract(start); + polygons[i].rightEnd.rotate_YZ(30); + polygons[i].rightEnd.add(start); + + polygons[i].bottomEnd.subtract(start); + polygons[i].bottomEnd.rotate_YZ(30); + polygons[i].bottomEnd.add(start); + + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + polygons[i].vertex3D[j].subtract(start); + polygons[i].vertex3D[j].rotate_YZ(30); + polygons[i].vertex3D[j].add(start); + polygons[i].findNormal(); + polygons[i].findDiffuse(); + } + } + + } + + + public int createRadarDiskPolygon(vector[] v, texture theTexture, float scaleX, float scaleY, int type){ + polygon3D poly = null; + + //find a linear combination of the basis vectors in texture space + tempVector0.set(v[0]); + tempVector0.subtract(v[1]); + tempVector0.z = 0; + tempVector0.unit(); + + tempVector1.set(v[2]); + tempVector1.subtract(v[1]); + tempVector1.z = 0; + tempVector1.unit(); + + tempVector2.cross(tempVector0, tempVector1); + tempVector3.cross(tempVector2, tempVector0); + + geometry.solveLinerEquation2D(tempVector0.x, tempVector0.y, tempVector3.x, tempVector3.y, radarDiskCorner0.x - v[1].x , radarDiskCorner0.y - v[1].y); + float X0 = geometry.X; + float Y0 = geometry.Y; + + geometry.solveLinerEquation2D(tempVector0.x, tempVector0.y, tempVector3.x, tempVector3.y, radarDiskCorner1.x - v[1].x , radarDiskCorner1.y - v[1].y); + float X1 = geometry.X; + float Y1 = geometry.Y; + + geometry.solveLinerEquation2D(tempVector0.x, tempVector0.y, tempVector3.x, tempVector3.y, radarDiskCorner3.x - v[1].x , radarDiskCorner3.y - v[1].y); + float X3 = geometry.X; + float Y3 = geometry.Y; + + //apply the combination in 3d space to find out OUV coordinates + tempVector0.set(v[0]); + tempVector0.subtract(v[1]); + tempVector0.unit(); + + tempVector1.set(v[2]); + tempVector1.subtract(v[1]); + tempVector1.unit(); + + tempVector2.cross(tempVector0, tempVector1); + tempVector3.cross(tempVector2, tempVector0); + + vector O = v[1].myClone(); + O.add(tempVector0, X0); + O.add(tempVector3, Y0); + + vector U = v[1].myClone(); + U.add(tempVector0, X1); + U.add(tempVector3, Y1); + + vector V = v[1].myClone(); + V.add(tempVector0, X3); + V.add(tempVector3, Y3); + + return addPolygon(polygons, new polygon3D(v, O, U, V, theTexture, scaleX,scaleY,type)); + } + + + + + + + + //update the model + public void update(){ + //process emerging from ground animation + if(centre.y < -0.32f){ + centre.y+=0.02f; + + for(int i = 0; i < radarDiskIndexStart; i++){ + + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + polygons[i].vertex3D[j].y+=0.02f; + } + } + + for(int i = radarDiskIndexStart; i <= radarDiskIndexEnd; i++){ + polygons[i].origin.y+=0.02f; + polygons[i].rightEnd.y+=0.02f; + polygons[i].bottomEnd.y+=0.02f; + + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + polygons[i].vertex3D[j].y+=0.02f; + + } + polygons[i].findDiffuse(); + } + + shadowvertex0.y+=0.02f; + shadowvertex1.y+=0.02f; + shadowvertex2.y+=0.02f; + shadowvertex3.y+=0.02f; + + + //the building is invulnerable during emerging stage + currentHP = maxHP; + } + + + //check if the building has been destroyed + if(currentHP <= 0){ + countDownToDeath--; + + if(countDownToDeath == 0){ + //spawn an explosion when the building is destroyed + float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount]; + tempFloat[0] = centre.x; + tempFloat[1] = centre.y + 0.15f; + tempFloat[2] = centre.z; + tempFloat[3] = 3.5f; + tempFloat[4] = 1; + tempFloat[5] = 0; + tempFloat[6] = 7; + tempFloat[7] = this.height; + theAssetManager.explosionCount++; + theAssetManager.removeObject(this); + if(theBaseInfo.numberOfCommunicationCenter == 1) + cancelResearch(teamNo); + + if(teamNo == 0) + mainThread.pc.theBaseInfo.numberOfCommunicationCenter--; + else + mainThread.ec.theBaseInfo.numberOfCommunicationCenter--; + + + //removeFromGridMap(); + mainThread.gridMap.tiles[tileIndex[0]][0] = null; + mainThread.gridMap.tiles[tileIndex[1]][0] = null; + mainThread.gridMap.tiles[tileIndex[2]][0] = null; + mainThread.gridMap.tiles[tileIndex[3]][0] = null; + + mainThread.gridMap.tiles[tileIndex[0]][1] = null; + mainThread.gridMap.tiles[tileIndex[1]][1] = null; + mainThread.gridMap.tiles[tileIndex[2]][1] = null; + mainThread.gridMap.tiles[tileIndex[3]][1] = null; + + mainThread.gridMap.tiles[tileIndex[0]][2] = null; + mainThread.gridMap.tiles[tileIndex[1]][2] = null; + mainThread.gridMap.tiles[tileIndex[2]][2] = null; + mainThread.gridMap.tiles[tileIndex[3]][2] = null; + + mainThread.gridMap.tiles[tileIndex[0]][3] = null; + mainThread.gridMap.tiles[tileIndex[1]][3] = null; + mainThread.gridMap.tiles[tileIndex[2]][3] = null; + mainThread.gridMap.tiles[tileIndex[3]][3] = null; + + mainThread.gridMap.tiles[tileIndex[0]][4] = null; + mainThread.gridMap.tiles[tileIndex[1]][4] = null; + mainThread.gridMap.tiles[tileIndex[2]][4] = null; + mainThread.gridMap.tiles[tileIndex[3]][4] = null; + + if(teamNo != 0){ + mainThread.gridMap.tiles[tileIndex[4]][4] = null; + mainThread.gridMap.tiles[tileIndex[5]][4] = null; + mainThread.gridMap.tiles[tileIndex[6]][4] = null; + mainThread.gridMap.tiles[tileIndex[7]][4] = null; + mainThread.gridMap.tiles[tileIndex[8]][4] = null; + } + + + if(attacker.teamNo != teamNo) + attacker.experience+=35; + return; + }else{ + + float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount]; + tempFloat[0] = centre.x + (float)Math.random()/2.5f - 0.2f; + tempFloat[1] = centre.y + 0.15f; + tempFloat[2] = centre.z + (float)Math.random()/2.5f - 0.2f; + tempFloat[3] = 1.5f; + tempFloat[4] = 1; + tempFloat[5] = 0; + tempFloat[6] = 6 + (gameData.getRandom()%4); + tempFloat[7] = this.height; + theAssetManager.explosionCount++; + + + } + } + + if(isRepairing && currentHP >0){ + if(mainThread.frameIndex%8==0 && theBaseInfo.currentCredit > 0 && currentHP maxHP) + currentHP = maxHP; + } + } + + //process researching + if(mainThread.frameIndex%2==0 && (!(theBaseInfo.lowPower && mainThread.frameIndex%4==0))){ + + if(teamNo == 0){ + if(harvesterSpeedResearchProgress_player < 240){ + if(mainThread.pc.theBaseInfo.currentCredit >0){ + mainThread.pc.theBaseInfo.currentCredit--; + creditSpentOnResearching_player++; + harvesterSpeedResearchProgress_player = 240 * creditSpentOnResearching_player/1200; + } + + if(harvesterSpeedResearchProgress_player == 240){ + harvesterSpeedResearched_player = true; + rapidfireResearchProgress_player = 255; + creditSpentOnResearching_player = 0; + upgradeHarvester(0); + } + } + + if(rapidfireResearchProgress_player < 240){ + if(mainThread.pc.theBaseInfo.currentCredit >0){ + mainThread.pc.theBaseInfo.currentCredit--; + creditSpentOnResearching_player++; + rapidfireResearchProgress_player = 240 * creditSpentOnResearching_player/1200; + } + + if(rapidfireResearchProgress_player == 240){ + rapidfireResearched_player = true; + harvesterSpeedResearchProgress_player = 255; + creditSpentOnResearching_player = 0; + } + } + + }else{ + if(harvesterSpeedResearchProgress_enemy < 240){ + if(mainThread.pc.theBaseInfo.currentCredit >0){ + mainThread.pc.theBaseInfo.currentCredit--; + creditSpentOnResearching_enemy++; + harvesterSpeedResearchProgress_enemy = 240 * creditSpentOnResearching_enemy/1500; + } + } + + if(harvesterSpeedResearchProgress_enemy == 240){ + harvesterSpeedResearched_enemy = true; + rapidfireResearchProgress_enemy = 255; + creditSpentOnResearching_enemy = 0; + upgradeHarvester(1); + } + + if(rapidfireResearchProgress_enemy < 240){ + if(mainThread.pc.theBaseInfo.currentCredit >0){ + mainThread.pc.theBaseInfo.currentCredit--; + creditSpentOnResearching_enemy++; + rapidfireResearchProgress_enemy = 240 * creditSpentOnResearching_enemy/1500; + } + + if(rapidfireResearchProgress_enemy == 240){ + rapidfireResearched_enemy = true; + harvesterSpeedResearchProgress_enemy = 255; + creditSpentOnResearching_enemy = 0; + } + } + + } + } + + + + + if(underAttackCountDown > 0) + underAttackCountDown--; + + //mark itself on obstacle map + mainThread.gridMap.currentObstacleMap[tileIndex[0]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[1]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[2]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[3]] = false; + + //update center in camera coordinate + tempCentre.set(centre); + tempCentre.subtract(camera.position); + tempCentre.rotate_XZ(camera.XZ_angle); + tempCentre.rotate_YZ(camera.YZ_angle); + tempCentre.updateLocation(); + + theAssetManager = mainThread.theAssetManager; + + //test if the building is visible in camera point of view + if(visibleBoundary.contains(tempCentre.screenX, tempCentre.screenY) && isRevealed){ + visible = true; + + if(screenBoundary.contains(tempCentre.screenX, tempCentre.screenY)) + withinViewScreen = true; + else + withinViewScreen = false; + + tempshadowvertex0.set(shadowvertex0); + tempshadowvertex0.subtract(camera.position); + tempshadowvertex0.rotate_XZ(camera.XZ_angle); + tempshadowvertex0.rotate_YZ(camera.YZ_angle); + tempshadowvertex0.updateLocation(); + + tempshadowvertex1.set(shadowvertex1); + tempshadowvertex1.subtract(camera.position); + tempshadowvertex1.rotate_XZ(camera.XZ_angle); + tempshadowvertex1.rotate_YZ(camera.YZ_angle); + tempshadowvertex1.updateLocation(); + + tempshadowvertex2.set(shadowvertex2); + tempshadowvertex2.subtract(camera.position); + tempshadowvertex2.rotate_XZ(camera.XZ_angle); + tempshadowvertex2.rotate_YZ(camera.YZ_angle); + tempshadowvertex2.updateLocation(); + + tempshadowvertex3.set(shadowvertex3); + tempshadowvertex3.subtract(camera.position); + tempshadowvertex3.rotate_XZ(camera.XZ_angle); + tempshadowvertex3.rotate_YZ(camera.YZ_angle); + tempshadowvertex3.updateLocation(); + + updateGeometry(); + + + //if the object is visible then draw it on the shadow buffer from light point of view + if(shadowBoundary1.contains(tempshadowvertex0.screenX, tempshadowvertex0.screenY) || + shadowBoundary1.contains(tempshadowvertex1.screenX, tempshadowvertex1.screenY) || + shadowBoundary1.contains(tempshadowvertex2.screenX, tempshadowvertex2.screenY) || + shadowBoundary1.contains(tempshadowvertex3.screenX, tempshadowvertex3.screenY) + ){ + for(int i = 0; i < numOfPolygons; i++){ + polygons[i].update_lightspace(); + + + } + + } + + //add this object to visible unit list + theAssetManager.visibleUnit[theAssetManager.visibleUnitCount] = this; + theAssetManager.visibleUnitCount++; + + + }else{ + visible = false; + } + + + //create vision for enemy commander + if(teamNo == 1){ + int xPos = boundary2D.x1/16 - 12 + 10; + int yPos = 127 - boundary2D.y1/16 - 12 + 10; + + for(int y = 0; y < 25; y++){ + for(int x = 0; x < 25; x++){ + if(bitmapVisionForEnemy[x+ y*25]) + enemyCommander.tempBitmap[xPos + x + (yPos+y)*148] =true; + } + } + } + + + visionInsideScreen = true; + + + + if(visionInsideScreen){ + if(teamNo == 0){ + tempFloat = theAssetManager.visionPolygonInfo[theAssetManager.visionPolygonCount]; + tempFloat[0] = teamNo; + tempFloat[1] = centre.x; + tempFloat[2] = -0.4f; + tempFloat[3] = centre.z; + tempFloat[4] = 3; + theAssetManager.visionPolygonCount++; + } + } + + if(theAssetManager.minimapBitmap[tileIndex[0]] || + theAssetManager.minimapBitmap[tileIndex[1]] || + theAssetManager.minimapBitmap[tileIndex[2]] || + theAssetManager.minimapBitmap[tileIndex[3]] ) + isRevealed = true; + visible_minimap = isRevealed; + + + if(visible_minimap){ + tempInt = theAssetManager.unitsForMiniMap[theAssetManager.unitsForMiniMapCount]; + tempInt[0] = teamNo; + tempInt[1] = boundary2D.x1/16; + tempInt[2] = 127 - boundary2D.y1/16; + tempInt[3] = 3; + if(teamNo == 0 && underAttackCountDown > 0) + tempInt[4] = 10001; + else + tempInt[4] = 10000; + theAssetManager.unitsForMiniMapCount++; + + } + + //scan for clocked unit + if((ID + mainThread.frameIndex)%10 == 0 && !theBaseInfo.lowPower){ + 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].cloakCooldownCount = 60; + } + } + } + } + } + } + + } + + public void updateGeometry(){ + if(centre.y < -0.32f) + return; + + int angle = 2; + if(theBaseInfo.lowPower) + angle=0; + + for(int i = rotationPartIndexStart; i <= rotationPartIndexEnd; i++){ + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + polygons[i].vertex3D[j].subtract(start); + polygons[i].vertex3D[j].rotate_XZ(angle); + polygons[i].vertex3D[j].add(start); + polygons[i].findDiffuse(); + } + polygons[i].normal.rotate_XZ(angle); + } + + for(int i = radarDiskIndexStart; i <= radarDiskIndexEnd; i++){ + polygons[i].origin.subtract(start); + polygons[i].origin.rotate_XZ(angle); + polygons[i].origin.add(start); + + polygons[i].rightEnd.subtract(start); + polygons[i].rightEnd.rotate_XZ(angle); + polygons[i].rightEnd.add(start); + + polygons[i].bottomEnd.subtract(start); + polygons[i].bottomEnd.rotate_XZ(angle); + polygons[i].bottomEnd.add(start); + + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + polygons[i].vertex3D[j].subtract(start); + polygons[i].vertex3D[j].rotate_XZ(angle); + polygons[i].vertex3D[j].add(start); + + } + + polygons[i].normal.rotate_XZ(angle); + polygons[i].findDiffuse(); + } + } + + //draw the model + public void draw(){ + if(!visible) + return; + for(int i = 0; i < numOfPolygons; i++){ + polygons[i].update(); + polygons[i].draw(); + + } + + + } + + public int addPolygon(polygon3D[] polys, polygon3D poly){ + for(int i = 0; i < polys.length; i++){ + if(polys[i] == null){ + polys[i] = poly; + numOfPolygons++; + return i; + } + } + return -1; + } + + public static void researchHarvesterSpeed(int teamNo){ + if(teamNo == 0){ + + harvesterSpeedResearchProgress_player = 0; + rapidfireResearchProgress_player = 254; + }else{ + harvesterSpeedResearchProgress_enemy = 0; + rapidfireResearchProgress_enemy = 254; + } + } + + + public static void researchRapidfire(int teamNo){ + if(teamNo == 0){ + + rapidfireResearchProgress_player = 0; + harvesterSpeedResearchProgress_player = 254; + }else{ + rapidfireResearchProgress_enemy = 0; + harvesterSpeedResearchProgress_enemy = 254; + } + } + + //cancel research + public static void cancelResearch(int teamNo){ + if(teamNo == 0){ + harvesterSpeedResearchProgress_player = 255; + rapidfireResearchProgress_player = 255; + mainThread.pc.theBaseInfo.currentCredit+=creditSpentOnResearching_player; + creditSpentOnResearching_player = 0; + }else{ + harvesterSpeedResearchProgress_enemy = 255; + rapidfireResearchProgress_enemy = 255; + mainThread.ec.theBaseInfo.currentCredit+=creditSpentOnResearching_enemy; + creditSpentOnResearching_enemy = 0; + } + } + + + public void upgradeHarvester(int teamNo){ + for(int i = 0; i < mainThread.theAssetManager.harvesters.length; i++){ + if(mainThread.theAssetManager.harvesters[i] != null && mainThread.theAssetManager.harvesters[i].teamNo == teamNo){ + mainThread.theAssetManager.harvesters[i].speed = 0.014f; + mainThread.theAssetManager.harvesters[i].bodyTurnRate = 8; + } + } + } + + + + public vector getMovement(){ + return movenment; + } +} diff --git a/entity/constructionVehicle.java b/entity/constructionVehicle.java new file mode 100644 index 0000000..dc6cafc --- /dev/null +++ b/entity/constructionVehicle.java @@ -0,0 +1,2018 @@ +package entity; + +import java.awt.Rectangle; + +import core.*; +import enemyAI.enemyCommander; + + +public class constructionVehicle extends solidObject { + + public vector iDirectionBody, jDirectionBody, kDirectionBody; + public vector bodyCenter; + + public static polygon3D[] body, arm, pillar, foot1, foot2, foot3, foot4; + public polygon3D[] bodyClone, armClone, pillarClone, foot1Clone, + foot2Clone, foot3Clone, foot4Clone; + + public static vector armCenter; + public vector armCenterClone; + public int armAngle; + public int openArmCount; + public int extendArmCount; + + public static vector pillarCenter; + public vector pillarCenterClone; + public int pillarAngle; + public int pillarArmCount; + public int footExtendCount; + + public static int maxHP = 300; + + // 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, + 908, 597); + + // 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, 688, + 432); + + // 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, + 1300); + + // a bitmap representation of the vision of the harvester for enemy + // commander + public static boolean[] bitmapVisionForEnemy; + + // the oreintation of the construction vehicle + public int bodyAngle; + + // destination angle + public int destinationAngle; + + public static Rect border, destinationBlock, probeBlock, pointBlock; + + public int heuristicRecalculationCountDown; + public byte[] heuristicMap; + public boolean pathIsFound; + public float nextNodeX, nextNodeY; + public int bodyTurnRate = 5; + + public int jobStatus = 0; + public final int idle = 0; + public final int deploying = 1; + + public static vector tempVector0; + public static vector tempVector1; + public static vector tempVector2; + public static vector tempVector3; + + public static int[] surrounding = new int[9]; + + public constructionYard myConstructionYard; + + public constructionVehicle(vector origin, int bodyAngle, int teamNo) { + speed = 0.009f; + start = new vector(0, 0, 0); + centre = origin.myClone(); + tempCentre = origin.myClone(); + this.bodyAngle = bodyAngle; + immediateDestinationAngle = bodyAngle; + progressStatus = -1; + attackStatus = isAttacking; + + destinationAngle = bodyAngle; + this.teamNo = teamNo; + currentHP = maxHP; + type = 3; + if (bitmapVisionForEnemy == null) { + bitmapVisionForEnemy = createBitmapVision(6); + } + + 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); + border = new Rect(0, 0, 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); + pointBlock = new Rect((int) (origin.x * 64) - 6, + (int) (origin.z * 64) + 6, 12, 12); + + // create main axis in object space + iDirection = new vector(1f, 0, 0); + jDirection = new vector(0, 1f, 0); + kDirection = new vector(0, 0, 1f); + + // create polygons + makePolygons(); + + heuristicMap = new byte[128 * 128]; + + } + + public void makePolygons() { + + + + int skinTextureIndex = 42; + int windowTexture = 43; + int upperBodyTExture = 44; + int armTop = 31; + + if (body == null) { + start.y -= 0.18f; + body = new polygon3D[87]; + v = new vector[] { put(-0.071, 0.025, 0.11), + put(-0.071, 0.025, -0.15), put(-0.071, 0.005, -0.15), + put(-0.071, -0.025, -0.08), put(-0.071, -0.025, 0.07), + put(-0.071, 0.005, 0.11) }; + body[0] = new polygon3D(v, put(-0.071, 0.027, 0.11), put(-0.071, + 0.027, -0.15), put(-0.071, -0.025, 0.11), mainThread.textures[3], + 1, 1, 1); + + v = new vector[] { put(0.071, 0.005, 0.11), + put(0.071, -0.025, 0.07), put(0.071, -0.025, -0.08), + put(0.071, 0.005, -0.15), put(0.071, 0.025, -0.15), + put(0.071, 0.025, 0.11) }; + body[1] = new polygon3D(v, put(0.071, 0.027, -0.15), put(0.071, + 0.027, 0.11), put(0.071, -0.025, -0.15), mainThread.textures[3], + 1, 1, 1); + + v = new vector[] { put(-0.07, 0.05, -0.15), put(0.07, 0.05, -0.15), + put(0.07, 0.015, -0.15), put(-0.07, 0.015, -0.15) }; + body[2] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[skinTextureIndex], 1, 0.3f, 1); + + v = new vector[] { put(-0.07, 0.005, -0.15), + put(-0.05, 0.005, -0.15), put(-0.05, -0.025, -0.08), + put(-0.07, -0.025, -0.08) }; + body[3] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[3], 1, + 1, 1); + + v = new vector[] { put(-0.07, 0.015, -0.15), + put(-0.05, 0.015, -0.15), put(-0.05, 0.005, -0.15), + put(-0.07, 0.005, -0.15) }; + body[4] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[3], 1, + 1, 1); + + v = new vector[] { put(0.05, 0.015, -0.15), + put(0.07, 0.015, -0.15), put(0.07, 0.005, -0.15), + put(0.05, 0.005, -0.15) }; + body[5] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[3], 1, + 1, 1); + + v = new vector[] { put(0.05, 0.005, -0.15), + put(0.07, 0.005, -0.15), put(0.07, -0.025, -0.08), + put(0.05, -0.025, -0.08) }; + body[6] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[3], 1, + 1, 1); + + v = new vector[] { put(0.07, 0.05, -0.15), put(0.07, 0.05, 0.11), + put(0.07, 0.015, 0.11), put(0.07, 0.015, -0.15) }; + body[7] = new polygon3D(v, put(0.07, 0.05, -0.15), put(0.07, 0.05, + 0.11), put(0.07, 0.015, -0.15), + mainThread.textures[skinTextureIndex], 1, 0.3f, 1); + + v = new vector[] { put(-0.07, 0.05, 0.11), put(-0.07, 0.05, -0.15), + put(-0.07, 0.015, -0.15), put(-0.07, 0.015, 0.11) }; + body[8] = new polygon3D(v, put(-0.07, 0.05, 0.11), put(-0.07, 0.05, + -0.15), put(-0.07, 0.015, 0.11), + mainThread.textures[skinTextureIndex], 1, 0.3f, 1); + + v = new vector[] { put(0.07, 0.05, 0.11), put(-0.07, 0.05, 0.11), + put(-0.07, 0.01, 0.11), put(0.07, 0.01, 0.11) }; + body[9] = new polygon3D(v, v[2], v[3], v[1], + mainThread.textures[skinTextureIndex], 1, 0.3f, 1); + + v = new vector[] { put(0.07, 0.05, 0.11), put(-0.07, 0.05, 0.11), + put(-0.07, 0.01, 0.11), put(0.07, 0.01, 0.11) }; + body[10] = new polygon3D(v, v[2], v[3], v[1], + mainThread.textures[skinTextureIndex], 1, 0.3f, 1); + + v = new vector[] { put(0.07, 0.05, 0.11), put(0.07, 0.05, -0.15), + put(-0.07, 0.05, -0.15), put(-0.07, 0.05, 0.11) }; + body[11] = new polygon3D(v, v[1], v[2], v[0], + mainThread.textures[skinTextureIndex], 1, 2f, 1); + body[11].shadowBias = 1000; + + v = new vector[] { put(0.07, 0.08, 0.05), put(0.07, 0.08, 0.13), + put(0.07, 0.04, 0.15), put(0.07, 0.01, 0.15), + put(0.07, 0.01, 0.02) }; + body[12] = new polygon3D(v, put(0.07, 0.05, -0.15), put(0.07, 0.05, + 0.11), put(0.07, 0.015, -0.15), + mainThread.textures[skinTextureIndex], 1, 0.3f, 1); + + v = new vector[] { put(-0.07, 0.01, 0.02), put(-0.07, 0.01, 0.15), + put(-0.07, 0.04, 0.15), put(-0.07, 0.08, 0.13), + put(-0.07, 0.08, 0.05) }; + body[13] = new polygon3D(v, put(-0.07, 0.05, 0.11), put(-0.07, + 0.05, -0.15), put(-0.07, 0.015, 0.11), + mainThread.textures[skinTextureIndex], 1, 0.3f, 1); + + v = new vector[] { put(-0.07, 0.08, 0.05), put(0.07, 0.08, 0.05), + put(0.07, 0.01, 0.02), put(-0.07, 0.01, 0.02) }; + body[14] = new polygon3D(v, v[2], v[3], v[1], + mainThread.textures[skinTextureIndex], 1, 0.3f, 1); + + v = new vector[] { put(-0.07, 0.08, 0.13), put(0.07, 0.08, 0.13), + put(0.07, 0.08, 0.05), put(-0.07, 0.08, 0.05) }; + body[15] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[skinTextureIndex], 1, 0.5f, 1); + + v = new vector[] { put(0.07, 0.04, 0.15), put(-0.07, 0.04, 0.15), + put(-0.07, 0.01, 0.15), put(0.07, 0.01, 0.15) }; + body[16] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[skinTextureIndex], 1, 0.3f, 1); + + v = new vector[] { put(0.07, 0.08, 0.13), put(-0.07, 0.08, 0.13), + put(-0.07, 0.04, 0.15), put(0.07, 0.04, 0.15) }; + body[17] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[windowTexture], 1, 0.6f, 1); + + double theta = Math.PI / 32; + double r = 0.08; + double angleOffset = Math.PI / 4 * 5 - 0.06; + + start.z -= 0.08f; + + tempVector0 = new vector(0, 0, 0); + tempVector1 = new vector(0, 0, 0); + tempVector2 = new vector(0, 0, 0); + tempVector3 = new vector(0, 0, 0); + + for (int i = 0; i < 18; i++) { + v = new vector[] { + put(r * Math.cos((i + 1) * theta + angleOffset), 0.04, + r * Math.sin((i + 1) * theta + angleOffset)), + put(r * Math.cos(i * theta + angleOffset), 0.04, r + * Math.sin(i * theta + angleOffset)), + put(r * Math.cos(i * theta + angleOffset), 0.09, r + * Math.sin(i * theta + angleOffset)), + put(r * Math.cos((i + 1) * theta + angleOffset), 0.09, + r * Math.sin((i + 1) * theta + angleOffset)) }; + + if (i == 0) { + + tempVector1 = v[2].myClone(); + } + + if (i == 17) { + + tempVector3 = v[3].myClone(); + } + body[18 + i] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[upperBodyTExture], 1, 1, 1); + + } + start.z += 0.08f; + + float the_x = tempVector1.x; + float the_y = tempVector1.y; + float the_z = tempVector1.z; + + v = new vector[] { new vector(the_x, the_y, the_z + 0.1f), + tempVector1.myClone(), + new vector(the_x, the_y - 0.08f, the_z), + new vector(the_x, the_y - 0.08f, the_z + 0.1f) }; + body[36] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[upperBodyTExture], 1, 1, 1); + tempVector0 = new vector(the_x, the_y, the_z + 0.1f); + + float the_x1 = tempVector3.x; + float the_y1 = tempVector3.y; + float the_z1 = tempVector3.z; + + v = new vector[] { tempVector3.myClone(), + new vector(the_x1, the_y1, the_z + 0.1f), + new vector(the_x1, the_y1 - 0.08f, the_z + 0.1f), + new vector(the_x1, the_y1 - 0.08f, the_z1) }; + body[37] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[upperBodyTExture], 1, 1, 1); + tempVector2 = new vector(the_x1, the_y1, the_z + 0.1f); + + start.z -= 0.08f; + v = new vector[21]; + for (int i = 0; i < 19; i++) { + v[i] = put(r * Math.cos((18 - i) * theta + angleOffset), 0.09, + r * Math.sin((18 - i) * theta + angleOffset)); + } + v[19] = tempVector0.myClone(); + v[20] = tempVector2.myClone(); + + body[38] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[upperBodyTExture], 2, 2, 1); + body[38].Ambient_I -= 11; + body[38].shadowBias = 10000; + + start.z += 0.08f; + + v = new vector[] { + tempVector2.myClone(), + tempVector0.myClone(), + new vector(tempVector0.x, tempVector0.y - 0.08f, + tempVector0.z), + new vector(tempVector2.x, tempVector2.y - 0.08f, + tempVector2.z) }; + body[39] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[upperBodyTExture], 2, 2, 1); + + v = new vector[] { + new vector(the_x1, -0.04f, tempVector0.z - 0.07f), + new vector(the_x1, -0.04f, tempVector0.z - 0.015f), + new vector(the_x1, the_y1, tempVector0.z), + new vector(the_x1, the_y1, tempVector0.z - 0.08f) }; + body[40] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[upperBodyTExture], 2, 2, 1); + + v = new vector[] { + new vector(the_x1 - 0.05f, the_y1, tempVector0.z - 0.08f), + new vector(the_x1 - 0.05f, the_y1, tempVector0.z), + new vector(the_x1 - 0.05f, -0.04f, tempVector0.z - 0.015f), + new vector(the_x1 - 0.05f, -0.04f, tempVector0.z - 0.07f) }; + body[41] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[upperBodyTExture], 2, 2, 1); + + v = new vector[] { + new vector(the_x1 - 0.05f, -0.04f, tempVector0.z - 0.07f), + new vector(the_x1, -0.04f, tempVector0.z - 0.07f), + new vector(the_x1, the_y1, tempVector0.z - 0.08f), + new vector(the_x1 - 0.05f, the_y1, tempVector0.z - 0.08f) }; + body[42] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[upperBodyTExture], 2, 2, 1); + + v = new vector[] { + new vector(the_x1 - 0.05f, -0.04f, tempVector0.z - 0.015f), + new vector(the_x1, -0.04f, tempVector0.z - 0.015f), + new vector(the_x1, -0.04f, tempVector0.z - 0.07f), + new vector(the_x1 - 0.05f, -0.04f, tempVector0.z - 0.07f) }; + body[43] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[upperBodyTExture], 2, 2, 1); + + v = new vector[] { + new vector(the_x1 + 0.001f, -0.045f, tempVector0.z - 0.05f), + new vector(the_x1 + 0.001f, -0.045f, tempVector0.z - 0.02f), + new vector(the_x1 + 0.001f, the_y1, tempVector0.z - 0.005f), + new vector(the_x1 + 0.001f, the_y1 + 0.01f, + tempVector0.z - 0.05f) }; + body[44] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[45], 2, + 2, 1); + + v = new vector[] { + new vector(the_x1, -0.04f, tempVector0.z - 0.015f), + new vector(the_x1 - 0.05f, -0.04f, tempVector0.z - 0.015f), + new vector(the_x1 - 0.05f, the_y1, tempVector0.z), + new vector(the_x1, the_y1, tempVector0.z) }; + body[45] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[46], 1, + 1, 1); + + v = new vector[] { + new vector(the_x1 - 0.051f, the_y1 + 0.01f, + tempVector0.z - 0.05f), + new vector(the_x1 - 0.051f, the_y1, tempVector0.z - 0.005f), + new vector(the_x1 - 0.051f, -0.045f, tempVector0.z - 0.02f), + new vector(the_x1 - 0.051f, -0.045f, tempVector0.z - 0.05f) }; + body[46] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[45], 2, + 2, 1); + + angleOffset = Math.PI * 1.65; + theta = Math.PI / 22; + r = 0.02; + + float h = 0.11f; + float l = -0.12f; + + for (int i = 0; i < 16; i++) { + v = new vector[] { + put(0.005f, r * Math.cos((i + 1) * theta + angleOffset) + + h, + r * Math.sin((i + 1) * theta + angleOffset) + l), + put(0.005f, r * Math.cos(i * theta + angleOffset) + h, + r * Math.sin(i * theta + angleOffset) + l), + put(-0.005, r * Math.cos(i * theta + angleOffset) + h, + r * Math.sin(i * theta + angleOffset) + l), + put(-0.005f, + r * Math.cos((i + 1) * theta + angleOffset) + h, + r * Math.sin((i + 1) * theta + angleOffset) + l) }; + + if (i == 0) { + the_x = v[2].x; + the_y = v[2].y; + the_z = v[2].z; + } + if (i == 15) { + the_x1 = v[0].x; + the_y1 = v[0].y; + the_z1 = v[0].z; + } + + body[47 + i] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[25], 1, 1, 1); + } + + v = new vector[] { new vector(the_x, the_y, the_z), + new vector(the_x + 0.01f, the_y, the_z), + new vector(the_x + 0.01f, the_y - 0.08f, the_z), + new vector(the_x, the_y - 0.08f, the_z) }; + body[63] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1, + 10, 1); + + v = new vector[] { new vector(the_x1, the_y1, the_z1), + new vector(the_x1 - 0.01f, the_y1, the_z1), + new vector(the_x1 - 0.01f, the_y1 - 0.08f, the_z1 + 0.01f), + new vector(the_x1, the_y1 - 0.08f, the_z1 + 0.01f) }; + body[64] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1, + 10, 1); + + v = new vector[19]; + for (int i = 0; i < 17; i++) { + v[i] = put(-0.005f, + r * Math.cos((16 - i) * theta + angleOffset) + h, r + * Math.sin((16 - i) * theta + angleOffset) + l); + } + v[17] = new vector(-0.005f, the_y - 0.08f, the_z); + v[18] = new vector(-0.005f, the_y1 - 0.08f, the_z1 + 0.01f); + body[65] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1, + 1, 1); + + v = new vector[19]; + for (int i = 0; i < 19; i++) { + v[i] = body[65].vertex3D[18 - i].myClone(); + v[i].x += 0.01f; + } + body[66] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1, + 1, 1); + + start.x -= 0.05; + + for (int i = 0; i < 16; i++) { + v = new vector[] { + put(0.005f, r * Math.cos((i + 1) * theta + angleOffset) + + h, + r * Math.sin((i + 1) * theta + angleOffset) + l), + put(0.005f, r * Math.cos(i * theta + angleOffset) + h, + r * Math.sin(i * theta + angleOffset) + l), + put(-0.005, r * Math.cos(i * theta + angleOffset) + h, + r * Math.sin(i * theta + angleOffset) + l), + put(-0.005f, + r * Math.cos((i + 1) * theta + angleOffset) + h, + r * Math.sin((i + 1) * theta + angleOffset) + l) }; + + if (i == 0) { + the_x = v[2].x; + the_y = v[2].y; + the_z = v[2].z; + } + if (i == 15) { + the_x1 = v[0].x; + the_y1 = v[0].y; + the_z1 = v[0].z; + } + + body[67 + i] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[25], 1, 1, 1); + } + + v = new vector[] { new vector(the_x, the_y, the_z), + new vector(the_x + 0.01f, the_y, the_z), + new vector(the_x + 0.01f, the_y - 0.08f, the_z), + new vector(the_x, the_y - 0.08f, the_z) }; + body[83] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1, + 10, 1); + + v = new vector[] { new vector(the_x1, the_y1, the_z1), + new vector(the_x1 - 0.01f, the_y1, the_z1), + new vector(the_x1 - 0.01f, the_y1 - 0.08f, the_z1 + 0.01f), + new vector(the_x1, the_y1 - 0.08f, the_z1 + 0.01f) }; + body[84] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1, + 10, 1); + + v = new vector[19]; + for (int i = 0; i < 17; i++) { + v[i] = put(-0.005f, + r * Math.cos((16 - i) * theta + angleOffset) + h, r + * Math.sin((16 - i) * theta + angleOffset) + l); + } + v[17] = new vector(-0.055f, the_y - 0.08f, the_z); + v[18] = new vector(-0.055f, the_y1 - 0.08f, the_z1 + 0.01f); + body[85] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1, + 1, 1); + + v = new vector[19]; + for (int i = 0; i < 19; i++) { + v[i] = body[85].vertex3D[18 - i].myClone(); + v[i].x += 0.01f; + } + body[86] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1, + 1, 1); + + start.set(0, 0, 0); + armCenter = new vector(-0.025f, -0.06000001f, -0.12f); + + arm = new polygon3D[33]; + v = new vector[] { put(-0.02f, 0.025f, 0.23), + put(0.02f, 0.025f, 0.23), put(0.02f, 0.025f, -0.02), + put(-0.02f, 0.025f, -0.02) }; + arm[0] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[upperBodyTExture], 10, 10, 1); + arm[0].shadowBias = 100000; + + v = new vector[] { put(-0.02f, -0.015f, -0.02), + put(0.02f, -0.015f, -0.02), put(0.02f, -0.015f, 0.23), + put(-0.02f, -0.015f, 0.23) }; + arm[1] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[upperBodyTExture], 10, 10, 1); + arm[1].shadowBias = 100000; + + v = new vector[] { put(0.02f, 0.025f, -0.02), + put(0.02f, 0.025f, 0.23), put(0.02f, -0.015f, 0.23), + put(0.02f, -0.015f, -0.02) }; + arm[2] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[upperBodyTExture], 10, 10, 1); + arm[2].shadowBias = 100000; + + v = new vector[] { put(-0.02f, -0.015f, -0.02), + put(-0.02f, -0.015f, 0.23), put(-0.02f, 0.025f, 0.23), + put(-0.02f, 0.025f, -0.02) }; + arm[3] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[upperBodyTExture], 10, 10, 1); + arm[3].shadowBias = 100000; + + r = 0.02f; + theta = Math.PI / 16; + angleOffset = Math.PI; + h = 0.005f; + l = -0.02f; + + for (int i = 0; i < 16; i++) { + v = new vector[] { + put(0.02f, r * Math.cos((i + 1) * theta + angleOffset) + + h, + r * Math.sin((i + 1) * theta + angleOffset) + l), + put(0.02f, r * Math.cos(i * theta + angleOffset) + h, r + * Math.sin(i * theta + angleOffset) + l), + put(-0.02f, r * Math.cos(i * theta + angleOffset) + h, + r * Math.sin(i * theta + angleOffset) + l), + put(-0.02f, r * Math.cos((i + 1) * theta + angleOffset) + + h, + r * Math.sin((i + 1) * theta + angleOffset) + l) }; + + arm[4 + i] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[upperBodyTExture], 10, 10, 1); + } + + v = new vector[17]; + for (int i = 0; i < 17; i++) { + v[i] = put(-0.02f, r * Math.cos((16 - i) * theta + angleOffset) + + h, r * Math.sin((16 - i) * theta + angleOffset) + l); + } + arm[20] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[upperBodyTExture], 10, 10, 1); + + v = new vector[17]; + for (int i = 0; i < 17; i++) { + v[i] = arm[20].vertex3D[16 - i].myClone(); + v[i].x += 0.03f; + } + arm[21] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[upperBodyTExture], 10, 10, 1); + + v = new vector[] { put(0.02f, 0.025f, 0.23), + put(-0.02f, 0.025f, 0.23), put(-0.02f, -0.015f, 0.23), + put(0.02f, -0.015f, 0.23) }; + arm[22] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[upperBodyTExture], 10, 10, 1); + + v = new vector[] { put(-0.015f, 0.02f, 0.27), + put(0.015f, 0.02f, 0.27), put(0.015f, 0.02f, 0.03), + put(-0.015f, 0.02f, 0.03) }; + arm[23] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[47], 10, + 10, 1); + + v = new vector[] { put(-0.015f, -0.01f, 0.03), + put(0.015f, -0.01f, 0.03), put(0.015f, -0.01f, 0.27), + put(-0.015f, -0.01f, 0.27) }; + arm[24] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[47], 10, + 10, 1); + + v = new vector[] { put(0.015f, 0.02f, 0.03), + put(0.015f, 0.02f, 0.27), put(0.015f, -0.01f, 0.27), + put(0.015f, -0.01f, 0.03) }; + arm[25] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[47], 10, + 10, 1); + + v = new vector[] { put(-0.015f, -0.01f, 0.03), + put(-0.015f, -0.01f, 0.27), put(-0.015f, 0.02f, 0.27), + put(-0.015f, 0.02f, 0.03) }; + arm[26] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[47], 10, + 10, 1); + + v = new vector[] { put(-0.02f, 0.025f, 0.29), + put(0.02f, 0.025f, 0.29), put(0.02f, 0.025f, 0.27), + put(-0.02f, 0.025f, 0.27) }; + arm[27] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[armTop], + 1.2f, 1f, 1); + + v = new vector[] { put(0.02f, 0.025f, 0.27), + put(0.02f, 0.025f, 0.29), put(0.02f, 0f, 0.29), + put(0.02f, -0.015f, 0.27) }; + arm[28] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[armTop], + 1f, 1f, 1); + + v = new vector[] { put(-0.02f, -0.015f, 0.27), + put(-0.02f, 0f, 0.29), put(-0.02f, 0.025f, 0.29), + put(-0.02f, 0.025f, 0.27) }; + arm[29] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[armTop], + 1f, 1f, 1); + + v = new vector[] { put(0.02f, 0.025f, 0.29), + put(-0.02f, 0.025f, 0.29), put(-0.02f, 0, 0.29), + put(0.02f, 0, 0.29) }; + arm[30] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[armTop], + 1.2f, 1f, 1); + + v = new vector[] { put(-0.02f, 0.025f, 0.27), + put(0.02f, 0.025f, 0.27), put(0.02f, -0.015f, 0.27), + put(-0.02f, -0.015f, 0.27) }; + arm[31] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[armTop], + 1.2f, 1f, 1); + + v = new vector[] { put(0.02f, 0, 0.29), put(-0.02f, 0, 0.29), + put(-0.02f, -0.015f, 0.27), put(0.02f, -0.015f, 0.27) }; + arm[32] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[armTop], + 1.2f, 1f, 1); + + start.set(0, 0, 0); + pillarCenter = new vector(-0.025f, -0.09000001f, -0.05f); + pillar = new polygon3D[49]; + + theta = Math.PI / 12; + r = 0.01; + + for (int i = 0; i < 24; i++) { + v = new vector[] { + put(r * Math.cos((i + 1) * theta), + r * Math.sin((i + 1) * theta), 0.08), + put(r * Math.cos(i * theta), r * Math.sin(i * theta), + 0.08), + put(r * Math.cos(i * theta), r * Math.sin(i * theta), 0), + put(r * Math.cos((i + 1) * theta), + r * Math.sin((i + 1) * theta), 0), + + }; + pillar[i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), + v[3].myClone(), mainThread.textures[upperBodyTExture], 4f, + 4f, 1); + } + + v = new vector[24]; + for (int i = 0; i < 24; i++) { + v[i] = put(r * Math.cos(i * theta), r * Math.sin(i * theta), + 0.08); + } + pillar[24] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[upperBodyTExture], 4f, 4f, 1); + + r = 0.005; + for (int i = 0; i < 24; i++) { + v = new vector[] { + put(r * Math.cos((i + 1) * theta), + r * Math.sin((i + 1) * theta), 0.18), + put(r * Math.cos(i * theta), r * Math.sin(i * theta), + 0.18), + put(r * Math.cos(i * theta), r * Math.sin(i * theta), + 0.08), + put(r * Math.cos((i + 1) * theta), + r * Math.sin((i + 1) * theta), 0.08), + + }; + pillar[25 + i] = new polygon3D(v, v[0].myClone(), + v[1].myClone(), v[3].myClone(), mainThread.textures[29], 4f, + 4f, 1); + } + + // foot 1 + foot1 = new polygon3D[53]; + theta = Math.PI / 12; + r = 0.01; + float w = 0.08f; + l = 0.06f; + + for (int i = 0; i < 24; i++) { + v = new vector[] { + put(r * Math.cos((i + 1) * theta) + w, -0.16, + r * Math.sin((i + 1) * theta) + l), + put(r * Math.cos(i * theta) + w, -0.16, + r * Math.sin(i * theta) + l), + put(r * Math.cos(i * theta) + w, -0.13, + r * Math.sin(i * theta) + l), + put(r * Math.cos((i + 1) * theta) + w, -0.13, + r * Math.sin((i + 1) * theta) + l), }; + foot1[i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), + v[3].myClone(), mainThread.textures[upperBodyTExture], 4f, + 4f, 1); + } + v = new vector[24]; + for (int i = 0; i < 24; i++) { + v[23 - i] = put(r * Math.cos(i * theta) + w, -0.13, + r * Math.sin(i * theta) + l); + } + foot1[24] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[upperBodyTExture], 4f, 4f, 1); + + r = 0.006f; + + for (int i = 0; i < 24; i++) { + v = new vector[] { + put(r * Math.cos((i + 1) * theta) + w, -0.17, + r * Math.sin((i + 1) * theta) + l), + put(r * Math.cos(i * theta) + w, -0.17, + r * Math.sin(i * theta) + l), + put(r * Math.cos(i * theta) + w, -0.131, + r * Math.sin(i * theta) + l), + put(r * Math.cos((i + 1) * theta) + w, -0.131, + r * Math.sin((i + 1) * theta) + l), }; + foot1[i + 25] = new polygon3D(v, v[0].myClone(), + v[1].myClone(), v[3].myClone(), mainThread.textures[29], 4f, + 4f, 1); + } + + theta = Math.PI / 12; + r = 0.014; + + v = new vector[24]; + for (int i = 0; i < 24; i++) { + v[23 - i] = put(r * Math.cos(i * theta) + w, -0.17, + r * Math.sin(i * theta) + l); + } + foot1[49] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[33], + 4f, 4f, 1); + foot1[49].shadowBias = 10000; + + start.x -= 0.08; + + v = new vector[] { put(0.0, -0.14, 0.065), put(0.15, -0.14, 0.065), + put(0.15, -0.14, 0.055), put(0.0, -0.14, 0.055) }; + foot1[50] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], + 4f, 1f, 1); + + v = new vector[] { put(0.15, -0.14, 0.065), put(0.0, -0.14, 0.065), + put(0.0, -0.16, 0.065), put(0.15, -0.16, 0.065) }; + foot1[51] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[armTop], 4f, 0.5f, 1); + + v = new vector[] { put(0.15, -0.16, 0.055), put(0.0, -0.16, 0.055), + put(0.0, -0.14, 0.055), put(0.15, -0.14, 0.055) }; + foot1[52] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[armTop], 4f, 0.5f, 1); + + // foot 2 + start.set(0, 0, 0); + foot2 = new polygon3D[53]; + theta = Math.PI / 12; + r = 0.01; + w = 0.08f; + l = -0.12f; + + for (int i = 0; i < 24; i++) { + v = new vector[] { + put(r * Math.cos((i + 1) * theta) + w, -0.16, + r * Math.sin((i + 1) * theta) + l), + put(r * Math.cos(i * theta) + w, -0.16, + r * Math.sin(i * theta) + l), + put(r * Math.cos(i * theta) + w, -0.13, + r * Math.sin(i * theta) + l), + put(r * Math.cos((i + 1) * theta) + w, -0.13, + r * Math.sin((i + 1) * theta) + l), }; + foot2[i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), + v[3].myClone(), mainThread.textures[upperBodyTExture], 4f, + 4f, 1); + } + v = new vector[24]; + for (int i = 0; i < 24; i++) { + v[23 - i] = put(r * Math.cos(i * theta) + w, -0.13, + r * Math.sin(i * theta) + l); + } + foot2[24] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[upperBodyTExture], 4f, 4f, 1); + + r = 0.006f; + + for (int i = 0; i < 24; i++) { + v = new vector[] { + put(r * Math.cos((i + 1) * theta) + w, -0.17, + r * Math.sin((i + 1) * theta) + l), + put(r * Math.cos(i * theta) + w, -0.17, + r * Math.sin(i * theta) + l), + put(r * Math.cos(i * theta) + w, -0.131, + r * Math.sin(i * theta) + l), + put(r * Math.cos((i + 1) * theta) + w, -0.131, + r * Math.sin((i + 1) * theta) + l), }; + foot2[i + 25] = new polygon3D(v, v[0].myClone(), + v[1].myClone(), v[3].myClone(), mainThread.textures[29], 4f, + 4f, 1); + } + + theta = Math.PI / 12; + r = 0.014; + + v = new vector[24]; + for (int i = 0; i < 24; i++) { + v[23 - i] = put(r * Math.cos(i * theta) + w, -0.17, + r * Math.sin(i * theta) + l); + } + foot2[49] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[33], + 4f, 4f, 1); + foot2[49].shadowBias = 10000; + + start.x -= 0.08; + start.z -= 0.18; + + v = new vector[] { put(0.0, -0.14, 0.065), put(0.15, -0.14, 0.065), + put(0.15, -0.14, 0.055), put(0.0, -0.14, 0.055) }; + foot2[50] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], + 4f, 1f, 1); + + v = new vector[] { put(0.15, -0.14, 0.065), put(0.0, -0.14, 0.065), + put(0.0, -0.16, 0.065), put(0.15, -0.16, 0.065) }; + foot2[51] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[armTop], 4f, 0.5f, 1); + + v = new vector[] { put(0.15, -0.16, 0.055), put(0.0, -0.16, 0.055), + put(0.0, -0.14, 0.055), put(0.15, -0.14, 0.055) }; + foot2[52] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[armTop], 4f, 0.5f, 1); + + // foot 3 + start.set(0, 0, 0); + foot3 = new polygon3D[53]; + theta = Math.PI / 12; + r = 0.01; + w = -0.08f; + l = 0.06f; + + for (int i = 0; i < 24; i++) { + v = new vector[] { + put(r * Math.cos((i + 1) * theta) + w, -0.16, + r * Math.sin((i + 1) * theta) + l), + put(r * Math.cos(i * theta) + w, -0.16, + r * Math.sin(i * theta) + l), + put(r * Math.cos(i * theta) + w, -0.13, + r * Math.sin(i * theta) + l), + put(r * Math.cos((i + 1) * theta) + w, -0.13, + r * Math.sin((i + 1) * theta) + l), }; + foot3[i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), + v[3].myClone(), mainThread.textures[upperBodyTExture], 4f, + 4f, 1); + } + v = new vector[24]; + for (int i = 0; i < 24; i++) { + v[23 - i] = put(r * Math.cos(i * theta) + w, -0.13, + r * Math.sin(i * theta) + l); + } + foot3[24] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[upperBodyTExture], 4f, 4f, 1); + + r = 0.006f; + + for (int i = 0; i < 24; i++) { + v = new vector[] { + put(r * Math.cos((i + 1) * theta) + w, -0.17, + r * Math.sin((i + 1) * theta) + l), + put(r * Math.cos(i * theta) + w, -0.17, + r * Math.sin(i * theta) + l), + put(r * Math.cos(i * theta) + w, -0.131, + r * Math.sin(i * theta) + l), + put(r * Math.cos((i + 1) * theta) + w, -0.131, + r * Math.sin((i + 1) * theta) + l), }; + foot3[i + 25] = new polygon3D(v, v[0].myClone(), + v[1].myClone(), v[3].myClone(), mainThread.textures[29], 4f, + 4f, 1); + } + + theta = Math.PI / 12; + r = 0.014; + + v = new vector[24]; + for (int i = 0; i < 24; i++) { + v[23 - i] = put(r * Math.cos(i * theta) + w, -0.17, + r * Math.sin(i * theta) + l); + } + foot3[49] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[33], + 4f, 4f, 1); + foot3[49].shadowBias = 10000; + + start.x -= 0.08; + + v = new vector[] { put(0.0, -0.14, 0.065), put(0.15, -0.14, 0.065), + put(0.15, -0.14, 0.055), put(0.0, -0.14, 0.055) }; + foot3[50] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], + 4f, 1f, 1); + + v = new vector[] { put(0.15, -0.14, 0.065), put(0.0, -0.14, 0.065), + put(0.0, -0.16, 0.065), put(0.15, -0.16, 0.065) }; + foot3[51] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[armTop], 4f, 0.5f, 1); + + v = new vector[] { put(0.15, -0.16, 0.055), put(0.0, -0.16, 0.055), + put(0.0, -0.14, 0.055), put(0.15, -0.14, 0.055) }; + foot3[52] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[armTop], 4f, 0.5f, 1); + + // foot 4 + start.set(0, 0, 0); + foot4 = new polygon3D[53]; + theta = Math.PI / 12; + r = 0.01; + w = -0.08f; + l = -0.12f; + + for (int i = 0; i < 24; i++) { + v = new vector[] { + put(r * Math.cos((i + 1) * theta) + w, -0.16, + r * Math.sin((i + 1) * theta) + l), + put(r * Math.cos(i * theta) + w, -0.16, + r * Math.sin(i * theta) + l), + put(r * Math.cos(i * theta) + w, -0.13, + r * Math.sin(i * theta) + l), + put(r * Math.cos((i + 1) * theta) + w, -0.13, + r * Math.sin((i + 1) * theta) + l), }; + foot4[i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), + v[3].myClone(), mainThread.textures[upperBodyTExture], 4f, + 4f, 1); + } + v = new vector[24]; + for (int i = 0; i < 24; i++) { + v[23 - i] = put(r * Math.cos(i * theta) + w, -0.13, + r * Math.sin(i * theta) + l); + } + foot4[24] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[upperBodyTExture], 4f, 4f, 1); + + r = 0.006f; + + for (int i = 0; i < 24; i++) { + v = new vector[] { + put(r * Math.cos((i + 1) * theta) + w, -0.17, + r * Math.sin((i + 1) * theta) + l), + put(r * Math.cos(i * theta) + w, -0.17, + r * Math.sin(i * theta) + l), + put(r * Math.cos(i * theta) + w, -0.131, + r * Math.sin(i * theta) + l), + put(r * Math.cos((i + 1) * theta) + w, -0.131, + r * Math.sin((i + 1) * theta) + l), }; + foot4[i + 25] = new polygon3D(v, v[0].myClone(), + v[1].myClone(), v[3].myClone(), mainThread.textures[29], 4f, + 4f, 1); + } + + theta = Math.PI / 12; + r = 0.014; + + v = new vector[24]; + for (int i = 0; i < 24; i++) { + v[23 - i] = put(r * Math.cos(i * theta) + w, -0.17, + r * Math.sin(i * theta) + l); + } + foot4[49] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[33], + 4f, 4f, 1); + foot4[49].shadowBias = 10000; + + start.x -= 0.08; + start.z -= 0.18; + + v = new vector[] { put(0.0, -0.14, 0.065), put(0.15, -0.14, 0.065), + put(0.15, -0.14, 0.055), put(0.0, -0.14, 0.055) }; + foot4[50] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], + 4f, 1f, 1); + + v = new vector[] { put(0.15, -0.14, 0.065), put(0.0, -0.14, 0.065), + put(0.0, -0.16, 0.065), put(0.15, -0.16, 0.065) }; + foot4[51] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[armTop], 4f, 0.5f, 1); + + v = new vector[] { put(0.15, -0.16, 0.055), put(0.0, -0.16, 0.055), + put(0.0, -0.14, 0.055), put(0.15, -0.14, 0.055) }; + foot4[52] = new polygon3D(v, v[0], v[1], v[3], + mainThread.textures[armTop], 4f, 0.5f, 1); + + } + + bodyClone = clonePolygons(body, false); + + armCenterClone = new vector(0, 0, 0); + armClone = clonePolygons(arm, false); + + pillarCenterClone = new vector(0, 0, 0); + pillarClone = clonePolygons(pillar, false); + + foot1Clone = clonePolygons(foot1, false); + foot2Clone = clonePolygons(foot2, false); + foot3Clone = clonePolygons(foot3, false); + foot4Clone = clonePolygons(foot4, false); + + if (teamNo != 0) { + for (int i = 0; i < body.length; i++) { + if (body[i].myTexture.ID == 42) + bodyClone[i].myTexture = mainThread.textures[10]; + + if (body[i].myTexture.ID == upperBodyTExture) + bodyClone[i].myTexture = mainThread.textures[48]; + + if (body[i].myTexture.ID == 46) + bodyClone[i].myTexture = mainThread.textures[50]; + } + + for (int i = 0; i < foot1.length; i++) { + if (foot1[i].myTexture.ID == upperBodyTExture) { + foot1Clone[i].myTexture = mainThread.textures[48]; + foot2Clone[i].myTexture = mainThread.textures[48]; + foot3Clone[i].myTexture = mainThread.textures[48]; + foot4Clone[i].myTexture = mainThread.textures[48]; + + } + if (foot1[i].myTexture.ID == armTop) { + foot1Clone[i].myTexture = mainThread.textures[49]; + foot2Clone[i].myTexture = mainThread.textures[49]; + foot3Clone[i].myTexture = mainThread.textures[49]; + foot4Clone[i].myTexture = mainThread.textures[49]; + } + } + + for (int i = 0; i < arm.length; i++) { + if (arm[i].myTexture.ID == upperBodyTExture) + armClone[i].myTexture = mainThread.textures[48]; + + if (armClone[i].myTexture.ID == armTop) + armClone[i].myTexture = mainThread.textures[49]; + } + + for (int i = 0; i < pillar.length; i++) { + if (pillar[i].myTexture.ID == upperBodyTExture) { + pillarClone[i].myTexture = mainThread.textures[48]; + + } + } + + } + } + + // update the model + public void update() { + // check if the harvester has finished deploying + if (footExtendCount == 180) { + theAssetManager.removeObject(this); + removeFromGridMap(); + currentHP = 0; + if (isSelected) { + mainThread.pc.addToSelection(myConstructionYard); + } + return; + } + + // check if harvester 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+=30; + + if (jobStatus == deploying) { + myConstructionYard.currentHP = 0; + myConstructionYard.countDownToDeath = -1; + } + + return; + } + + if (jobStatus == deploying && footExtendCount == 0) { + movement.reset(); + footExtendCount = 1; + } + + if (footExtendCount > 0) { + footExtendCount++; + } + + if (footExtendCount == 80) + openArmCount = 60; + + if (openArmCount > 1) { + openArmCount--; + } + + if (openArmCount == 1 && extendArmCount < 30) + extendArmCount++; + + // carry out commands given by the player or AI + if (jobStatus != deploying && !disableUnitLevelAI) + carryOutCommands(); + + if (tightSpaceManeuverCountDown > 0) + tightSpaceManeuverCountDown--; + + if (heuristicRecalculationCountDown > 0) + heuristicRecalculationCountDown--; + + if(underAttackCountDown > 0) + underAttackCountDown--; + + // 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(); + } + + // 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 - 650); + visionInsideScreen = camera.screen.intersects(visionBoundary); + + // 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; + } + } + } + + if (visionInsideScreen && teamNo == 0) { + 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 / 16) * 128]; + if (teamNo == 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] = 0; + theAssetManager.unitsForMiniMapCount++; + } + + // test if the tank object is visible in camera point of view + if (visible_minimap) { + if (currentHP <= maxHP / 2 && (mainThread.frameIndex + ID) % 3 == 0) { + // spawn smoke particle if the unit 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) { + updateGeometry(); + + for (int i = 0; i < bodyClone.length; i++) { + bodyClone[i].update_lightspace(); + } + + for (int i = 0; i < armClone.length; i++) { + armClone[i].update_lightspace(); + } + + for (int i = 0; i < pillarClone.length; i++) { + pillarClone[i].update_lightspace(); + } + + for (int i = 0; i < foot1Clone.length; i++) { + foot1Clone[i].update_lightspace(); + } + + for (int i = 0; i < foot2Clone.length; i++) { + foot2Clone[i].update_lightspace(); + } + + for (int i = 0; i < foot3Clone.length; i++) { + foot3Clone[i].update_lightspace(); + } + + for (int i = 0; i < foot4Clone.length; i++) { + foot4Clone[i].update_lightspace(); + } + + theAssetManager.visibleUnit[theAssetManager.visibleUnitCount] = this; + theAssetManager.visibleUnitCount++; + + } + } + + // carry out commands given by player or AI commander + public void carryOutCommands() { + if (currentCommand == StandBy) { + resetLogicStatus(); + jobStatus = idle; + + } else if (currentCommand == move) { + performPathFindingLogic(); + } + } + + // use a path finder to move to desination + public void performPathFindingLogic() { + + if (!pathIsFound && heuristicRecalculationCountDown == 0) { + + int destX = (int) (destinationX * 64) / 16; + int destY = 127 - (int) (destinationY * 64) / 16; + + pathIsFound = PathFinder.createHeuristicMap(heuristicMap, + occupiedTile0, occupiedTile1, occupiedTile2, occupiedTile3, + destX, destY); + heuristicRecalculationCountDown = 32; + + if (pathIsFound) { + // find the first node in the path + int nextTile0 = findAdjacentTileWithSmallestHeuristic(occupiedTile0); + int nextTile1 = findAdjacentTileWithSmallestHeuristic(occupiedTile1); + int nextTile2 = findAdjacentTileWithSmallestHeuristic(occupiedTile2); + int nextTile3 = findAdjacentTileWithSmallestHeuristic(occupiedTile3); + + if (occupiedTile1 == -1) + nextTile1 = occupiedTile1; + if (occupiedTile2 == -1) + nextTile2 = occupiedTile2; + if (occupiedTile3 == -1) + nextTile3 = occupiedTile3; + + if (nextTile0 != occupiedTile0) { + nextNodeX = 0.125f + (nextTile0 % 128) * 0.25f; + nextNodeY = 0.125f + (127 - (nextTile0 / 128)) * 0.25f; + + } else if (nextTile1 != occupiedTile1) { + nextNodeX = 0.125f + (nextTile1 % 128) * 0.25f; + nextNodeY = 0.125f + (127 - (nextTile1 / 128)) * 0.25f; + + } else if (nextTile2 != occupiedTile2) { + nextNodeX = 0.125f + (nextTile2 % 128) * 0.25f; + nextNodeY = 0.125f + (127 - (nextTile2 / 128)) * 0.25f; + + } else if (nextTile3 != occupiedTile3) { + nextNodeX = 0.125f + (nextTile3 % 128) * 0.25f; + nextNodeY = 0.125f + (127 - (nextTile3 / 128)) * 0.25f; + } + } + } + + if (pathIsFound) { + + movement.reset(); + + // check if the harvester has reached next node in the path + if (centre.x == nextNodeX && centre.z == nextNodeY) { + // check if the harvester has reached the destination + int destX = (int) (destinationX * 64) / 16; + int destY = 127 - (int) (destinationY * 64) / 16; + int nodeX = (int) (centre.x * 64) / 16; + int nodeY = 127 - (int) (centre.z * 64) / 16; + if (destX == nodeX && destY == nodeY) { + pathIsFound = false; + resetLogicStatus(); + currentCommand = StandBy; + return; + } else { + // if destination hasn't reached, find the next node + int nextTile0 = findAdjacentTileWithSmallestHeuristic(occupiedTile0); + nextNodeX = 0.125f + (nextTile0 % 128) * 0.25f; + nextNodeY = 0.125f + (127 - (nextTile0 / 128)) * 0.25f; + } + } + + float distanceToNextNode = (float) Math.sqrt((nextNodeX - centre.x) + * (nextNodeX - centre.x) + (nextNodeY - centre.z) + * (nextNodeY - centre.z)); + calculateMovement(); + destinationAngle = geometry.findAngle(centre.x, centre.z, + nextNodeX, nextNodeY); + immediateDestinationAngle = destinationAngle; + + if (Math.abs(bodyAngle - immediateDestinationAngle) > 45 + && Math.abs(bodyAngle - immediateDestinationAngle) < 315) { + + int bodyAngleDelta = 360 - (geometry.findAngleDelta(bodyAngle, + immediateDestinationAngle, bodyTurnRate) + 360) % 360; + bodyAngle = (bodyAngle - bodyAngleDelta + 360) % 360; + movement.reset(); + + } else { + if (bodyAngle != immediateDestinationAngle) { + int bodyAngleDelta = 360 - (geometry.findAngleDelta( + bodyAngle, immediateDestinationAngle, bodyTurnRate) + 360) % 360; + bodyAngle = (bodyAngle - bodyAngleDelta + 360) % 360; + } + + movement.set(nextNodeX - centre.x, 0, nextNodeY - centre.z); + + if (speed < distanceToNextNode) { + movement.unit(); + movement.scale(speed); + } + + // check collision + xPos_old = boundary2D.x1; + yPos_old = boundary2D.y1; + xPos = (int) ((centre.x + movement.x) * 64) - 8; + yPos = (int) ((centre.z + movement.z) * 64) + 8; + boundary2D.setOrigin(xPos, yPos); + + Rect r = checkForCollision(boundary2D); + boundary2D.setOrigin(xPos_old, yPos_old); + + if (r != null) { + movement.reset(); + pathIsFound = false; + + } + } + + return; + } + + if (!pathIsFound) { + if ((movement.x == 0 && movement.z == 0) + || mainThread.gridMap.tiles[occupiedTile0][4] != null) { + if ((Math.abs(destinationX - centre.x) + + Math.abs(destinationY - centre.z) > 0.5) + || (jobStatus == idle)) { + heuristicRecalculationCountDown = 64; + } + } + performMovementLogic(); + avoidGettingStucked(); + + } + + } + + public int findAdjacentTileWithSmallestHeuristic(int currentTile) { + int smallestHeurstic = 127; + int nextTile = currentTile; + + boolean[] obstacleMap = mainThread.gridMap.previousObstacleMap; + + // check north west tile + int northWestTile = currentTile - 128 - 1; + int northTile = currentTile - 128; + int northEastTile = currentTile - 128 + 1; + int eastTile = currentTile + 1; + int southEastTile = currentTile + 1 + 128; + int southTile = currentTile + 128; + int southWestTile = currentTile + 128 - 1; + int westTile = currentTile - 1; + + if (northWestTile > 0 && northWestTile < 16384 + && obstacleMap[northTile] && obstacleMap[westTile]) { + if (heuristicMap[northWestTile] < smallestHeurstic) { + smallestHeurstic = heuristicMap[northWestTile]; + nextTile = northWestTile; + } + } + + // check north tile + + if (northTile > 0 && northTile < 16384) { + if (heuristicMap[northTile] < smallestHeurstic) { + smallestHeurstic = heuristicMap[northTile]; + nextTile = northTile; + } + } + + // check north east tile + if (northEastTile > 0 && northEastTile < 16384 + && obstacleMap[northTile] && obstacleMap[eastTile]) { + if (heuristicMap[northEastTile] < smallestHeurstic) { + smallestHeurstic = heuristicMap[northEastTile]; + nextTile = northEastTile; + } + } + + // check east tile + + if (eastTile > 0 && eastTile < 16384) { + if (heuristicMap[eastTile] < smallestHeurstic) { + smallestHeurstic = heuristicMap[eastTile]; + nextTile = eastTile; + } + } + + // check south east tile + + if (southEastTile > 0 && southEastTile < 16384 + && obstacleMap[southTile] && obstacleMap[eastTile]) { + if (heuristicMap[southEastTile] < smallestHeurstic) { + smallestHeurstic = heuristicMap[southEastTile]; + nextTile = southEastTile; + } + } + + // check south tile + + if (southTile > 0 && southTile < 16384) { + if (heuristicMap[southTile] < smallestHeurstic) { + smallestHeurstic = heuristicMap[southTile]; + nextTile = southTile; + } + } + + // check south west tile + + if (southWestTile > 0 && southWestTile < 16384 + && obstacleMap[southTile] && obstacleMap[westTile]) { + if (heuristicMap[southWestTile] < smallestHeurstic) { + smallestHeurstic = heuristicMap[southWestTile]; + nextTile = southWestTile; + } + } + + // check west tile + if (westTile > 0 && westTile < 16384) { + if (heuristicMap[westTile] < smallestHeurstic) { + smallestHeurstic = heuristicMap[westTile]; + nextTile = westTile; + } + } + + return nextTile; + } + + // move to a destination position, ignore any hostile units it encounters + public void performMovementLogic() { + + // 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; + } + + if (Math.abs(bodyAngle - immediateDestinationAngle) > 45 + && Math.abs(bodyAngle - immediateDestinationAngle) < 315) { + + int bodyAngleDelta = 360 - (geometry.findAngleDelta(bodyAngle, + immediateDestinationAngle, bodyTurnRate) + 360) % 360; + bodyAngle = (bodyAngle - bodyAngleDelta + 360) % 360; + movement.reset(); + + } else { + if (bodyAngle != immediateDestinationAngle) { + int bodyAngleDelta = 360 - (geometry.findAngleDelta(bodyAngle, + immediateDestinationAngle, bodyTurnRate) + 360) % 360; + bodyAngle = (bodyAngle - bodyAngleDelta + 360) % 360; + } + + 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 avoidGettingStucked() { + // if the object can't move for some period then recalculate the path + if (movement.x == 0 && movement.z == 0) { + stuckCount++; + } + + if (obstacle != null) { + if ((unStableObstacle != null || !isStable(obstacle.owner)) + && (ID + randomNumber + mainThread.frameIndex) % 128 == 0) { + newDestinationisGiven = true; + currentMovementStatus = freeToMove; + hugWallCoolDown = 0; + stuckCount = 0; + randomNumber = gameData.getRandom(); + } + } + + if (stuckCount > 128) { + newDestinationisGiven = true; + stuckCount = 0; + currentMovementStatus = freeToMove; + hugWallCoolDown = 0; + + } + } + + public void draw() { + if (!visible) + return; + + for (int i = 0; i < bodyClone.length; i++) { + bodyClone[i].update(); + bodyClone[i].draw(); + } + + for (int i = 0; i < armClone.length; i++) { + armClone[i].update(); + armClone[i].draw(); + } + + for (int i = 0; i < pillarClone.length; i++) { + pillarClone[i].update(); + pillarClone[i].draw(); + } + + for (int i = 0; i < foot1Clone.length; i++) { + foot1Clone[i].update(); + foot1Clone[i].draw(); + } + + for (int i = 0; i < foot2Clone.length; i++) { + foot2Clone[i].update(); + foot2Clone[i].draw(); + } + + for (int i = 0; i < foot3Clone.length; i++) { + foot3Clone[i].update(); + foot3Clone[i].draw(); + } + + for (int i = 0; i < foot4Clone.length; i++) { + foot4Clone[i].update(); + foot4Clone[i].draw(); + } + } + + public vector getMovement() { + return movement; + } + + public void updateGeometry() { + + for (int i = 0; i < bodyClone.length; i++) { + bodyClone[i].origin.set(body[i].origin); + + bodyClone[i].origin.rotate_XZ(360 - bodyAngle); + bodyClone[i].origin.add(centre); + + bodyClone[i].bottomEnd.set(body[i].bottomEnd); + + bodyClone[i].bottomEnd.rotate_XZ(360 - bodyAngle); + bodyClone[i].bottomEnd.add(centre); + + bodyClone[i].rightEnd.set(body[i].rightEnd); + bodyClone[i].rightEnd.rotate_XZ(360 - bodyAngle); + bodyClone[i].rightEnd.add(centre); + + for (int j = 0; j < bodyClone[i].vertex3D.length; j++) { + bodyClone[i].vertex3D[j].set(body[i].vertex3D[j]); + bodyClone[i].vertex3D[j].rotate_XZ(360 - bodyAngle); + bodyClone[i].vertex3D[j].add(centre); + + bodyClone[i].normal.set(body[i].normal); + bodyClone[i].normal.rotate_XZ(360 - bodyAngle); + bodyClone[i].findDiffuse(); + } + } + + // update arm center + armCenterClone.set(armCenter); + armCenterClone.rotate_XZ(360 - bodyAngle); + armCenterClone.add(centre); + + if (openArmCount == 0) + armAngle = 0; + else + armAngle = 360 - (60 - openArmCount); + + for (int i = 0; i < armClone.length; i++) { + armClone[i].origin.set(arm[i].origin); + if (i > 22) + armClone[i].origin.z += (0.006f * extendArmCount); + + armClone[i].origin.rotate_YZ(armAngle); + armClone[i].origin.rotate_XZ(360 - bodyAngle); + armClone[i].origin.add(armCenterClone); + + armClone[i].bottomEnd.set(arm[i].bottomEnd); + if (i > 22) + armClone[i].bottomEnd.z += (0.006f * extendArmCount); + armClone[i].bottomEnd.rotate_YZ(armAngle); + armClone[i].bottomEnd.rotate_XZ(360 - bodyAngle); + armClone[i].bottomEnd.add(armCenterClone); + + armClone[i].rightEnd.set(arm[i].rightEnd); + if (i > 22) + armClone[i].rightEnd.z += (0.006f * extendArmCount); + armClone[i].rightEnd.rotate_YZ(armAngle); + armClone[i].rightEnd.rotate_XZ(360 - bodyAngle); + armClone[i].rightEnd.add(armCenterClone); + + for (int j = 0; j < armClone[i].vertex3D.length; j++) { + armClone[i].vertex3D[j].set(arm[i].vertex3D[j]); + if (i > 22) + armClone[i].vertex3D[j].z += (0.006f * extendArmCount); + armClone[i].vertex3D[j].rotate_YZ(armAngle); + armClone[i].vertex3D[j].rotate_XZ(360 - bodyAngle); + armClone[i].vertex3D[j].add(armCenterClone); + + armClone[i].normal.set(arm[i].normal); + armClone[i].normal.rotate_YZ(armAngle); + armClone[i].normal.rotate_XZ(360 - bodyAngle); + armClone[i].findDiffuse(); + } + } + + // update pillar center + pillarCenterClone.set(pillarCenter); + pillarCenterClone.rotate_XZ(360 - bodyAngle); + pillarCenterClone.add(centre); + + if (openArmCount == 0) + pillarAngle = 350; + else + pillarAngle = 350 - (int) ((60 - openArmCount) * 1.3); + + for (int i = 0; i < pillarClone.length; i++) { + pillarClone[i].origin.set(pillar[i].origin); + pillarClone[i].origin.rotate_YZ(pillarAngle); + pillarClone[i].origin.rotate_XZ(360 - bodyAngle); + pillarClone[i].origin.add(pillarCenterClone); + + pillarClone[i].bottomEnd.set(pillar[i].bottomEnd); + pillarClone[i].bottomEnd.rotate_YZ(pillarAngle); + pillarClone[i].bottomEnd.rotate_XZ(360 - bodyAngle); + pillarClone[i].bottomEnd.add(pillarCenterClone); + + pillarClone[i].rightEnd.set(pillar[i].rightEnd); + pillarClone[i].rightEnd.rotate_YZ(pillarAngle); + pillarClone[i].rightEnd.rotate_XZ(360 - bodyAngle); + pillarClone[i].rightEnd.add(pillarCenterClone); + + for (int j = 0; j < pillarClone[i].vertex3D.length; j++) { + pillarClone[i].vertex3D[j].set(pillar[i].vertex3D[j]); + pillarClone[i].vertex3D[j].rotate_YZ(pillarAngle); + pillarClone[i].vertex3D[j].rotate_XZ(360 - bodyAngle); + pillarClone[i].vertex3D[j].add(pillarCenterClone); + + pillarClone[i].normal.set(pillar[i].normal); + pillarClone[i].normal.rotate_YZ(pillarAngle); + pillarClone[i].normal.rotate_XZ(360 - bodyAngle); + pillarClone[i].findDiffuse(); + } + } + + float footExtendDistance = footExtendCount * 0.002f; + if (footExtendDistance > 0.08) + footExtendDistance = 0.08f; + + float footDownDistance = 0; + if (footExtendDistance == 0.08f) + footDownDistance = (footExtendCount - 40) * 0.001f; + if (footDownDistance > 0.03) + footDownDistance = 0.03f; + + // update foot1 + for (int i = 0; i < foot1Clone.length; i++) { + foot1Clone[i].origin.set(foot1[i].origin); + foot1Clone[i].origin.x += footExtendDistance; + if (i >= 25 && i <= 49) + foot1Clone[i].origin.y -= footDownDistance; + foot1Clone[i].origin.rotate_XZ(360 - bodyAngle); + foot1Clone[i].origin.add(centre); + + foot1Clone[i].bottomEnd.set(foot1[i].bottomEnd); + foot1Clone[i].bottomEnd.x += footExtendDistance; + if (i >= 25 && i <= 49) + foot1Clone[i].bottomEnd.y -= footDownDistance; + foot1Clone[i].bottomEnd.rotate_XZ(360 - bodyAngle); + foot1Clone[i].bottomEnd.add(centre); + + foot1Clone[i].rightEnd.set(foot1[i].rightEnd); + foot1Clone[i].rightEnd.x += footExtendDistance; + if (i >= 25 && i <= 49) + foot1Clone[i].rightEnd.y -= footDownDistance; + foot1Clone[i].rightEnd.rotate_XZ(360 - bodyAngle); + foot1Clone[i].rightEnd.add(centre); + + for (int j = 0; j < foot1Clone[i].vertex3D.length; j++) { + foot1Clone[i].vertex3D[j].set(foot1[i].vertex3D[j]); + foot1Clone[i].vertex3D[j].x += footExtendDistance; + + if (i >= 25 && i <= 49) + foot1Clone[i].vertex3D[j].y -= footDownDistance; + + foot1Clone[i].vertex3D[j].rotate_XZ(360 - bodyAngle); + foot1Clone[i].vertex3D[j].add(centre); + + foot1Clone[i].normal.set(foot1[i].normal); + foot1Clone[i].normal.rotate_XZ(360 - bodyAngle); + foot1Clone[i].findDiffuse(); + } + } + + // update foot2 + for (int i = 0; i < foot2Clone.length; i++) { + foot2Clone[i].origin.set(foot2[i].origin); + foot2Clone[i].origin.x += footExtendDistance; + if (i >= 25 && i <= 49) + foot2Clone[i].origin.y -= footDownDistance; + foot2Clone[i].origin.rotate_XZ(360 - bodyAngle); + foot2Clone[i].origin.add(centre); + + foot2Clone[i].bottomEnd.set(foot2[i].bottomEnd); + foot2Clone[i].bottomEnd.x += footExtendDistance; + if (i >= 25 && i <= 49) + foot2Clone[i].bottomEnd.y -= footDownDistance; + foot2Clone[i].bottomEnd.rotate_XZ(360 - bodyAngle); + foot2Clone[i].bottomEnd.add(centre); + + foot2Clone[i].rightEnd.set(foot2[i].rightEnd); + foot2Clone[i].rightEnd.x += footExtendDistance; + if (i >= 25 && i <= 49) + foot2Clone[i].rightEnd.y -= footDownDistance; + foot2Clone[i].rightEnd.rotate_XZ(360 - bodyAngle); + foot2Clone[i].rightEnd.add(centre); + + for (int j = 0; j < foot2Clone[i].vertex3D.length; j++) { + foot2Clone[i].vertex3D[j].set(foot2[i].vertex3D[j]); + foot2Clone[i].vertex3D[j].x += footExtendDistance; + + if (i >= 25 && i <= 49) + foot2Clone[i].vertex3D[j].y -= footDownDistance; + + foot2Clone[i].vertex3D[j].rotate_XZ(360 - bodyAngle); + foot2Clone[i].vertex3D[j].add(centre); + + foot2Clone[i].normal.set(foot2[i].normal); + foot2Clone[i].normal.rotate_XZ(360 - bodyAngle); + foot2Clone[i].findDiffuse(); + } + } + + // update foot3 + for (int i = 0; i < foot3Clone.length; i++) { + foot3Clone[i].origin.set(foot3[i].origin); + foot3Clone[i].origin.x -= footExtendDistance; + if (i >= 25 && i <= 49) + foot3Clone[i].origin.y -= footDownDistance; + foot3Clone[i].origin.rotate_XZ(360 - bodyAngle); + foot3Clone[i].origin.add(centre); + + foot3Clone[i].bottomEnd.set(foot3[i].bottomEnd); + foot3Clone[i].bottomEnd.x -= footExtendDistance; + if (i >= 25 && i <= 49) + foot3Clone[i].bottomEnd.y -= footDownDistance; + foot3Clone[i].bottomEnd.rotate_XZ(360 - bodyAngle); + foot3Clone[i].bottomEnd.add(centre); + + foot3Clone[i].rightEnd.set(foot3[i].rightEnd); + foot3Clone[i].rightEnd.x -= footExtendDistance; + if (i >= 25 && i <= 49) + foot3Clone[i].rightEnd.y -= footDownDistance; + foot3Clone[i].rightEnd.rotate_XZ(360 - bodyAngle); + foot3Clone[i].rightEnd.add(centre); + + for (int j = 0; j < foot3Clone[i].vertex3D.length; j++) { + foot3Clone[i].vertex3D[j].set(foot3[i].vertex3D[j]); + foot3Clone[i].vertex3D[j].x -= footExtendDistance; + + if (i >= 25 && i <= 49) + foot3Clone[i].vertex3D[j].y -= footDownDistance; + + foot3Clone[i].vertex3D[j].rotate_XZ(360 - bodyAngle); + foot3Clone[i].vertex3D[j].add(centre); + + foot3Clone[i].normal.set(foot3[i].normal); + foot3Clone[i].normal.rotate_XZ(360 - bodyAngle); + foot3Clone[i].findDiffuse(); + } + } + + // update foot3 + for (int i = 0; i < foot4Clone.length; i++) { + foot4Clone[i].origin.set(foot4[i].origin); + foot4Clone[i].origin.x -= footExtendDistance; + if (i >= 25 && i <= 49) + foot4Clone[i].origin.y -= footDownDistance; + foot4Clone[i].origin.rotate_XZ(360 - bodyAngle); + foot4Clone[i].origin.add(centre); + + foot4Clone[i].bottomEnd.set(foot4[i].bottomEnd); + foot4Clone[i].bottomEnd.x -= footExtendDistance; + if (i >= 25 && i <= 49) + foot4Clone[i].bottomEnd.y -= footDownDistance; + foot4Clone[i].bottomEnd.rotate_XZ(360 - bodyAngle); + foot4Clone[i].bottomEnd.add(centre); + + foot4Clone[i].rightEnd.set(foot4[i].rightEnd); + foot4Clone[i].rightEnd.x -= footExtendDistance; + if (i >= 25 && i <= 49) + foot4Clone[i].rightEnd.y -= footDownDistance; + foot4Clone[i].rightEnd.rotate_XZ(360 - bodyAngle); + foot4Clone[i].rightEnd.add(centre); + + for (int j = 0; j < foot4Clone[i].vertex3D.length; j++) { + foot4Clone[i].vertex3D[j].set(foot4[i].vertex3D[j]); + foot4Clone[i].vertex3D[j].x -= footExtendDistance; + + if (i >= 25 && i <= 49) + foot4Clone[i].vertex3D[j].y -= footDownDistance; + + foot4Clone[i].vertex3D[j].rotate_XZ(360 - bodyAngle); + foot4Clone[i].vertex3D[j].add(centre); + + foot4Clone[i].normal.set(foot4[i].normal); + foot4Clone[i].normal.rotate_XZ(360 - bodyAngle); + foot4Clone[i].findDiffuse(); + } + } + } + + public boolean canBeDeployed() { + if (jobStatus == deploying) + return false; + + int position = (boundary2D.x1 + 8) / 16 + + (127 - (boundary2D.y1 - 8 - 1) / 16) * 128; + surrounding[0] = position - 129; + surrounding[1] = position - 128; + surrounding[2] = position - 127; + surrounding[3] = position - 1; + surrounding[4] = position; + surrounding[5] = position + 1; + surrounding[6] = position + 127; + surrounding[7] = position + 128; + surrounding[8] = position + 129; + + for (int i = 0; i < 9; i++) { + position = surrounding[i]; + if (position / 128 > 0 && position / 128 < 127 + && position % 128 > 0 && position % 128 < 127) { + tile = mainThread.gridMap.tiles[position]; + for (int j = 0; j < 5; j++) { + if (tile[j] != null && tile[j] != this) { + return false; + } + } + } else { + return false; + } + } + + return true; + } + + public void expand() { + + jobStatus = deploying; + + float theXPos = ((boundary2D.x1 + 8) / 16 * 0.25f) + 0.125f; + float theYPos = ((boundary2D.y1 - 8 - 1) / 16 * 0.25f) + 0.125f; + + myConstructionYard = new constructionYard(theXPos, -2.89f, theYPos, + teamNo); + myConstructionYard.isSelectable = false; + theAssetManager.addContructionYard(myConstructionYard); + + } + + public void resetLogicStatus() { + movement.reset(); + currentMovementStatus = freeToMove; + stuckCount = 0; + destinationX = centre.x; + destinationY = centre.z; + insideDeistinationRadiusCount = 0; + obstacle = null; + closeToDestination = false; + + } + + public void moveTo(float destinationX, float destinationY) { + + if (jobStatus != idle) { + return; + } + + resetLogicStatus(); + pathIsFound = false; + this.destinationX = destinationX; + this.destinationY = destinationY; + newDestinationisGiven = true; + heuristicRecalculationCountDown = 0; + jobStatus = idle; + + } + + public int getMaxHp() { + return maxHP; + } + +} diff --git a/entity/constructionYard.java b/entity/constructionYard.java new file mode 100644 index 0000000..48e9148 --- /dev/null +++ b/entity/constructionYard.java @@ -0,0 +1,1813 @@ +package entity; + +import java.awt.Rectangle; + +import core.*; +import enemyAI.enemyCommander; +import gui.deployGrid; + +//the construction yard model + +public class constructionYard extends solidObject{ + //the polygons of the model + private polygon3D[] polygons; + + public static int maxHP = 1000; + public int countDownToDeath = 16; + + public boolean needToDrawDeploymentGrid; + + public vector shadowvertex0, tempshadowvertex0,shadowvertex1, tempshadowvertex1,shadowvertex2, tempshadowvertex2,shadowvertex3, tempshadowvertex3; + + //a screen space boundary which is used to test if the object is visible from camera point of view + public final static Rectangle visibleBoundary = new Rectangle(-85,-85,920, 762); + + //a screen space boundary which is used to test if the entire object is within the screen + public final static Rectangle screenBoundary = new Rectangle(60,60,648, 402); + + //screen space boundary which is used to test if the shadow of the object is within the screen + public final static Rectangle shadowBoundary1 = new Rectangle(40,70,828, 502); + + //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,1600, 2000); + + //a bitmap representation of the vision of the power plant for enemy commander + public static boolean[] bitmapVisionForEnemy; + + //construction yard never moves + public final static vector movenment = new vector(0,0,0); + + //construction yard occupies 9 tiles + public int [] tileIndex = new int[9]; + + public vector tempVector = new vector(0,0,0); + public vector tempVector0 = new vector(0,0,0); + public vector tempVector1 = new vector(0,0,0); + public vector tempVector2 = new vector(0,0,0); + public vector tempVector3 = new vector(0,0,0); + + //positions of the vents + public vector ventCenter1 = new vector(0,0,0); + public polygon3D[] vent1; + public polygon3D[] vent1Clone; + public int vent1Angle = 0; + + public vector ventCenter2 = new vector(0,0,0); + public polygon3D[] vent2; + public polygon3D[] vent2Clone; + public int vent2Angle = 35; + + //crane + vector armCenter; + vector pillarCenter; + + public boolean emergingStarted; + + public int currentStatus; + //public static int isBuilding = 1; + + public boolean canBuildPowerPlant, canBuildRefinery, canBuildFactory, canBuildCommunicationCenter, canBuildTechCenter, canBuildGunTurret, canBuildMissileTurret; + public int powerPlantProgress, refineryProgress, factoryProgress, communicationCenterProgress, techCenterProgress, gunTurretProgress, missileTurretProgress; + public int creditSpentOnBuilding; + + public deployGrid dg; + + public baseInfo theBaseInfo; + + public static int intendedDeployLocation = -1; + + public int currentBuildingType = -1; + + public constructionYard(float x, float y, float z, int teamNo){ + //uncontrollable unit, but act as a big sized static collidable agent + type = 104; + + currentHP = 1000; + + this.teamNo = teamNo; + + ID = globalUniqID++; + + currentCommand = StandBy; + + if(teamNo == 0){ + isRevealed = true; + theBaseInfo = mainThread.pc.theBaseInfo; + }else{ + theBaseInfo = mainThread.ec.theBaseInfo; + } + + theBaseInfo.numberOfConstructionYard++; + + + dg = new deployGrid(); + + + if(bitmapVisionForEnemy == null){ + bitmapVisionForEnemy = createBitmapVision(8); + } + + powerPlantProgress = 255; + refineryProgress = 255; + factoryProgress = 255; + communicationCenterProgress = 255; + techCenterProgress = 255; + gunTurretProgress = 255; + missileTurretProgress = 255; + + + //create 2D boundary + boundary2D = new Rect((int)(x*64) - 24, (int)(z*64) + 24, 48, 48); + boundary2D.owner = this; + int centerX = (int)(x*64); + int centerY = (int)(z*64); + + tileIndex[0] = (centerX - 16)/16 + (127 - (centerY + 16)/16)*128; + tileIndex[1] = (centerX + 16)/16 + (127 - (centerY + 16)/16)*128; + tileIndex[2] = (centerX + 16)/16 + (127 - (centerY - 16)/16)*128; + tileIndex[3] = (centerX - 16)/16 + (127 - (centerY - 16)/16)*128; + tileIndex[4] = (centerX)/16 + (127 - (centerY + 16)/16)*128; + tileIndex[5] = (centerX)/16 + (127 - (centerY - 16)/16)*128; + tileIndex[6] = (centerX - 16)/16 + (127 - centerY/16)*128; + tileIndex[7] = centerX/16 + (127 - centerY/16)*128; + tileIndex[8] = (centerX + 16)/16 + (127 - centerY/16)*128; + + + mainThread.gridMap.tiles[tileIndex[0]][0] = this; + mainThread.gridMap.tiles[tileIndex[1]][0] = this; + mainThread.gridMap.tiles[tileIndex[2]][0] = this; + mainThread.gridMap.tiles[tileIndex[3]][0] = this; + mainThread.gridMap.tiles[tileIndex[4]][0] = this; + mainThread.gridMap.tiles[tileIndex[5]][0] = this; + mainThread.gridMap.tiles[tileIndex[6]][0] = this; + mainThread.gridMap.tiles[tileIndex[7]][0] = this; + mainThread.gridMap.tiles[tileIndex[8]][0] = this; + + + mainThread.gridMap.tiles[tileIndex[0]][1] = this; + mainThread.gridMap.tiles[tileIndex[1]][1] = this; + mainThread.gridMap.tiles[tileIndex[2]][1] = this; + mainThread.gridMap.tiles[tileIndex[3]][1] = this; + mainThread.gridMap.tiles[tileIndex[4]][1] = this; + mainThread.gridMap.tiles[tileIndex[5]][1] = this; + mainThread.gridMap.tiles[tileIndex[6]][1] = this; + mainThread.gridMap.tiles[tileIndex[7]][1] = this; + mainThread.gridMap.tiles[tileIndex[8]][1] = this; + + mainThread.gridMap.tiles[tileIndex[0]][2] = this; + mainThread.gridMap.tiles[tileIndex[1]][2] = this; + mainThread.gridMap.tiles[tileIndex[2]][2] = this; + mainThread.gridMap.tiles[tileIndex[3]][2] = this; + mainThread.gridMap.tiles[tileIndex[4]][2] = this; + mainThread.gridMap.tiles[tileIndex[5]][2] = this; + mainThread.gridMap.tiles[tileIndex[6]][2] = this; + mainThread.gridMap.tiles[tileIndex[7]][2] = this; + mainThread.gridMap.tiles[tileIndex[8]][2] = this; + + mainThread.gridMap.tiles[tileIndex[0]][3] = this; + mainThread.gridMap.tiles[tileIndex[1]][3] = this; + mainThread.gridMap.tiles[tileIndex[2]][3] = this; + mainThread.gridMap.tiles[tileIndex[3]][3] = this; + mainThread.gridMap.tiles[tileIndex[4]][3] = this; + mainThread.gridMap.tiles[tileIndex[5]][3] = this; + mainThread.gridMap.tiles[tileIndex[6]][3] = this; + mainThread.gridMap.tiles[tileIndex[7]][3] = this; + mainThread.gridMap.tiles[tileIndex[8]][3] = this; + + + mainThread.gridMap.tiles[tileIndex[0]][4] = this; + mainThread.gridMap.tiles[tileIndex[1]][4] = this; + mainThread.gridMap.tiles[tileIndex[2]][4] = this; + mainThread.gridMap.tiles[tileIndex[3]][4] = this; + mainThread.gridMap.tiles[tileIndex[4]][4] = this; + mainThread.gridMap.tiles[tileIndex[5]][4] = this; + mainThread.gridMap.tiles[tileIndex[6]][4] = this; + mainThread.gridMap.tiles[tileIndex[7]][4] = this; + mainThread.gridMap.tiles[tileIndex[8]][4] = this; + + + //init model + start = new vector(x,y,z); + iDirection = new vector(1f,0,0); + jDirection = new vector(0,1f,0); + kDirection = new vector(0,0,1f); + + //define centre of the model in world coordinate + start = new vector(x,y,z); + centre = start.myClone(); + tempCentre = start.myClone(); + + shadowvertex0 =start.myClone(); + shadowvertex0.add(-0.4f,-0.2f, -0.45f); + tempshadowvertex0 = new vector(0,0,0); + + shadowvertex1 =start.myClone(); + shadowvertex1.add(-0.45f,-0.2f, 0.2f); + tempshadowvertex1 = new vector(0,0,0); + + shadowvertex2 =start.myClone(); + shadowvertex2.add(0.2f,-0.2f, -0.45f); + tempshadowvertex2 = new vector(0,0,0); + + shadowvertex3 =start.myClone(); + shadowvertex3.add(0.2f,-0.2f, 0.2f); + tempshadowvertex3 = new vector(0,0,0); + + polygon3D.recreateTextureCoordinateFlag = true; + makePolygons(); + polygon3D.recreateTextureCoordinateFlag = false; + } + + //create polygons + public void makePolygons(){ + polygons = new polygon3D[240 + 73+77]; + + int polyIndex; + + int doorTextureIndex = 44; + int upperBodyTExture = 44; + int armTop = 31; + if(teamNo == 1) + doorTextureIndex = 53; + + v = new vector[]{put(-0.38, 0.3, 0.35), put(-0.345, 0.3, 0.385), put(0.345, 0.3, 0.385), put(0.38, 0.3, 0.35), put(0.38, 0.3, -0.35), put(0.345, 0.3, -0.385), put(-0.345, 0.3, -0.385), put(-0.38, 0.3, -0.35)}; + polyIndex = addPolygon(polygons, new polygon3D(v, put(-0.38, 0.3, 0.385), put(0.38, 0.3, 0.385), put(-0.38, 0.3, -0.385), mainThread.textures[30], 1,1,1)); + polygons[polyIndex].shadowBias = 5000; + + v = new vector[]{put(0.345, 0.35, -0.1), put(0.345, 0.35, 0.345), put(0.345, 0.30, 0.345), put(0.345, 0.30, -0.1) }; + addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,0.25f,1)); + + v = new vector[]{put(-0.1, 0.30, -0.1), put(-0.1, 0.30, 0.345), put(-0.1, 0.35, 0.345), put(-0.1, 0.35, -0.1)}; + addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,0.25f,1)); + + v = new vector[]{put(-0.0875, 0.35, -0.1), put(-0.0875, 0.35, 0.345), put(-0.0875, 0.30, 0.345), put(-0.0875, 0.30, -0.1) }; + addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,0.25f,1)); + + v = new vector[]{put(0.3325, 0.30, -0.1), put(0.3325, 0.30, 0.345), put(0.3325, 0.35, 0.345), put(0.3325, 0.35, -0.1)}; + addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,0.25f,1)); + + v = new vector[]{put(0.3325, 0.35, -0.1), put(0.345, 0.35, -0.1), put(0.345, 0.30, -0.1), put(0.3325, 0.30, -0.1)}; + addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,0.25f,1)); + + v = new vector[]{put(0.3325, 0.30, 0.345), put(0.345, 0.30, 0.345), put(0.345, 0.35, 0.345), put(0.3325, 0.35, 0.345)}; + addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,0.25f,1)); + + v = new vector[]{put(-0.1, 0.35, -0.1), put(-0.0875, 0.35, -0.1), put(-0.0875, 0.30, -0.1), put(-0.1, 0.30, -0.1)}; + addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,0.25f,1)); + + v = new vector[]{put(-0.1, 0.30, 0.345), put(-0.0875, 0.30, 0.345), put(-0.0875, 0.35, 0.345), put(-0.1, 0.35, 0.345)}; + addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,0.25f,1)); + + + + double r = 0.2225; + double delta = Math.PI/16; + + float w = 0.1225f; + float h = 0.35f; + + for(int i = 0; i < 16; i++){ + v = new vector[]{put(r*Math.cos(i*delta) + w, r*Math.sin(i*delta) +h, -0.1), + put(r*Math.cos((i+1)*delta) + w, r*Math.sin((i+1)*delta) + h, -0.1), + put(r*Math.cos((i+1)*delta) + w, r*Math.sin((i+1)*delta) + h, 0.345), + put(r*Math.cos(i*delta) + w, r*Math.sin(i*delta) +h, 0.345) + }; + + tempVector.set(v[1]); + tempVector.subtract(v[0]); + tempVector0.set(v[0]); + tempVector1.set(v[1]); + tempVector3.set(v[3]); + + tempVector0.add(tempVector, -i); + tempVector3.add(tempVector, -i); + tempVector1.add(tempVector, 15 - i); + + + change(w,h,-0.1f, tempVector); + polyIndex = addPolygon(polygons, new polygon3D(v, tempVector0.myClone(),tempVector1.myClone(), tempVector3.myClone(), mainThread.textures[51], 1f,1f,1)); + polygons[polyIndex].textureScaledWidth = (int)(polygons[polyIndex].myTexture.width/16); + polygons[polyIndex].createShadeSpan(tempVector, v[0], v[1]); + + } + + double r2 = 0.21; + for(int i = 0; i < 16; i++){ + v = new vector[]{put(r2*Math.cos(i*delta) + w, r2*Math.sin(i*delta) +h, 0.345), + put(r2*Math.cos((i+1)*delta) + w, r2*Math.sin((i+1)*delta) + h, 0.345), + put(r2*Math.cos((i+1)*delta) + w, r2*Math.sin((i+1)*delta) + h, -0.1), + put(r2*Math.cos(i*delta) + w, r2*Math.sin(i*delta) +h, -0.1) + }; + + tempVector.set(v[1]); + tempVector.subtract(v[0]); + tempVector0.set(v[0]); + tempVector1.set(v[1]); + tempVector3.set(v[3]); + + tempVector0.add(tempVector, -i); + tempVector3.add(tempVector, -i); + tempVector1.add(tempVector, 15 - i); + + polyIndex = addPolygon(polygons, new polygon3D(v, tempVector0.myClone(),tempVector1.myClone(), tempVector3.myClone(), mainThread.textures[51], 1f,1f,1)); + } + + for(int i = 0; i < 16; i ++){ + v = new vector[]{put(r*Math.cos((i+1)*delta) + w, r*Math.sin((i+1)*delta) + h, -0.1), + put(r*Math.cos(i*delta) + w, r*Math.sin(i*delta) +h, -0.1), + put(r2*Math.cos(i*delta) + w, r2*Math.sin(i*delta) +h, -0.1), + put(r2*Math.cos((i+1)*delta) + w, r2*Math.sin((i+1)*delta) + h, -0.1) + }; + addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,1f,1)); + } + + for(int i = 0; i < 16; i ++){ + v = new vector[]{put(r2*Math.cos((i+1)*delta) + w, r2*Math.sin((i+1)*delta) + h, 0.345), + put(r2*Math.cos(i*delta) + w, r2*Math.sin(i*delta) +h, 0.345), + put(r*Math.cos(i*delta) + w, r*Math.sin(i*delta) +h, 0.345), + put(r*Math.cos((i+1)*delta) + w, r*Math.sin((i+1)*delta) + h, 0.345) + }; + addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,1f,1)); + } + + v = new vector[17]; + + for(int i = 0; i < 17; i++){ + v[i] = put(r*Math.cos(i*delta) + w, r*Math.sin(i*delta) +h, 0.33); + } + tempVector.set(v[0]); + tempVector.y -=0.2; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[16], tempVector.myClone(), mainThread.textures[51], 1,1f,1)); + polygons[polyIndex].shadowBias = 9500; + + v = new vector[]{put(0.3325, 0.35, 0.33), put(-0.0875, 0.35, 0.33), put(-0.0875, 0.30, 0.33), put(0.3325, 0.30, 0.33)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,1f,1)); + polygons[polyIndex].shadowBias = 9500; + + + v = new vector[17]; + for(int i = 0; i < 17; i++){ + v[16 - i] = put(r*Math.cos(i*delta) + w, r*Math.sin(i*delta) +h, -0.09); + } + tempVector.set(v[0]); + tempVector.y -=0.2; + addPolygon(polygons, new polygon3D(v, v[0], v[16], tempVector.myClone(), mainThread.textures[12], 1,1,1)); + + tempVector0.set(v[0]); + tempVector1.set(v[16]); + v = new vector[]{put(0.3325, 0.30, -0.09),put(-0.0875, 0.30, -0.09), put(-0.0875, 0.35, -0.09), put(0.3325, 0.35, -0.09)}; + polyIndex = addPolygon(polygons, new polygon3D(v, tempVector0.myClone(), tempVector1.myClone(), tempVector.myClone(), mainThread.textures[12], 1,1f,1)); + + v = new vector[]{put(w - 0.11, 0.48, -0.091), put(w + 0.11, 0.48, -0.091), put(w + 0.11, 0.3, -0.091), put(w - 0.11, 0.3, -0.091)}; + addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[52], 1,0.8f,1)); + + v = new vector[]{put(w - 0.11, 0.49, -0.092), put(w + 0.11, 0.49, -0.092), put(w + 0.11, 0.47, -0.092), put(w - 0.11, 0.47, -0.092)}; + addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[doorTextureIndex], 3,0.5f,1)); + + + v = new vector[]{put(-0.32, 0.41, 0.31), put(-0.08, 0.41, 0.31), put(-0.08, 0.41, -0.06), put(-0.32, 0.41, -0.06)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,1f,1)); + + v = new vector[]{put(-0.32, 0.41, 0.31), put(-0.32, 0.41, -0.06), put(-0.33, 0.405, -0.07), put(-0.33, 0.405, 0.32)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,1f,1)); + + + v = new vector[]{put(-0.33, 0.405, -0.07), put(-0.32, 0.41, -0.06), put(-0.08, 0.41, -0.06), put(-0.06, 0.405, -0.07)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,1f,1)); + + + v = new vector[]{put(-0.32, 0.41, 0.31), put(-0.33, 0.405, 0.32), put(-0.06, 0.405, 0.32), put(-0.08, 0.41, 0.31)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,1f,1)); + + + v = new vector[]{put(-0.06, 0.405, 0.32), put(-0.33, 0.405, 0.32), put(-0.33, 0.3, 0.32), put(-0.06, 0.3, 0.32) }; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,1f,1)); + + + v = new vector[]{put(-0.06, 0.3, -0.07), put(-0.33, 0.3, -0.07), put(-0.33, 0.405, -0.07) , put(-0.06, 0.405, -0.07)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,1f,1)); + + + v = new vector[]{put(-0.33, 0.405, 0.32), put(-0.33, 0.405, -0.07), put(-0.33, 0.3, -0.07), put(-0.33, 0.3, 0.32)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,1f,1)); + + + //create crane start -------------------------------------------- + double theta = Math.PI/32; + r = 0.08; + double angleOffset = Math.PI/4*5 - 0.06; + int startIndex = polyIndex+1; + + + float startz = 0.13f; + float startx = 0.24f; + + start.y+=0.61f; + start.z-=startz; + start.x+=startx; + + start.z -=0.08f; + tempVector0 = new vector(0,0,0); + tempVector1 = new vector(0,0,0); + tempVector2 = new vector(0,0,0); + tempVector3 = new vector(0,0,0); + + for(int i = 0; i < 18; i++){ + v = new vector[]{put(r*Math.cos((i+1)*theta + angleOffset), 0.04, r*Math.sin((i+1)*theta + angleOffset)), + put(r*Math.cos(i*theta + angleOffset), 0.04, r*Math.sin(i*theta + angleOffset)), + put(r*Math.cos(i*theta + angleOffset), 0.09, r*Math.sin(i*theta + angleOffset)), + put(r*Math.cos((i+1)*theta + angleOffset), 0.09, r*Math.sin((i+1)*theta + angleOffset)) + }; + + if(i == 0){ + + tempVector1 = v[2].myClone(); + } + + if(i == 17){ + + tempVector3 = v[3].myClone(); + } + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[upperBodyTExture], 1,1,1)); + + } + start.z +=0.08f; + + float the_x = tempVector1.x; + float the_y = tempVector1.y; + float the_z = tempVector1.z; + + v = new vector[]{new vector(the_x, the_y, the_z + 0.1f), tempVector1.myClone(), new vector(the_x, the_y - 0.05f, the_z), new vector(the_x, the_y - 0.05f, the_z + 0.1f) }; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[upperBodyTExture], 1,1,1)); + tempVector0 = new vector(the_x, the_y, the_z + 0.1f); + + + float the_x1 = tempVector3.x; + float the_y1 = tempVector3.y; + float the_z1 = tempVector3.z; + + v = new vector[]{tempVector3.myClone(), new vector(the_x1, the_y1, the_z1 + 0.1f), new vector(the_x1, the_y1-0.05f, the_z1 + 0.1f), new vector(the_x1, the_y1-0.05f, the_z1)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[upperBodyTExture], 1,1,1)); + tempVector2 = new vector(the_x1, the_y1, the_z1 + 0.1f); + + + start.z -=0.08f; + v = new vector[21]; + for(int i = 0; i < 19; i++){ + v[i] = put(r*Math.cos((18-i)*theta + angleOffset), 0.09, r*Math.sin((18-i)*theta + angleOffset)); + } + v[19] = tempVector0.myClone(); + v[20] = tempVector2.myClone(); + + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[upperBodyTExture], 2,2,1)); + polygons[polyIndex].Ambient_I -=11; + polygons[polyIndex].shadowBias = 10000; + start.z +=0.08f; + + v = new vector[]{tempVector2.myClone(), tempVector0.myClone(), new vector(tempVector0.x, tempVector0.y - 0.08f, tempVector0.z), new vector(tempVector2.x, tempVector2.y - 0.08f, tempVector2.z)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[upperBodyTExture], 2,2,1)); + + v = new vector[]{new vector(the_x1, tempVector0.y+0.05f, tempVector0.z-0.07f), new vector(the_x1, tempVector0.y+0.05f, tempVector0.z - 0.015f), new vector(the_x1, the_y1, tempVector0.z), new vector(the_x1, the_y1, tempVector0.z - 0.08f)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[upperBodyTExture], 2,2,1)); + + v = new vector[]{new vector(the_x1-0.05f, the_y1, tempVector0.z - 0.08f) , new vector(the_x1-0.05f, the_y1, tempVector0.z), new vector(the_x1 - 0.05f, tempVector0.y+0.05f, tempVector0.z - 0.015f) , new vector(the_x1 - 0.05f, tempVector0.y+0.05f, tempVector0.z-0.07f)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[upperBodyTExture], 2,2,1)); + + v = new vector[]{new vector(the_x1 - 0.05f, tempVector0.y+0.05f, tempVector0.z-0.07f), new vector(the_x1, tempVector0.y+0.05f, tempVector0.z-0.07f), new vector(the_x1, the_y1, tempVector0.z - 0.08f), new vector(the_x1- 0.05f, the_y1, tempVector0.z - 0.08f) }; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[upperBodyTExture], 2,2,1)); + + v = new vector[]{new vector(the_x1-0.05f, tempVector0.y+0.05f, tempVector0.z - 0.015f), new vector(the_x1, tempVector0.y+0.05f, tempVector0.z - 0.015f), new vector(the_x1, tempVector0.y+0.05f, tempVector0.z-0.07f), new vector(the_x1 - 0.05f, tempVector0.y+0.05f, tempVector0.z-0.07f)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[upperBodyTExture], 2,2,1)); + + v = new vector[]{new vector(the_x1+0.001f, tempVector0.y+0.045f, tempVector0.z-0.05f), new vector(the_x1+0.001f, tempVector0.y+0.045f, tempVector0.z - 0.02f), new vector(the_x1+0.001f, the_y1, tempVector0.z - 0.005f), new vector(the_x1+0.001f, the_y1+0.01f, tempVector0.z - 0.05f)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[45], 2,2,1)); + + v = new vector[]{new vector(the_x1, tempVector0.y+0.05f, tempVector0.z - 0.015f), new vector(the_x1 - 0.05f, tempVector0.y+0.05f, tempVector0.z - 0.015f), new vector(the_x1-0.05f, the_y1, tempVector0.z), new vector(the_x1, the_y1, tempVector0.z)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[46], 1,1,1)); + + v = new vector[]{new vector(the_x1-0.051f, the_y1+0.01f, tempVector0.z - 0.05f), new vector(the_x1-0.051f, the_y1, tempVector0.z - 0.005f), new vector(the_x1-0.051f, tempVector0.y+0.045f, tempVector0.z - 0.02f), new vector(the_x1-0.051f, tempVector0.y+0.045f, tempVector0.z-0.05f) }; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[45], 2,2,1)); + + + + angleOffset = Math.PI * 1.65; + theta = Math.PI/22; + r = 0.02; + + h = 0.11f; + float l = -0.12f; + + for(int i = 0; i < 16; i++){ + v = new vector[]{ put(0.005f, r*Math.cos((i+1)*theta + angleOffset) + h, r*Math.sin((i+1)*theta + angleOffset) + l), + put( 0.005f, r*Math.cos(i*theta + angleOffset) + h, r*Math.sin(i*theta + angleOffset) + l), + put( -0.005, r*Math.cos(i*theta + angleOffset) + h, r*Math.sin(i*theta + angleOffset) + l), + put(-0.005f, r*Math.cos((i+1)*theta + angleOffset) + h, r*Math.sin((i+1)*theta + angleOffset) + l) + }; + + if(i ==0){ + the_x = v[2].x; + the_y = v[2].y; + the_z = v[2].z; + } + if(i == 15){ + the_x1 = v[0].x; + the_y1 = v[0].y; + the_z1 = v[0].z; + } + + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1,1,1)); + } + + + v = new vector[]{new vector(the_x, the_y, the_z), new vector(the_x + 0.01f, the_y, the_z), new vector(the_x + 0.01f, the_y- 0.08f, the_z ), new vector(the_x, the_y- 0.08f, the_z)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1,10,1)); + + v = new vector[]{new vector(the_x1, the_y1, the_z1), new vector(the_x1 - 0.01f, the_y1, the_z1), new vector(the_x1 - 0.01f, the_y1-0.08f, the_z1 + 0.01f), new vector(the_x1, the_y1-0.08f, the_z1 + 0.01f)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1,10,1)); + + v = new vector[19]; + for(int i = 0; i < 17; i ++){ + v[i] = put(-0.005f, r*Math.cos((16-i)*theta + angleOffset)+h, r*Math.sin((16-i)*theta + angleOffset)+l); + } + v[17] = new vector(v[0].x, the_y- 0.08f, the_z); + v[18] = new vector(v[0].x, the_y1- 0.08f, the_z1 + 0.01f); + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1,1,1)); + + v = new vector[19]; + for(int i = 0; i < 19; i ++){ + v[i] = polygons[polyIndex].vertex3D[18- i].myClone(); + v[i].x +=0.01f; + } + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1,1,1)); + + start.x-=0.05; + + for(int i = 0; i < 16; i++){ + v = new vector[]{ put(0.005f, r*Math.cos((i+1)*theta + angleOffset) + h, r*Math.sin((i+1)*theta + angleOffset) + l), + put( 0.005f, r*Math.cos(i*theta + angleOffset) + h, r*Math.sin(i*theta + angleOffset) + l), + put( -0.005, r*Math.cos(i*theta + angleOffset) + h, r*Math.sin(i*theta + angleOffset) + l), + put(-0.005f, r*Math.cos((i+1)*theta + angleOffset) + h, r*Math.sin((i+1)*theta + angleOffset) + l) + }; + + if(i ==0){ + the_x = v[2].x; + the_y = v[2].y; + the_z = v[2].z; + } + if(i == 15){ + the_x1 = v[0].x; + the_y1 = v[0].y; + the_z1 = v[0].z; + } + + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1,1,1)); + } + + v = new vector[]{new vector(the_x, the_y, the_z), new vector(the_x + 0.01f, the_y, the_z), new vector(the_x + 0.01f, the_y- 0.08f, the_z), new vector(the_x, the_y- 0.08f, the_z)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1,10,1)); + + v = new vector[]{new vector(the_x1, the_y1, the_z1), new vector(the_x1 - 0.01f, the_y1, the_z1), new vector(the_x1 - 0.01f, the_y1-0.08f, the_z1 + 0.01f), new vector(the_x1, the_y1-0.08f, the_z1 + 0.01f)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1,10,1)); + + v = new vector[19]; + for(int i = 0; i < 17; i ++){ + v[i] = put(-0.005f, r*Math.cos((16-i)*theta + angleOffset)+h, r*Math.sin((16-i)*theta + angleOffset)+l); + } + v[17] = new vector(v[0].x, the_y- 0.08f, the_z); + v[18] = new vector(v[0].x, the_y1- 0.08f, the_z1 + 0.01f); + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1,1,1)); + + v = new vector[19]; + for(int i = 0; i < 19; i ++){ + v[i] = polygons[polyIndex].vertex3D[18- i].myClone(); + v[i].x +=0.01f; + } + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1,1,1)); + + start.x+=0.05; + + //crane arm + tempVector.set(start); + start.set(0,0,0); + armCenter = new vector(-0.023f, 0.12f, -0.11f); + + int armIndexStart = polyIndex + 1; + v = new vector[]{put(-0.02f,0.025f, 0.23), put(0.02f,0.025f, 0.23), put(0.02f,0.025f, -0.02), put(-0.02f,0.025f, -0.02)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[upperBodyTExture], 10,10,1)); + polygons[polyIndex].shadowBias = 100000; + + + v = new vector[]{ put(-0.02f,-0.015f, -0.02), put(0.02f,-0.015f, -0.02), put(0.02f,-0.015f, 0.23), put(-0.02f,-0.015f, 0.23)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[upperBodyTExture], 10,10,1)); + polygons[polyIndex].shadowBias = 100000; + + v = new vector[]{put(0.02f,0.025f, -0.02), put(0.02f,0.025f, 0.23), put(0.02f,-0.015f, 0.23), put(0.02f,-0.015f, -0.02)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[upperBodyTExture], 10,10,1)); + polygons[polyIndex].shadowBias = 100000; + + v = new vector[]{put(-0.02f,-0.015f, -0.02), put(-0.02f,-0.015f, 0.23), put(-0.02f,0.025f, 0.23), put(-0.02f,0.025f, -0.02)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[upperBodyTExture], 10,10,1)); + polygons[polyIndex].shadowBias = 100000; + + r = 0.02f; + theta = Math.PI/16; + angleOffset = Math.PI; + h = 0.005f; + l = -0.02f; + + for(int i = 0; i < 16; i++){ + v = new vector[]{ put(0.02f, r*Math.cos((i+1)*theta + angleOffset) + h, r*Math.sin((i+1)*theta + angleOffset) + l), + put( 0.02f, r*Math.cos(i*theta + angleOffset) + h, r*Math.sin(i*theta + angleOffset) + l), + put(-0.02f, r*Math.cos(i*theta + angleOffset) + h, r*Math.sin(i*theta + angleOffset) + l), + put(-0.02f, r*Math.cos((i+1)*theta + angleOffset) + h, r*Math.sin((i+1)*theta + angleOffset) + l) + }; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[upperBodyTExture], 10,10,1)); + } + + v = new vector[17]; + for(int i = 0; i < 17; i ++){ + v[i] = put(-0.02f, r*Math.cos((16-i)*theta + angleOffset)+h, r*Math.sin((16-i)*theta + angleOffset)+l); + } + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[upperBodyTExture], 10,10,1)); + + v = new vector[17]; + for(int i = 0; i < 17; i ++){ + v[i] = polygons[polyIndex].vertex3D[16- i].myClone(); + v[i].x +=0.04f; + } + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[upperBodyTExture], 10,10,1)); + + v = new vector[]{put(0.02f,0.025f, 0.23), put(-0.02f,0.025f, 0.23), put(-0.02f,-0.015f, 0.23), put(0.02f,-0.015f, 0.23)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[upperBodyTExture], 10,10,1)); + + v = new vector[]{put(-0.015f,0.02f, 0.27), put(0.015f,0.02f, 0.27), put(0.015f,0.02f, 0.03), put(-0.015f,0.02f, 0.03)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[47], 10,10,1)); + + v = new vector[]{ put(-0.015f,-0.01f, 0.03), put(0.015f,-0.01f, 0.03), put(0.015f,-0.01f, 0.27), put(-0.015f,-0.01f, 0.27)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[47], 10,10,1)); + + v = new vector[]{put(0.015f,0.02f, 0.03), put(0.015f,0.02f, 0.27), put(0.015f,-0.01f, 0.27), put(0.015f,-0.01f, 0.03)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[47], 10,10,1)); + + v = new vector[]{put(-0.015f,-0.01f, 0.03), put(-0.015f,-0.01f, 0.27), put(-0.015f,0.02f, 0.27), put(-0.015f,0.02f, 0.03)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[47], 10,10,1)); + + + v = new vector[]{put(-0.02f,0.025f, 0.29), put(0.02f,0.025f, 0.29), put(0.02f,0.025f, 0.27), put(-0.02f,0.025f, 0.27)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[armTop], 1.2f,1f,1)); + + v = new vector[]{put(0.02f,0.025f, 0.27), put(0.02f,0.025f, 0.29), put(0.02f,0f, 0.29), put(0.02f,-0.015f, 0.27)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[armTop], 1f,1f,1)); + + v = new vector[]{put(-0.02f,-0.015f, 0.27), put(-0.02f,0f, 0.29), put(-0.02f,0.025f, 0.29), put(-0.02f,0.025f, 0.27)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[armTop], 1f,1f,1)); + + v = new vector[]{put(0.02f,0.025f, 0.29), put(-0.02f,0.025f, 0.29), put(-0.02f,0, 0.29), put(0.02f,0, 0.29)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[armTop], 1.2f,1f,1)); + + v = new vector[]{put(-0.02f,0.025f, 0.27), put(0.02f,0.025f, 0.27), put(0.02f,-0.015f, 0.27), put(-0.02f,-0.015f, 0.27)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[armTop], 1.2f,1f,1)); + + v = new vector[]{put(0.02f,0, 0.29), put(-0.02f,0, 0.29), put(-0.02f,-0.015f, 0.27), put(0.02f,-0.015f, 0.27)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[armTop], 1.2f,1f,1)); + + int armIndexEnd = polyIndex; + + for(int i = armIndexStart; i <= armIndexEnd; i++){ + polygons[i].origin = polygons[i].origin.myClone(); + polygons[i].origin.rotate_YZ(310); + polygons[i].origin.add(tempVector); + polygons[i].origin.add(armCenter); + + polygons[i].bottomEnd = polygons[i].bottomEnd.myClone(); + polygons[i].bottomEnd.rotate_YZ(310); + polygons[i].bottomEnd.add(tempVector); + polygons[i].bottomEnd.add(armCenter); + + polygons[i].rightEnd = polygons[i].rightEnd.myClone(); + polygons[i].rightEnd.rotate_YZ(310); + polygons[i].rightEnd.add(tempVector); + polygons[i].rightEnd.add(armCenter); + + + + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + polygons[i].vertex3D[j].rotate_YZ(310); + polygons[i].vertex3D[j].add(tempVector); + polygons[i].vertex3D[j].add(armCenter); + } + + polygons[i].findNormal(); + polygons[i].findDiffuse(); + polygons[i].diffuse_I = 0; + } + + //crane pillar + pillarCenter = new vector(-0.025f, 0.09f, -0.04f); + int pillarIndexStart = polyIndex + 1; + + theta = Math.PI/12; + r = 0.01; + + for(int i = 0; i < 24; i++){ + v = new vector[]{put(r*Math.cos((i+1)*theta) , r*Math.sin((i+1)*theta), 0.08), + put(r*Math.cos(i*theta) , r*Math.sin(i*theta), 0.08), + put(r*Math.cos(i*theta) , r*Math.sin(i*theta), 0 ), + put(r*Math.cos((i+1)*theta), r*Math.sin((i+1)*theta), 0), + + }; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[upperBodyTExture], 4f,4f,1)); + } + + v = new vector[24]; + for(int i = 0; i < 24; i ++){ + v[i] = put(r*Math.cos(i*theta), r*Math.sin(i*theta), 0.08); + } + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[upperBodyTExture], 4f,4f,1)); + + r = 0.005; + for(int i = 0; i < 24; i++){ + v = new vector[]{put(r*Math.cos((i+1)*theta), r*Math.sin((i+1)*theta), 0.18), + put(r*Math.cos(i*theta), r*Math.sin(i*theta), 0.18), + put(r*Math.cos(i*theta), r*Math.sin(i*theta), 0.08 ), + put(r*Math.cos((i+1)*theta), r*Math.sin((i+1)*theta), 0.08), + + }; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[29], 4f,4f,1)); + } + + int pillarIndexEnd = polyIndex; + + for(int i = pillarIndexStart; i <= pillarIndexEnd; i++){ + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + polygons[i].vertex3D[j].rotate_YZ(290); + polygons[i].vertex3D[j].add(tempVector); + polygons[i].vertex3D[j].add(pillarCenter); + + polygons[i].findNormal(); + polygons[i].findDiffuse(); + } + } + + + + int endIndex = polyIndex; + + start.set(tempVector); + start.y-=0.61f; + start.z+=startz; + start.x-=startx; + + h = -0.3f; + + for(int i = startIndex; i <= endIndex; i++){ + polygons[i].origin = polygons[i].origin.myClone(); + polygons[i].origin.subtract(start); + polygons[i].origin.rotate_XZ(270); + polygons[i].origin.add(start); + polygons[i].origin.y+=h; + + polygons[i].bottomEnd = polygons[i].bottomEnd.myClone(); + polygons[i].bottomEnd.subtract(start); + polygons[i].bottomEnd.rotate_XZ(270); + polygons[i].bottomEnd.add(start); + polygons[i].bottomEnd.y+=h; + + polygons[i].rightEnd = polygons[i].rightEnd.myClone(); + polygons[i].rightEnd.subtract(start); + polygons[i].rightEnd.rotate_XZ(270); + polygons[i].rightEnd.add(start); + polygons[i].rightEnd.y+=h; + + + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + polygons[i].vertex3D[j].subtract(start); + polygons[i].vertex3D[j].rotate_XZ(270); + polygons[i].vertex3D[j].add(start); + polygons[i].vertex3D[j].y+=h; + + polygons[i].findNormal(); + polygons[i].findDiffuse(); + } + + + } + + //create crane end----------------------------------------------- + + //create vent1 + ventCenter1.set(centre); + ventCenter1.x-=0.21f; + ventCenter1.z+=0.2f; + + r = 0.05; + delta = Math.PI/16; + start.set(ventCenter1); + + v = new vector[32]; + for(int i = 0; i < 32; i++){ + v[31 - i] = put(r*Math.cos(i*delta), 0.411, r*Math.sin(i*delta)); + } + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], null, 1,1f,4)); + + v = new vector[32]; + for(int i = 0; i < 32; i++){ + v[31 - i] = put(r*Math.cos(i*delta), 0.341, r*Math.sin(i*delta)); + } + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,1f,1)); + + + for(int i = 0; i < 32; i++){ + v = new vector[]{put(r*Math.cos(i*delta), 0.311, r*Math.sin(i*delta)), + put(r*Math.cos((i +1)*delta), 0.311, r*Math.sin((i + 1)*delta)), + put(r*Math.cos((i +1)*delta), 0.411, r*Math.sin((i + 1)*delta)), + put(r*Math.cos(i*delta), 0.411, r*Math.sin(i*delta)) + }; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,1f,1)); + } + + r = 0.0075f; + r2 = 0.0001f; + for(int i = 0; i < 32; i++){ + v = new vector[]{put(r2*Math.cos(i*delta), 0.4, r2*Math.sin(i*delta)), + put(r2*Math.cos((i +1)*delta), 0.4, r2*Math.sin((i + 1)*delta)), + put(r*Math.cos((i +1)*delta), 0.38, r*Math.sin((i + 1)*delta)), + put(r*Math.cos(i*delta), 0.38, r*Math.sin(i*delta)) + }; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 1,1f,1)); + } + + //create vent2 + ventCenter2.set(centre); + ventCenter2.x-=0.21f; + ventCenter2.z+=0.03f; + + r = 0.05; + delta = Math.PI/16; + start.set(ventCenter2); + + v = new vector[32]; + for(int i = 0; i < 32; i++){ + v[31 - i] = put(r*Math.cos(i*delta), 0.411, r*Math.sin(i*delta)); + } + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], null, 1,1f,4)); + + v = new vector[32]; + for(int i = 0; i < 32; i++){ + v[31 - i] = put(r*Math.cos(i*delta), 0.341, r*Math.sin(i*delta)); + } + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,1f,1)); + + + for(int i = 0; i < 32; i++){ + v = new vector[]{put(r*Math.cos(i*delta), 0.311, r*Math.sin(i*delta)), + put(r*Math.cos((i +1)*delta), 0.311, r*Math.sin((i + 1)*delta)), + put(r*Math.cos((i +1)*delta), 0.411, r*Math.sin((i + 1)*delta)), + put(r*Math.cos(i*delta), 0.411, r*Math.sin(i*delta)) + }; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,1f,1)); + } + + r = 0.0075f; + r2 = 0.0001f; + for(int i = 0; i < 32; i++){ + v = new vector[]{put(r2*Math.cos(i*delta), 0.4, r2*Math.sin(i*delta)), + put(r2*Math.cos((i +1)*delta), 0.4, r2*Math.sin((i + 1)*delta)), + put(r*Math.cos((i +1)*delta), 0.38, r*Math.sin((i + 1)*delta)), + put(r*Math.cos(i*delta), 0.38, r*Math.sin(i*delta)) + }; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 1,1f,1)); + } + + start.x=0; + start.z=0; + + r = 0.04; + delta = Math.PI/15; + h = 0.38f; + + vent1 = new polygon3D[3]; + v = new vector[5]; + for(int i = 0; i < 4; i++){ + v[3 - i] = put(r*Math.cos(i*delta), h, r*Math.sin(i*delta)); + } + v[4] = put(0,h,0); + addPolygon(vent1, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1,1f,1)); + vent1[0].shadowBias = 40000; + + v = new vector[5]; + for(int i = 0; i < 4; i++){ + v[3 - i] = put(r*Math.cos((i+10)*delta), h, r*Math.sin((i+10)*delta)); + } + v[4] = put(0,h,0); + addPolygon(vent1, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1,1f,1)); + vent1[1].shadowBias = 40000; + + v = new vector[5]; + for(int i = 0; i < 4; i++){ + v[3 - i] = put(r*Math.cos((i+20)*delta), h, r*Math.sin((i+20)*delta)); + } + v[4] = put(0,h,0); + addPolygon(vent1, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1,1f,1)); + vent1[2].shadowBias = 40000; + + vent2 = new polygon3D[3]; + v = new vector[5]; + for(int i = 0; i < 4; i++){ + v[3 - i] = put(r*Math.cos(i*delta), h, r*Math.sin(i*delta)); + } + v[4] = put(0,h,0); + addPolygon(vent2, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1,1f,1)); + vent2[0].shadowBias = 40000; + + v = new vector[5]; + for(int i = 0; i < 4; i++){ + v[3 - i] = put(r*Math.cos((i+10)*delta), h, r*Math.sin((i+10)*delta)); + } + v[4] = put(0,h,0); + addPolygon(vent2, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1,1f,1)); + vent2[1].shadowBias = 40000; + + v = new vector[5]; + for(int i = 0; i < 4; i++){ + v[3 - i] = put(r*Math.cos((i+20)*delta), h, r*Math.sin((i+20)*delta)); + } + v[4] = put(0,h,0); + addPolygon(vent2, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 1,1f,1)); + vent2[2].shadowBias = 40000; + + start.set(tempVector); + start.x-=0.46; + start.z-=0.12; + + + + + v = new vector[]{put(-0.08, -0.26, 0.08), put(0.08, -0.26, 0.08), put(0.08, -0.26, -0.08), put(-0.08, -0.26, -0.08)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,1f,1)); + + v = new vector[]{put(-0.08, -0.26, -0.08), put(0.08, -0.26, -0.08), put(0.13, -0.35, -0.13), put(-0.13, -0.35, -0.13)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,1f,1)); + + v = new vector[]{put(-0.13, -0.35, 0.13), put(0.13, -0.35, 0.13), put(0.08, -0.26, 0.08), put(-0.08, -0.26, 0.08)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,1f,1)); + + v = new vector[]{put(0.08, -0.26, -0.08), put(0.08, -0.26, 0.08), put(0.13, -0.35, 0.13), put(0.13, -0.35, -0.13)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,1f,1)); + + v = new vector[]{put(-0.13, -0.35, -0.13), put(-0.13, -0.35, 0.13), put(-0.08, -0.26, 0.08), put(-0.08, -0.26, -0.08)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[51], 1,1f,1)); + + + + v = new vector[]{put(0.23, -0.3095, 0.12), put(0.31, -0.3095, 0.12), put(0.31, -0.3095, 0.11), put(0.23, -0.3095, 0.11)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[doorTextureIndex], 1,1f,1)); + polygons[polyIndex].diffuse_I-=20; + + v = new vector[]{put(0.37, -0.3095, 0.12), put(0.45, -0.3095, 0.12), put(0.45, -0.3095, 0.11), put(0.37, -0.3095, 0.11)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[doorTextureIndex], 1,1f,1)); + polygons[polyIndex].diffuse_I-=20; + + v = new vector[]{put(0.23, -0.3095, -0.09), put(0.31, -0.3095, -0.09), put(0.31, -0.3095, -0.1), put(0.23, -0.3095, -0.1)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[doorTextureIndex], 1,1f,1)); + polygons[polyIndex].diffuse_I-=20; + + v = new vector[]{put(0.37, -0.3095, -0.09), put(0.45, -0.3095, -0.09), put(0.45, -0.3095, -0.1), put(0.37, -0.3095, -0.1)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[doorTextureIndex], 1,1f,1)); + polygons[polyIndex].diffuse_I-=20; + + v = new vector[]{put(0.23, -0.3095, 0.12), put(0.24, -0.3095, 0.12), put(0.24, -0.3095, 0.04), put(0.23, -0.3095, 0.04)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[doorTextureIndex], 1,1f,1)); + polygons[polyIndex].diffuse_I-=20; + + v = new vector[]{put(0.23, -0.3095, -0.02), put(0.24, -0.3095, -0.02), put(0.24, -0.3095,-0.1), put(0.23, -0.3095, -0.1)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[doorTextureIndex], 1,1f,1)); + polygons[polyIndex].diffuse_I-=20; + + v = new vector[]{put(0.44, -0.3095, 0.12), put(0.45, -0.3095, 0.12), put(0.45, -0.3095, 0.04), put(0.44, -0.3095, 0.04)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[doorTextureIndex], 1,1f,1)); + polygons[polyIndex].diffuse_I-=20; + + v = new vector[]{put(0.44, -0.3095, -0.02), put(0.45, -0.3095, -0.02), put(0.45, -0.3095,-0.1), put(0.44, -0.3095, -0.1)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[doorTextureIndex], 1,1f,1)); + polygons[polyIndex].diffuse_I-=20; + + ventCenter1.y = 0; + vent1Clone = clonePolygons(vent1,true); + + ventCenter2.y = 0; + vent2Clone = clonePolygons(vent2,true); + + start.set(centre); + + v = new vector[]{put(-0.345, 0.3, -0.385), put(0.345, 0.3, -0.385), put(0.345, 0.28, -0.385), put(-0.345, 0.28, -0.385)}; + addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[30], 1,1f,1)); + + v = new vector[]{put(-0.345, 0.28,0.385), put(0.345, 0.28, 0.385), put(0.345, 0.3, 0.385), put(-0.345, 0.3, 0.385)}; + addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[30], 1,1f,1)); + + v = new vector[]{put(-0.38, 0.3, 0.35), put(-0.38, 0.3, -0.35), put(-0.38, 0.28, -0.35), put(-0.38, 0.28, 0.35)}; + addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[30], 1,1f,1)); + + v = new vector[]{put(0.38, 0.28, 0.35), put(0.38, 0.28, -0.35), put(0.38, 0.3, -0.35), put(0.38, 0.3, 0.35)}; + addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[30], 1,1f,1)); + + v = new vector[]{put(-0.345, 0.3, 0.385), put(-0.38, 0.3, 0.35), put(-0.38, 0.28, 0.35), put(-0.345, 0.28, 0.385)}; + addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[30], 1,1f,1)); + + v = new vector[]{put(0.345, 0.28, 0.385), put(0.38, 0.28, 0.35), put(0.38, 0.3, 0.35), put(0.345, 0.3, 0.385)}; + addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[30], 1,1f,1)); + + v = new vector[]{put(-0.345, 0.28, -0.385), put(-0.38, 0.28, -0.35), put(-0.38, 0.3, -0.35), put(-0.345, 0.3, -0.385)}; + addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[30], 1,1f,1)); + + v = new vector[]{put(0.345, 0.3, -0.385), put(0.38, 0.3, -0.35), put(0.38, 0.28, -0.35), put(0.345, 0.28, -0.385)}; + addPolygon(polygons, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[30], 1,1f,1)); + + if(teamNo != 0){ + for(int i = 0; i < polygons.length; i++){ + if(polygons[i].myTexture == null) + continue; + + if(polygons[i].myTexture.ID == 42) + polygons[i].myTexture = mainThread.textures[10]; + + if(polygons[i].myTexture.ID == upperBodyTExture) + polygons[i].myTexture = mainThread.textures[48]; + + if(polygons[i].myTexture.ID == 46) + polygons[i].myTexture = mainThread.textures[50]; + + if(polygons[i].myTexture.ID == armTop) + polygons[i].myTexture = mainThread.textures[49]; + } + } + + for(int i = 0; i < polygons.length; i++){ + polygons[i].findDiffuse(); + polygons[i].parentObject = this; + + } + } + + + + //add a polygon to the mesh + public int addPolygon(polygon3D[] polys, polygon3D poly){ + for(int i = 0; i < polys.length; i++){ + if(polys[i] == null){ + polys[i] = poly; + return i; + } + } + return -1; + } + + //update the model + public void update(){ + + //update tech tree info + canBuildPowerPlant = theBaseInfo.canBuildPowerPlant; + canBuildRefinery = theBaseInfo.canBuildRefinery; + canBuildFactory = theBaseInfo.canBuildFactory; + canBuildCommunicationCenter = theBaseInfo.canBuildCommunicationCenter; + canBuildGunTurret = theBaseInfo.canBuildGunTurret; + canBuildMissileTurret = theBaseInfo.canBuildMissileTurret; + canBuildTechCenter = theBaseInfo.canBuildTechCenter; + + if(canBuildRefinery == false && refineryProgress <=240){ + cancelBuilding(); + } + + if(canBuildFactory == false && factoryProgress <=240){ + cancelBuilding(); + } + + if(canBuildCommunicationCenter == false && communicationCenterProgress <=240){ + cancelBuilding(); + } + + if(canBuildGunTurret == false && gunTurretProgress <=240){ + cancelBuilding(); + } + + if(canBuildMissileTurret == false && missileTurretProgress <=240) + cancelBuilding(); + + if(canBuildTechCenter == false && techCenterProgress <= 240) + cancelBuilding(); + + if(underAttackCountDown > 0) + underAttackCountDown--; + + + //process emerging from ground animation + if(centre.y < -0.79f){ + centre.y+=0.01; + for(int i = 0; i < polygons.length; i++){ + polygons[i].origin.y+=0.01; + polygons[i].rightEnd.y+=0.01; + polygons[i].bottomEnd.y+=0.01; + + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + polygons[i].vertex3D[j].y+=0.01; + } + } + + + shadowvertex0.y+=0.01; + shadowvertex1.y+=0.01; + shadowvertex2.y+=0.01; + shadowvertex3.y+=0.01; + + if(centre.y >= -0.79f){ + centre.y = -0.79f; + start = centre.myClone(); + tempCentre = start.myClone(); + + makePolygons(); + } + + if(centre.y > -1.2f){ + emergingStarted = true; + isSelectable = true; + } + + //the building is invulnerable during emerging stage + currentHP = maxHP; + } + + + //check if construction yard has been destroyed + if(currentHP <= 0){ + countDownToDeath--; + + if(countDownToDeath <= 0){ + //spawn an explosion when the object is destroyed + if(countDownToDeath == 0){ + float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount]; + tempFloat[0] = centre.x; + tempFloat[1] = centre.y + 0.45f; + tempFloat[2] = centre.z; + tempFloat[3] = 4f; + tempFloat[4] = 1; + tempFloat[5] = 0; + tempFloat[6] = 7; + tempFloat[7] = this.height; + theAssetManager.explosionCount++; + cancelBuilding(); + + if(needToDrawDeploymentGrid){ + mainThread.pc.isDeployingBuilding = false; + mainThread.pc.selectedConstructionYard = null; + } + } + + theAssetManager.removeObject(this); + + mainThread.gridMap.tiles[tileIndex[0]][0] = null; + mainThread.gridMap.tiles[tileIndex[1]][0] = null; + mainThread.gridMap.tiles[tileIndex[2]][0] = null; + mainThread.gridMap.tiles[tileIndex[3]][0] = null; + mainThread.gridMap.tiles[tileIndex[4]][0] = null; + mainThread.gridMap.tiles[tileIndex[5]][0] = null; + mainThread.gridMap.tiles[tileIndex[6]][0] = null; + mainThread.gridMap.tiles[tileIndex[7]][0] = null; + mainThread.gridMap.tiles[tileIndex[8]][0] = null; + + + mainThread.gridMap.tiles[tileIndex[0]][1] = null; + mainThread.gridMap.tiles[tileIndex[1]][1] = null; + mainThread.gridMap.tiles[tileIndex[2]][1] = null; + mainThread.gridMap.tiles[tileIndex[3]][1] = null; + mainThread.gridMap.tiles[tileIndex[4]][1] = null; + mainThread.gridMap.tiles[tileIndex[5]][1] = null; + mainThread.gridMap.tiles[tileIndex[6]][1] = null; + mainThread.gridMap.tiles[tileIndex[7]][1] = null; + mainThread.gridMap.tiles[tileIndex[8]][1] = null; + + mainThread.gridMap.tiles[tileIndex[0]][2] = null; + mainThread.gridMap.tiles[tileIndex[1]][2] = null; + mainThread.gridMap.tiles[tileIndex[2]][2] = null; + mainThread.gridMap.tiles[tileIndex[3]][2] = null; + mainThread.gridMap.tiles[tileIndex[4]][2] = null; + mainThread.gridMap.tiles[tileIndex[5]][2] = null; + mainThread.gridMap.tiles[tileIndex[6]][2] = null; + mainThread.gridMap.tiles[tileIndex[7]][2] = null; + mainThread.gridMap.tiles[tileIndex[8]][2] = null; + + mainThread.gridMap.tiles[tileIndex[0]][3] = null; + mainThread.gridMap.tiles[tileIndex[1]][3] = null; + mainThread.gridMap.tiles[tileIndex[2]][3] = null; + mainThread.gridMap.tiles[tileIndex[3]][3] = null; + mainThread.gridMap.tiles[tileIndex[4]][3] = null; + mainThread.gridMap.tiles[tileIndex[5]][3] = null; + mainThread.gridMap.tiles[tileIndex[6]][3] = null; + mainThread.gridMap.tiles[tileIndex[7]][3] = null; + mainThread.gridMap.tiles[tileIndex[8]][3] = null; + + + mainThread.gridMap.tiles[tileIndex[0]][4] = null; + mainThread.gridMap.tiles[tileIndex[1]][4] = null; + mainThread.gridMap.tiles[tileIndex[2]][4] = null; + mainThread.gridMap.tiles[tileIndex[3]][4] = null; + mainThread.gridMap.tiles[tileIndex[4]][4] = null; + mainThread.gridMap.tiles[tileIndex[5]][4] = null; + mainThread.gridMap.tiles[tileIndex[6]][4] = null; + mainThread.gridMap.tiles[tileIndex[7]][4] = null; + mainThread.gridMap.tiles[tileIndex[8]][4] = null; + + theBaseInfo.numberOfConstructionYard--; + + if(attacker.teamNo != teamNo) + attacker.experience+=50; + + return; + }else{ + + float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount]; + tempFloat[0] = centre.x + (float)Math.random()*0.6f - 0.3f; + tempFloat[1] = centre.y + 0.45f; + tempFloat[2] = centre.z + (float)Math.random()*0.6f - 0.3f; + tempFloat[3] = 1.5f; + tempFloat[4] = 1; + tempFloat[5] = 0; + tempFloat[6] = 6 + (gameData.getRandom()%4); + tempFloat[7] = this.height; + theAssetManager.explosionCount++; + + + } + } + + if(isRepairing && currentHP >0){ + if(mainThread.frameIndex%8==0 && theBaseInfo.currentCredit > 0 && currentHP maxHP) + currentHP = maxHP; + } + } + + //process building event + + if(!(theBaseInfo.lowPower && mainThread.frameIndex%2==0)){ + if(powerPlantProgress < 240){ + if(theBaseInfo.currentCredit >0){ + + theBaseInfo.currentCredit--; + creditSpentOnBuilding++; + powerPlantProgress = 240 * creditSpentOnBuilding/500; + } + }else if(refineryProgress < 240){ + if(theBaseInfo.currentCredit >0){ + + theBaseInfo.currentCredit--; + creditSpentOnBuilding++; + refineryProgress = 240 * creditSpentOnBuilding/1200; + } + }else if(factoryProgress < 240){ + if(theBaseInfo.currentCredit >0){ + + theBaseInfo.currentCredit--; + creditSpentOnBuilding++; + factoryProgress = 240 * creditSpentOnBuilding/1400; + } + }else if(communicationCenterProgress < 240){ + if(theBaseInfo.currentCredit >0){ + theBaseInfo.currentCredit--; + creditSpentOnBuilding++; + communicationCenterProgress = 240 * creditSpentOnBuilding/1000; + } + }else if(gunTurretProgress < 240){ + if(theBaseInfo.currentCredit >0){ + theBaseInfo.currentCredit--; + creditSpentOnBuilding++; + gunTurretProgress = 240 * creditSpentOnBuilding/400; + } + }else if(missileTurretProgress < 240){ + if(theBaseInfo.currentCredit >0){ + theBaseInfo.currentCredit--; + creditSpentOnBuilding++; + missileTurretProgress = 240 * creditSpentOnBuilding/750; + } + }else if(techCenterProgress < 240){ + if(theBaseInfo.currentCredit >0){ + theBaseInfo.currentCredit--; + creditSpentOnBuilding++; + techCenterProgress = 240 * creditSpentOnBuilding/1500; + } + } + } + + //mark itself on obstacle map + mainThread.gridMap.currentObstacleMap[tileIndex[0]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[1]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[2]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[3]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[4]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[5]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[6]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[7]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[8]] = false; + + + //update center in camera coordinate + tempCentre.set(centre); + tempCentre.subtract(camera.position); + tempCentre.rotate_XZ(camera.XZ_angle); + tempCentre.rotate_YZ(camera.YZ_angle); + tempCentre.updateLocation(); + + theAssetManager = mainThread.theAssetManager; + + //test if the object is visible in camera point of view + if(visibleBoundary.contains(tempCentre.screenX, tempCentre.screenY) && isRevealed){ + visible = true; + + if(screenBoundary.contains(tempCentre.screenX, tempCentre.screenY)) + withinViewScreen = true; + else + withinViewScreen = false; + + tempshadowvertex0.set(shadowvertex0); + tempshadowvertex0.subtract(camera.position); + tempshadowvertex0.rotate_XZ(camera.XZ_angle); + tempshadowvertex0.rotate_YZ(camera.YZ_angle); + tempshadowvertex0.updateLocation(); + + tempshadowvertex1.set(shadowvertex1); + tempshadowvertex1.subtract(camera.position); + tempshadowvertex1.rotate_XZ(camera.XZ_angle); + tempshadowvertex1.rotate_YZ(camera.YZ_angle); + tempshadowvertex1.updateLocation(); + + tempshadowvertex2.set(shadowvertex2); + tempshadowvertex2.subtract(camera.position); + tempshadowvertex2.rotate_XZ(camera.XZ_angle); + tempshadowvertex2.rotate_YZ(camera.YZ_angle); + tempshadowvertex2.updateLocation(); + + tempshadowvertex3.set(shadowvertex3); + tempshadowvertex3.subtract(camera.position); + tempshadowvertex3.rotate_XZ(camera.XZ_angle); + tempshadowvertex3.rotate_YZ(camera.YZ_angle); + tempshadowvertex3.updateLocation(); + + + //if the object is visible then draw it on the shadow buffer from light point of view + if(shadowBoundary1.contains(tempshadowvertex0.screenX, tempshadowvertex0.screenY) || + shadowBoundary1.contains(tempshadowvertex1.screenX, tempshadowvertex1.screenY) || + shadowBoundary1.contains(tempshadowvertex2.screenX, tempshadowvertex2.screenY) || + shadowBoundary1.contains(tempshadowvertex3.screenX, tempshadowvertex3.screenY) + ){ + + + if(emergingStarted){ + for(int i = 0; i < polygons.length; i++){ + polygons[i].update_lightspace(); + } + + for(int i = 0; i < vent1Clone.length; i++){ + vent1Clone[i].update_lightspace(); + } + + for(int i = 0; i < vent2Clone.length; i++){ + vent2Clone[i].update_lightspace(); + } + } + } + + //add this object to visible unit list + theAssetManager.visibleUnit[theAssetManager.visibleUnitCount] = this; + theAssetManager.visibleUnitCount++; + + + }else{ + visible = false; + } + + + //create vision for enemy commander + if(teamNo == 1){ + int xPos = boundary2D.x1/16 - 8 + 10 + 1; + int yPos = 127 - boundary2D.y1/16 - 8 + 10 + 1; + + 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; + } + } + } + + visionBoundary.x = (int)(tempCentre.screenX - 800); + visionBoundary.y = (int)(tempCentre.screenY - 1000); + visionInsideScreen = camera.screen.intersects(visionBoundary); + + + if(visionInsideScreen){ + if(teamNo == 0){ + 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++; + } + } + + if(theAssetManager.minimapBitmap[tileIndex[0]] || + theAssetManager.minimapBitmap[tileIndex[1]] || + theAssetManager.minimapBitmap[tileIndex[2]] || + theAssetManager.minimapBitmap[tileIndex[3]] || + theAssetManager.minimapBitmap[tileIndex[4]] || + theAssetManager.minimapBitmap[tileIndex[5]] || + theAssetManager.minimapBitmap[tileIndex[6]] || + theAssetManager.minimapBitmap[tileIndex[7]] || + theAssetManager.minimapBitmap[tileIndex[8]]) + isRevealed = true; + + visible_minimap = isRevealed; + + if(visible_minimap){ + tempInt = theAssetManager.unitsForMiniMap[theAssetManager.unitsForMiniMapCount]; + tempInt[0] = teamNo; + 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] = 10000; + theAssetManager.unitsForMiniMapCount++; + } + + + updateGeometry(); + + + } + + public void updateGeometry(){ + + //update vent1 + vent1Angle = (vent1Angle + 10)%360; + + + for(int i = 0; i < vent1.length; i++){ + vent1Clone[i].origin.set(vent1[i].origin); + + vent1Clone[i].origin.rotate_XZ(vent1Angle); + vent1Clone[i].origin.add(ventCenter1); + + + vent1Clone[i].bottomEnd.set(vent1[i].bottomEnd); + vent1Clone[i].bottomEnd.rotate_XZ(vent1Angle); + vent1Clone[i].bottomEnd.add(ventCenter1); + + + vent1Clone[i].rightEnd.set(vent1[i].rightEnd); + vent1Clone[i].rightEnd.rotate_XZ(vent1Angle); + vent1Clone[i].rightEnd.add(ventCenter1); + + for(int j = 0; j < vent1Clone[i].vertex3D.length; j++){ + vent1Clone[i].vertex3D[j].set(vent1[i].vertex3D[j]); + vent1Clone[i].vertex3D[j].rotate_XZ(vent1Angle); + vent1Clone[i].vertex3D[j].add(ventCenter1); + + + } + } + + //update vent2 + vent2Angle = (vent2Angle + 8)%360; + + + for(int i = 0; i < vent2.length; i++){ + vent2Clone[i].origin.set(vent2[i].origin); + + vent2Clone[i].origin.rotate_XZ(vent2Angle); + vent2Clone[i].origin.add(ventCenter2); + + + vent2Clone[i].bottomEnd.set(vent2[i].bottomEnd); + vent2Clone[i].bottomEnd.rotate_XZ(vent2Angle); + vent2Clone[i].bottomEnd.add(ventCenter2); + + + vent2Clone[i].rightEnd.set(vent2[i].rightEnd); + vent2Clone[i].rightEnd.rotate_XZ(vent2Angle); + vent2Clone[i].rightEnd.add(ventCenter2); + + for(int j = 0; j < vent2Clone[i].vertex3D.length; j++){ + vent2Clone[i].vertex3D[j].set(vent2[i].vertex3D[j]); + vent2Clone[i].vertex3D[j].rotate_XZ(vent2Angle); + vent2Clone[i].vertex3D[j].add(ventCenter2); + + + } + } + } + + //build structure + public void build(int buildingType){ + if(buildingType == 101) + buildPowerPlant(); + else if(buildingType == 102) + buildRefinery(); + else if(buildingType == 105) + buildFactory(); + else if(buildingType == 106) + buildCommunicationCentre(); + else if(buildingType == 200) + buildGunTurret(); + else if(buildingType == 199) + buildMissileTurret(); + else if(buildingType == 107) + buildTechCenter(); + } + + //building power plant + public void buildPowerPlant(){ + if(canBuildPowerPlant){ + powerPlantProgress = 0; + refineryProgress = 254; + factoryProgress = 254; + communicationCenterProgress = 254; + techCenterProgress = 254; + gunTurretProgress = 254; + missileTurretProgress = 254; + creditSpentOnBuilding = 0; + currentBuildingType = 101; + } + } + + //building power plant + public void buildRefinery(){ + if(canBuildRefinery){ + refineryProgress = 0; + powerPlantProgress = 254; + factoryProgress = 254; + communicationCenterProgress = 254; + techCenterProgress = 254; + gunTurretProgress = 254; + missileTurretProgress = 254; + creditSpentOnBuilding = 0; + currentBuildingType = 102; + } + } + + //building power plant + public void buildFactory(){ + if(canBuildFactory){ + refineryProgress = 254; + powerPlantProgress = 254; + factoryProgress = 0; + communicationCenterProgress = 254; + techCenterProgress = 254; + gunTurretProgress = 254; + missileTurretProgress = 254; + creditSpentOnBuilding = 0; + currentBuildingType = 105; + } + } + + //build communication centre + public void buildCommunicationCentre(){ + if(canBuildCommunicationCenter){ + refineryProgress = 254; + powerPlantProgress = 254; + factoryProgress = 254; + communicationCenterProgress = 0; + techCenterProgress = 254; + gunTurretProgress = 254; + missileTurretProgress = 254; + creditSpentOnBuilding = 0; + currentBuildingType = 106; + } + } + + //build gun turret + public void buildGunTurret(){ + if(canBuildGunTurret){ + refineryProgress = 254; + powerPlantProgress = 254; + factoryProgress = 254; + communicationCenterProgress = 254; + techCenterProgress = 254; + gunTurretProgress = 0; + missileTurretProgress = 254; + creditSpentOnBuilding = 0; + currentBuildingType = 200; + } + } + + //build Missile turret + public void buildMissileTurret(){ + if(canBuildGunTurret){ + refineryProgress = 254; + powerPlantProgress = 254; + factoryProgress = 254; + communicationCenterProgress = 254; + techCenterProgress = 254; + gunTurretProgress = 254; + missileTurretProgress = 0; + creditSpentOnBuilding = 0; + currentBuildingType = 199; + } + } + + //build Tech Center + public void buildTechCenter(){ + if(canBuildTechCenter){ + refineryProgress = 254; + powerPlantProgress = 254; + factoryProgress = 254; + communicationCenterProgress = 254; + techCenterProgress = 0; + gunTurretProgress = 254; + missileTurretProgress = 254; + creditSpentOnBuilding = 0; + currentBuildingType = 107; + } + } + + + //cancel building + public void cancelBuilding(){ + powerPlantProgress = 255; + refineryProgress = 255; + factoryProgress = 255; + communicationCenterProgress = 255; + techCenterProgress = 255; + gunTurretProgress = 255; + missileTurretProgress = 255; + if(teamNo == 0) + mainThread.pc.theBaseInfo.currentCredit+=creditSpentOnBuilding; + else + mainThread.ec.theBaseInfo.currentCredit+=creditSpentOnBuilding; + creditSpentOnBuilding = 0; + currentBuildingType = -1; + } + + //finishing deployment + public void finishDeployment(){ + powerPlantProgress = 255; + refineryProgress = 255; + factoryProgress = 255; + communicationCenterProgress = 255; + techCenterProgress = 255; + gunTurretProgress = 255; + missileTurretProgress = 255; + creditSpentOnBuilding = 0; + currentBuildingType = -1; + } + + public boolean isIdle(){ + return powerPlantProgress == 255 && refineryProgress == 255 && factoryProgress == 255 && communicationCenterProgress == 255 && techCenterProgress == 255 && gunTurretProgress == 255 && missileTurretProgress == 255; + } + + //create building + public void createBuilding(){ + if(powerPlantProgress == 240){ + int y = 127 - dg.gridOneIndex/128; + int x = dg.gridOneIndex%128 + 1; + powerPlant o = new powerPlant(x*0.25f, -1f, y*0.25f, 0); + mainThread.theAssetManager.addPowerPlant(o); + }else if(refineryProgress == 240){ + int y = 127 - dg.gridOneIndex/128; + int x = dg.gridOneIndex%128 + 1; + refinery o = new refinery(x*0.25f + 0.125f, -1.43f, y*0.25f, 0); + mainThread.theAssetManager.addRefinery(o); + harvester h = new harvester(new vector(x*0.25f + 0.125f,-0.3f, y*0.25f - 0.375f), 180, 0); + if(communicationCenter.harvesterSpeedResearched_player){ + h.speed = 0.014f; + h.bodyTurnRate = 8; + } + mainThread.theAssetManager.addHarvester(h); + h.goToTheNearestGoldMine(); + }else if(factoryProgress == 240){ + int y = 127 - dg.gridOneIndex/128; + int x = dg.gridOneIndex%128 + 1; + factory o = new factory(x*0.25f + 0.125f, -1.13f, y*0.25f, 0); + mainThread.theAssetManager.addFactory(o); + }else if(communicationCenterProgress == 240){ + int y = 127 - dg.gridOneIndex/128; + int x = dg.gridOneIndex%128 + 1; + communicationCenter o = new communicationCenter(x*0.25f, -1f, y*0.25f, 0); + mainThread.theAssetManager.addCommunicationCenter(o); + }else if(gunTurretProgress == 240){ + int y = 127 - dg.gridOneIndex/128; + int x = dg.gridOneIndex%128 + 1; + gunTurret o = new gunTurret(x*0.25f -0.125f, -0.65f, y*0.25f + 0.125f, 0); + mainThread.theAssetManager.addGunTurret(o); + }else if(missileTurretProgress == 240){ + int y = 127 - dg.gridOneIndex/128; + int x = dg.gridOneIndex%128 + 1; + missileTurret o = new missileTurret(x*0.25f -0.125f, -0.95f, y*0.25f + 0.125f, 0); + mainThread.theAssetManager.addMissileTurret(o); + }else if(techCenterProgress == 240){ + int y = 127 - dg.gridOneIndex/128; + int x = dg.gridOneIndex%128 + 1; + techCenter o = new techCenter(x*0.25f, -1f, y*0.25f, 0); + mainThread.theAssetManager.addTechCenter(o); + } + + + } + + public static int getPowerConsumption(int buildingType){ + if(buildingType == 101) + return -500; + else if(buildingType == 102) + return 150; + else if(buildingType == 105) + return 200; + else if(buildingType == 106) + return 250; + else if(buildingType == 200) + return 100; + else if(buildingType == 199) + return 200; + else if(buildingType == 107) + return 400; + return 0; + } + + + //draw the model + public void draw(){ + + if(!visible || !emergingStarted) + return; + for(int i = 0; i < polygons.length; i++){ + polygons[i].update(); + } + + for(int i = 0; i < vent1Clone.length; i++){ + vent1Clone[i].update(); + } + + for(int i = 0; i < vent2Clone.length; i++){ + vent2Clone[i].update(); + } + + for(int i = 0; i < polygons.length; i++){ + polygons[i].draw(); + } + + for(int i = 0; i < vent1Clone.length; i++){ + vent1Clone[i].draw(); + } + + for(int i = 0; i < vent2Clone.length; i++){ + vent2Clone[i].draw(); + } + + } + + public void drawDeploymentGrid(){ + + if(needToDrawDeploymentGrid){ + dg.update(); + dg.draw(); + } + } + + public vector getMovement(){ + return movenment; + } + + public void printCurrentBuilding(){ + if(refineryProgress <= 240){ + System.out.println("building refinery: " + 100*refineryProgress/240 + "%"); + } + + if(powerPlantProgress <= 240){ + System.out.println("building power plant: " + 100*powerPlantProgress/240 + "%"); + } + + if(factoryProgress <= 240){ + System.out.println("building factory: " + 100*factoryProgress/240 + "%"); + } + + if(communicationCenterProgress <= 240){ + System.out.println("building communication center: " + 100*communicationCenterProgress/240 + "%"); + } + + if(techCenterProgress <= 240){ + System.out.println("building tech Center: " + 100*techCenterProgress/240 + "%"); + } + + if(gunTurretProgress <= 240){ + System.out.println("building gun turret: " + 100*gunTurretProgress/240 + "%"); + } + + if(missileTurretProgress <= 240){ + System.out.println("building missile turret: " + 100*missileTurretProgress/240 + "%"); + } + + } +} diff --git a/entity/drone.java b/entity/drone.java new file mode 100644 index 0000000..d5271e7 --- /dev/null +++ b/entity/drone.java @@ -0,0 +1,673 @@ +package entity; + +import java.awt.Rectangle; + +import core.*; + +//small flying unit capable of repairing tanks + +public class drone extends solidObject{ + + public vector iDirectionBody, jDirectionBody, kDirectionBody; + + public vector bodyCenter; + + public static polygon3D[] polys; + + public static vector engine1Center, engine2Center; + + public int fan1Angle, fan2Angle; + + public final static Rectangle visibleBoundary = new Rectangle(-100,-150,1068, 812); + + //a screen space boundary which is used to test if the entire object is within the screen + public final static Rectangle screenBoundary = new Rectangle(40,40,688, 432); + + //screen space boundary which is used to test if the shadow of the object is within the screen + public final static Rectangle shadowBoundary1 = new Rectangle(0,0,768, 512); + + + public int bodyAngle, destinationAngle; + + //index of the tiles to check when the drone is idle + public static int[] tileCheckList; + + public factory myFactory; + + public static int numOfPolygons; + + public float heightVariance; + + public int randomNumber; + + public solidObject targetUnit; + + public vector idlePosition; + + public static final int returnToIdlePosition = 0; + public static final int healUnit = 1; + + public static final int turnRate = 5; + public static final float maxSpeed = 0.04f; + + public float serviceRadius; + + public static vector armCenter, armDirection; + public vector armCenterClone, armDirectionClone; + + + public drone(vector origin, int bodyAngle, factory myFactory){ + //register itself in factory and find out idle location + idlePosition = new vector(0,0,0); + + serviceRadius = 3.5f; + + for(int i = 0; i < 3; i++){ + if(myFactory.myDrones[i] == null){ + myFactory.myDrones[i] = this; + if(i == 0){ + idlePosition.set(myFactory.centre.x, 0, myFactory.centre.z+0.15f); + }else if(i == 1){ + idlePosition.set(myFactory.centre.x - 0.3f, 0, myFactory.centre.z-0.25f); + }else{ + idlePosition.set(myFactory.centre.x + 0.2f, 0, myFactory.centre.z-0.25f); + } + break; + } + } + + + + speed = 0f; + currentHP = 20; + start = origin.myClone(); + centre = origin.myClone(); + tempCentre = origin.myClone(); + bodyCenter = origin.myClone(); + this.bodyAngle = 360 -bodyAngle; + this.immediateDestinationAngle = bodyAngle; + + destinationAngle = bodyAngle; + + teamNo = myFactory.teamNo; + this.myFactory = myFactory; + + //drone does't have any collision boundary, and its unselectable + type = 5; + isSelectable = false; + + height = centre.y + 0.5f; //? + theAssetManager = mainThread.theAssetManager; + + movement = new vector(0,0,0); + + + + //create main axis in object space + iDirection = new vector(1f,0,0); + jDirection = new vector(0,1f,0); + kDirection = new vector(0,0,1f); + + iDirection.rotate_XZ(360-bodyAngle); + jDirection.rotate_XZ(360-bodyAngle); + kDirection.rotate_XZ(360-bodyAngle); + + + //create polygons + makePolygons(); + + + if(tileCheckList == null){ + tileCheckList = generateTileCheckList(11f); + } + + randomNumber = (int)(Math.random()*360); + } + + public void makePolygons(){ + if(polys == null){ + polys = new polygon3D[171]; + + vector[] v; + + engine1Center = new vector(0.041f, 0, 0); + engine2Center = new vector(-0.041f, 0, 0); + + + //create engine fan + start.reset(); + float delta = (float)Math.PI/4; + v = new vector[]{ + put(0.027*Math.cos(1*delta), -0.01, 0.027*Math.sin(1*delta)), + put(0.027*Math.cos((0)*delta), -0.01, 0.027*Math.sin((0)*delta)), + put(0.00001*Math.cos((0)*delta), -0.01, 0.00001*Math.sin((0)*delta)), + put(0.00001*Math.cos(1*delta), -0.01, 0.00001*Math.sin(1*delta)), + }; + addPolygon(polys, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 1f,1f,1)); + v = new vector[]{ + put(0.027*Math.cos(5*delta), -0.01, 0.027*Math.sin(5*delta)), + put(0.027*Math.cos((4)*delta), -0.01, 0.027*Math.sin((4)*delta)), + put(0.00001*Math.cos((4)*delta), -0.01, 0.00001*Math.sin((4)*delta)), + put(0.00001*Math.cos(5*delta), -0.01, 0.00001*Math.sin(5*delta)), + }; + addPolygon(polys, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 1f,1f,1)); + + + v = new vector[]{ + put(0.027*Math.cos(3*delta), -0.01, 0.027*Math.sin(3*delta)), + put(0.027*Math.cos((2)*delta), -0.01, 0.027*Math.sin((2)*delta)), + put(0.00001*Math.cos((2)*delta), -0.01, 0.00001*Math.sin((2)*delta)), + put(0.00001*Math.cos(3*delta), -0.01, 0.00001*Math.sin(3*delta)), + }; + addPolygon(polys, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 1f,1f,1)); + v = new vector[]{ + put(0.027*Math.cos(7*delta), -0.01, 0.027*Math.sin(7*delta)), + put(0.027*Math.cos((6)*delta), -0.01, 0.027*Math.sin((6)*delta)), + put(0.00001*Math.cos((6)*delta), -0.01, 0.00001*Math.sin((6)*delta)), + put(0.00001*Math.cos(7*delta), -0.01, 0.00001*Math.sin(7*delta)), + }; + addPolygon(polys, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 1f,1f,1)); + + + //create main body section + v = new vector[]{ put(-0.016, 0, -0.006),put(-0.016, 0, 0.006), put(-0.015, 0, 0.013), put(0.015, 0, 0.013), put(0.016, 0, 0.006), put(0.016, 0, -0.006), put(0.015, 0, -0.013),put(-0.015, 0, -0.013)}; + addPolygon(polys, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 1f,1f,1)); + + v = new vector[]{put(-0.016, 0, -0.006), put(-0.015, 0, -0.013), put(-0.015, -0.015, -0.013), put(-0.016, -0.015, -0.006)}; + addPolygon(polys, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 1f,1f,1)); + + v = new vector[]{ put(0.016, -0.015, -0.006), put(0.015, -0.015, -0.013), put(0.015, 0, -0.013),put(0.016, 0, -0.006)}; + addPolygon(polys, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 1f,1f,1)); + + v = new vector[]{put(-0.016, -0.015, 0.006), put(-0.015, -0.015, 0.013), put(-0.015, 0, 0.013), put(-0.016, 0, 0.006)}; + addPolygon(polys, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 1f,1f,1)); + + v = new vector[]{put(0.016, 0, 0.006), put(0.015, 0, 0.013), put(0.015, -0.015, 0.013), put(0.016, -0.015, 0.006)}; + addPolygon(polys, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 1f,1f,1)); + + v = new vector[]{put(0.015, 0, 0.013), put(-0.015, 0, 0.013), put(-0.015, -0.015, 0.013), put(0.015, -0.015, 0.013)}; + addPolygon(polys, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 1f,1f,1)); + + v = new vector[]{put(0.015, -0.015, -0.013), put(-0.015, -0.015, -0.013), put(-0.015, 0, -0.013), put(0.015, 0, -0.013)}; + addPolygon(polys, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 1f,1f,1)); + + //left engine + float r = 0.03f; + delta = (float)Math.PI/8; + + start.x-=0.041f; + + for(int i = 0; i < 16; i++){ + v = new vector[]{put(r*Math.cos(i*delta), 0.01, r*Math.sin(i*delta)), + put(r*Math.cos((i+1)*delta), 0.01, r*Math.sin((i+1)*delta)), + put(r*Math.cos((i+1)*delta), -0.013, r*Math.sin((i+1)*delta)), + put(r*Math.cos(i*delta), -0.013, r*Math.sin(i*delta)) + }; + + addPolygon(polys, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 1f,1f,1)); + + } + + float r2 = 0.026f; + for(int i = 0; i < 16; i++){ + v = new vector[]{put(r2*Math.cos(i*delta), -0.013, r2*Math.sin(i*delta)), + put(r2*Math.cos((i+1)*delta), -0.013, r2*Math.sin((i+1)*delta)), + put(r2*Math.cos((i+1)*delta), 0.01, r2*Math.sin((i+1)*delta)), + put(r2*Math.cos(i*delta), 0.01, r2*Math.sin(i*delta)) + + }; + + addPolygon(polys, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 1f,1f,1)); + + } + + for(int i = 0; i < 16; i++){ + v = new vector[]{ + put(r2*Math.cos(i*delta), 0.01, r2*Math.sin(i*delta)), + put(r2*Math.cos((i+1)*delta), 0.01, r2*Math.sin((i+1)*delta)), + put(r*Math.cos((i+1)*delta), 0.01, r*Math.sin((i+1)*delta)), + put(r*Math.cos(i*delta), 0.01, r*Math.sin(i*delta)), + }; + addPolygon(polys, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 1f,1f,1)); + } + + float r3 = 0.005f; + float r4 = 0.0001f; + for(int i = 0; i < 16; i++){ + v = new vector[]{put(r4*Math.cos(i*delta), 0.01, r4*Math.sin(i*delta)), + put(r4*Math.cos((i+1)*delta), 0.01, r4*Math.sin((i+1)*delta)), + put(r3*Math.cos((i+1)*delta), -0.01, r3*Math.sin((i+1)*delta)), + put(r3*Math.cos(i*delta), -0.01, r3*Math.sin(i*delta)) + }; + + addPolygon(polys, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 1f,1f,1)); + + } + + //right engine + start.x+=0.082f; + for(int i = 0; i < 16; i++){ + v = new vector[]{put(r*Math.cos(i*delta), 0.01, r*Math.sin(i*delta)), + put(r*Math.cos((i+1)*delta), 0.01, r*Math.sin((i+1)*delta)), + put(r*Math.cos((i+1)*delta), -0.013, r*Math.sin((i+1)*delta)), + put(r*Math.cos(i*delta), -0.013, r*Math.sin(i*delta)) + }; + + addPolygon(polys, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 1f,1f,1)); + + } + + + for(int i = 0; i < 16; i++){ + v = new vector[]{put(r2*Math.cos(i*delta), -0.013, r2*Math.sin(i*delta)), + put(r2*Math.cos((i+1)*delta), -0.013, r2*Math.sin((i+1)*delta)), + put(r2*Math.cos((i+1)*delta), 0.01, r2*Math.sin((i+1)*delta)), + put(r2*Math.cos(i*delta), 0.01, r2*Math.sin(i*delta)) + + }; + + addPolygon(polys, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 1f,1f,1)); + + } + + for(int i = 0; i < 16; i++){ + v = new vector[]{ + put(r2*Math.cos(i*delta), 0.01, r2*Math.sin(i*delta)), + put(r2*Math.cos((i+1)*delta), 0.01, r2*Math.sin((i+1)*delta)), + put(r*Math.cos((i+1)*delta), 0.01, r*Math.sin((i+1)*delta)), + put(r*Math.cos(i*delta), 0.01, r*Math.sin(i*delta)), + }; + addPolygon(polys, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 1f,1f,1)); + } + + for(int i = 0; i < 16; i++){ + v = new vector[]{put(r4*Math.cos(i*delta), 0.01, r4*Math.sin(i*delta)), + put(r4*Math.cos((i+1)*delta), 0.01, r4*Math.sin((i+1)*delta)), + put(r3*Math.cos((i+1)*delta), -0.01, r3*Math.sin((i+1)*delta)), + put(r3*Math.cos(i*delta), -0.01, r3*Math.sin(i*delta)) + }; + + addPolygon(polys, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 1f,1f,1)); + + } + + //repair arm + start.x-=0.041f; + r2 = 0.008f; + for(int i = 0; i < 16; i++){ + v = new vector[]{put(r2*Math.cos(i*delta), 0, r2*Math.sin(i*delta)), + put(r2*Math.cos((i+1)*delta), 0, r2*Math.sin((i+1)*delta)), + put(r2*Math.cos((i+1)*delta), -0.08, r2*Math.sin((i+1)*delta)), + put(r2*Math.cos(i*delta), -0.08, r2*Math.sin(i*delta)) + }; + + addPolygon(polys, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 1f,1f,1)); + } + + + + iDirection.rotate_YZ(340); + jDirection.rotate_YZ(340); + kDirection.rotate_YZ(340); + + start.y-=0.075f; + r3 = 0.007f; + for(int i = 0; i < 16; i++){ + v = new vector[]{put(r2*Math.cos(i*delta), 0, r2*Math.sin(i*delta)), + put(r2*Math.cos((i+1)*delta), 0, r2*Math.sin((i+1)*delta)), + put(r3*Math.cos((i+1)*delta), -0.04, r3*Math.sin((i+1)*delta)), + put(r3*Math.cos(i*delta), -0.04, r3*Math.sin(i*delta)) + }; + + addPolygon(polys, new polygon3D(v, v[0], v[1], v[3], mainThread.textures[26], 1f,1f,1)); + } + + armCenter = put(0,-0.04, 0); + armDirection = jDirection.myClone(); + armDirection.y*=-1; + + } + polygons = clonePolygons(polys, false); + armCenterClone = armCenter.myClone(); + armDirectionClone = armDirection.myClone(); + + + } + + + + //update the model + public void update(){ + + //check if factory where the drone is spawned has been destroyed + if(myFactory.currentHP <= 0){ + + if(targetUnit != null) + targetUnit.myHealer = null; + + //spawn an explosion when the object is destroyed + float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount]; + tempFloat[0] = centre.x; + tempFloat[1] = centre.y; + tempFloat[2] = centre.z; + tempFloat[3] = 0.99f; + tempFloat[4] = 1; + tempFloat[5] = 0; + tempFloat[6] = 7; + tempFloat[7] = this.height; + theAssetManager.explosionCount++; + + theAssetManager.removeObject(this); + + return; + + } + + //handle AI + + if(!disableUnitLevelAI){ + if(currentCommand == returnToIdlePosition){ + + if(centre.y <=0.05){ + centre.y+=0.005f; + } + + if(idlePosition.x != centre.x || idlePosition.z != centre.z){ + double distanceToDestination = Math.sqrt((idlePosition.x - centre.x)* (idlePosition.x - centre.x) + (idlePosition.z - centre.z)*(idlePosition.z - centre.z)); + + if(distanceToDestination >= 0.2f){ + if(speed <= maxSpeed) + speed+=0.002f; + } + if(distanceToDestination < 0.4f){ + if(speed >= 0.03f) + speed-=0.002f; + } + if(distanceToDestination < 0.25f){ + if(speed >= 0.02f) + speed-=0.002f; + } + if(distanceToDestination < 0.1f){ + if(speed >= 0.01f) + speed-=0.002f; + } + + //move to idle position + if(distanceToDestination <= speed){ + centre.x = idlePosition.x; + centre.z = idlePosition.z; + speed = 0; + }else{ + movement.set(idlePosition.x - centre.x, 0, idlePosition.z - centre.z); + movement.unit(); + movement.scale(speed); + centre.add(movement); + } + + //face idle position + destinationAngle = geometry.findAngle(centre.x, centre.z, idlePosition.x, idlePosition.z); + int angleDelta = 360 - (geometry.findAngleDelta(bodyAngle, destinationAngle, turnRate) + 360)%360; + bodyAngle= (bodyAngle - angleDelta + 360)%360; + if(Math.abs(bodyAngle - destinationAngle) <= turnRate) + bodyAngle = destinationAngle; + + } + + //scan for nearby damaged unit + currentOccupiedTile = (int)(centre.x*64)/16 + (127 - (int)(centre.z*64)/16)*128; + + for(int i = 0; i < tileCheckList.length; i++){ + if(targetUnit != null) + break; + + if(tileCheckList[i] != Integer.MAX_VALUE){ + int index = currentOccupiedTile + tileCheckList[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].currentHP < tile[j].getMaxHp() && getDistance(myFactory, tile[j]) < serviceRadius && tile[j].myHealer == null){ + + currentCommand = healUnit; + targetUnit = tile[j]; + targetUnit.myHealer = this; + break; + } + } + } + } + } + + }else if(currentCommand == healUnit){ + if(targetUnit.currentHP <=0 || getDistance(myFactory, targetUnit) >= serviceRadius){ + targetUnit.myHealer = null; + targetUnit = null; + currentCommand = returnToIdlePosition; + }else{ + tempVector.set(targetUnit.centre); + if(tempVector.x != centre.x || tempVector.z != centre.z){ + double distanceToDestination = Math.sqrt((tempVector.x - centre.x)* (tempVector.x - centre.x) + (tempVector.z - centre.z)*(tempVector.z - centre.z)); + + if(distanceToDestination >= 0.2f){ + if(speed <= maxSpeed) + speed+=0.002f; + + if(centre.y <=0.1){ + centre.y+=0.01f; + } + }else{ + if(centre.y > - 0.15){ + centre.y-=0.01f; + } + + } + + if(distanceToDestination < 0.4f){ + if(speed >= 0.03f) + speed-=0.002f; + + //heal unit + if(targetUnit.currentHP < targetUnit.getMaxHp() || targetUnit.underAttackCountDown > 60){ + if(mainThread.frameIndex%5 == 1 && centre.y <=-0.1){ + targetUnit.currentHP+=5; + if(targetUnit.currentHP > targetUnit.getMaxHp()) + targetUnit.currentHP = targetUnit.getMaxHp(); + } + if(mainThread.frameIndex%2==0 && centre.y <=-0.15){ + //spawn a healing steam particle + float[] tempFloat = theAssetManager.smokeEmmiterList[theAssetManager.smokeEmmiterCount]; + tempFloat[0] = armCenterClone.x + (float)(Math.random()/20) - 0.025f; + tempFloat[1] = armCenterClone.y; + tempFloat[2] = armCenterClone.z + (float)(Math.random()/20) - 0.025f; + tempFloat[3] = 0.8f; + tempFloat[4] = 1; + tempFloat[5] = 11; + tempFloat[6] = this.height; + theAssetManager.smokeEmmiterCount++; + } + }else{ + targetUnit.myHealer = null; + targetUnit = null; + currentCommand = returnToIdlePosition; + } + } + if(distanceToDestination < 0.25f){ + if(speed >= 0.02f) + speed-=0.002f; + + + } + if(distanceToDestination < 0.1f){ + if(speed >= 0.01f) + speed-=0.002f; + + + } + + + if(distanceToDestination >= 0.06f){ + + movement.set(tempVector.x - centre.x, 0, tempVector.z - centre.z); + movement.unit(); + movement.scale(speed); + centre.add(movement); + } + + //face idle position + destinationAngle = geometry.findAngle(centre.x, centre.z, tempVector.x, tempVector.z); + int angleDelta = 360 - (geometry.findAngleDelta(bodyAngle, destinationAngle, turnRate) + 360)%360; + bodyAngle= (bodyAngle - angleDelta + 360)%360; + if(Math.abs(bodyAngle - destinationAngle) <= turnRate) + bodyAngle = destinationAngle; + + } + } + } + } + + + + fan1Angle+=60; + fan2Angle+=300; + fan1Angle = fan1Angle%360; + fan2Angle = fan2Angle%360; + + heightVariance = gameData.sin[((mainThread.frameIndex+randomNumber)*5)%360] * 0.01f; + + + //update center in camera coordinate + tempCentre.set(centre); + tempCentre.subtract(camera.position); + tempCentre.rotate_XZ(camera.XZ_angle); + tempCentre.rotate_YZ(camera.YZ_angle); + tempCentre.updateLocation(); + + //check if the tank object is visible in mini map + visible_minimap = theAssetManager.minimapBitmap[(int)(centre.x*64)/16 + (127 - (int)(centre.z*64)/16)*128]; + + + + + + + + //test if the object is visible in camera point of view + if(visibleBoundary.contains(tempCentre.screenX, tempCentre.screenY) && myFactory.isRevealed && visible_minimap){ + visible = true; + + for(int i = 0; i < numOfPolygons; i++){ + polygons[i].update_lightspace(); + } + + //update centre + updateGeometry(); + + + if(screenBoundary.contains(tempCentre.screenX, tempCentre.screenY)) + withinViewScreen = true; + else + withinViewScreen = false; + + + + + }else{ + visible = false; + } + + + } + + public void updateGeometry(){ + int bodyAngle_ = 360 - bodyAngle; + //rotate fans + for(int j = 0; j < polygons[0].vertex3D.length; j++){ + polygons[0].vertex3D[j].set(polys[0].vertex3D[j]); + polygons[0].vertex3D[j].rotate_XZ(fan1Angle); + polygons[0].vertex3D[j].add(engine1Center); + polygons[0].vertex3D[j].rotate_XZ(bodyAngle_); + polygons[0].vertex3D[j].add(centre); + polygons[0].vertex3D[j].y+=heightVariance; + + polygons[1].vertex3D[j].set(polys[1].vertex3D[j]); + polygons[1].vertex3D[j].rotate_XZ(fan1Angle); + polygons[1].vertex3D[j].add(engine1Center); + polygons[1].vertex3D[j].rotate_XZ(bodyAngle_); + polygons[1].vertex3D[j].add(centre); + polygons[1].vertex3D[j].y+=heightVariance; + + polygons[2].vertex3D[j].set(polys[2].vertex3D[j]); + polygons[2].vertex3D[j].rotate_XZ(fan2Angle); + polygons[2].vertex3D[j].add(engine2Center); + polygons[2].vertex3D[j].rotate_XZ(bodyAngle_); + polygons[2].vertex3D[j].add(centre); + polygons[2].vertex3D[j].y+=heightVariance; + + polygons[3].vertex3D[j].set(polys[3].vertex3D[j]); + polygons[3].vertex3D[j].rotate_XZ(fan2Angle); + polygons[3].vertex3D[j].add(engine2Center); + polygons[3].vertex3D[j].rotate_XZ(bodyAngle_); + polygons[3].vertex3D[j].add(centre); + polygons[3].vertex3D[j].y+=heightVariance; + } + + + //update main body + for(int i =4; i < numOfPolygons; i++){ + + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + polygons[i].vertex3D[j].set(polys[i].vertex3D[j]); + polygons[i].normal.set(polys[i].normal); + polygons[i].normal.rotate_XZ(bodyAngle_); + polygons[i].vertex3D[j].rotate_XZ(bodyAngle_); + polygons[i].vertex3D[j].add(centre); + polygons[i].vertex3D[j].y+=heightVariance; + + + polygons[i].findDiffuse(); + + } + } + + //update arm + armCenterClone.set(armCenter); + armCenterClone.rotate_XZ(bodyAngle_); + armCenterClone.add(centre); + armCenterClone.y+=heightVariance; + + armDirectionClone.set(armDirection); + armDirectionClone.rotate_XZ(bodyAngle_); + } + + public void draw(){ + + if(!visible) + return; + + for(int i = 0; i < numOfPolygons; i++){ + polygons[i].update(); + polygons[i].draw(); + + } + + + } + + public int addPolygon(polygon3D[] polys, polygon3D poly){ + for(int i = 0; i < polys.length; i++){ + if(polys[i] == null){ + polys[i] = poly; + numOfPolygons++; + return i; + } + } + return -1; + } + + public float getDistance(solidObject o1, solidObject o2){ + return (float)Math.sqrt((o1.centre.x - o2.centre.x)*(o1.centre.x - o2.centre.x) + (o1.centre.z - o2.centre.z)*(o1.centre.z - o2.centre.z)); + } + +} diff --git a/entity/factory.java b/entity/factory.java new file mode 100644 index 0000000..18bfade --- /dev/null +++ b/entity/factory.java @@ -0,0 +1,2059 @@ +package entity; + +import java.awt.Rectangle; + +import core.*; +import enemyAI.enemyCommander; + +//the factory model +public class factory extends solidObject{ + + //the polygons of the model + private polygon3D[] polygons; + private polygon3D[] doorUpper; + private polygon3D[] doorLower; + private polygon3D[] fanA; + private polygon3D[] fanB; + + public static int maxHP = 850; + + public int countDownToDeath = 16; + + public vector tempVector = new vector(0,0,0); + public vector tempVector0 = new vector(0,0,0); + public vector tempVector1 = new vector(0,0,0); + public vector tempVector2 = new vector(0,0,0); + public vector tempVector3 = new vector(0,0,0); + + //factory occupies 6 tiles + public int [] tileIndex = new int[6]; + + public int[] tempInt; + + public float[] tempFloat; + + public vector shadowvertex0, tempshadowvertex0,shadowvertex1, tempshadowvertex1,shadowvertex2, tempshadowvertex2,shadowvertex3, tempshadowvertex3; + + //a screen space boundary which is used to test if the object is visible from camera point of view + public final static Rectangle visibleBoundary = new Rectangle(-85,-85,920, 762); + + //a screen space boundary which is used to test if the entire object is within the screen + public final static Rectangle screenBoundary = new Rectangle(60,60,648, 402); + + //screen space boundary which is used to test if the shadow of the object is within the screen + public final static Rectangle shadowBoundary1 = new Rectangle(20,60,788, 482); + + //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,1600, 2000); + + //a bitmap representation of the vision of the building for enemy commander + public static boolean[] bitmapVisionForEnemy; + + //factory never moves + public final static vector movenment = new vector(0,0,0); + + //number of polygons + public int numOfPolygons; + + //distortion polygon index + public int distortionA, distortionB; + + //power tower center + public vector powerTowerCenterA, powerTowerCenterB; + + public boolean canBuildLightTank, canBuildDrone, canBuildRocketTank, canBuildHarvester, canBuildStealthTank, canBuildHeavyTank, canBuildMCV; + public int lightTankProgress, droneProgress, rocketTankProgress, harvesterProgress, stealthTankProgress, heavyTankProgress, MCVProgress; + public int creditSpentOnBuilding; + public baseInfo theBaseInfo; + public byte[] productionQueue; + public int numOfLightTankOnQueue, numOfRocketTankOnQueue, numOfStealthTankOnQueue, numOfHarvesterOnQueue, numOfHeavyTankOnQueue, numOfDroneOnQueue, numOfMCVOnQueue; + public int numOfDrones; + public boolean isDeliveringUnit, doorOpened, doorClosed, openingDoor, closingDoor; + public float doorHeightMark; + public boolean doorHeightMarked; + public solidObject deliveredUnit; + + + public static int lightTankType = 0; + public static int rocketTankType = 1; + public static int harvesterType = 2; + public static int droneType = 5; + public static int MCVType = 3; + public static int stealthTankType = 4; + public static int heavyTankType = 6; + + public int currentStatus; + public static int isBuilding = 1; + public static int isIdle = 0; + + public vector rallyCenter; + public vector[] rallyPoints; + public boolean rallyPointChanged; + + public goldMine targetGoldMine; + + public drone[] myDrones; + + + + public factory(float x, float y, float z, int teamNo){ + //uncontrollable unit, but act as a big sized static collidable agent + type = 105; + + currentHP = 850; + + myDrones = new drone[3]; + + if(teamNo == 0){ + isRevealed = true; + theBaseInfo = mainThread.pc.theBaseInfo; + }else{ + theBaseInfo = mainThread.ec.theBaseInfo; + } + + theBaseInfo.numberOfFactory++; + + this.teamNo = teamNo; + + ID = globalUniqID++; + + currentCommand = StandBy; + + if(teamNo == 0){ + isRevealed = true; + } + + if(bitmapVisionForEnemy == null){ + bitmapVisionForEnemy = createBitmapVision(8); + } + + lightTankProgress = 255; + droneProgress = 255; + rocketTankProgress = 255; + harvesterProgress = 255; + stealthTankProgress = 255; + heavyTankProgress = 255; + MCVProgress = 255; + + //create 2D boundary + boundary2D = new Rect((int)(x*64) - 24, (int)(z*64) + 16, 48, 32); + boundary2D.owner = this; + int centerX = (int)(x*64); + int centerY = (int)(z*64); + + tileIndex[0] = (centerX - 16)/16 + (127 - (centerY + 8)/16)*128; + tileIndex[1] = (centerX + 16)/16 + (127 - (centerY + 8)/16)*128; + tileIndex[2] = (centerX + 16)/16 + (127 - (centerY - 8)/16)*128; + tileIndex[3] = (centerX - 16)/16 + (127 - (centerY - 8)/16)*128; + tileIndex[4] = (centerX)/16 + (127 - (centerY + 8)/16)*128; + tileIndex[5] = (centerX)/16 + (127 - (centerY - 8)/16)*128; + + + + mainThread.gridMap.tiles[tileIndex[0]][0] = this; + mainThread.gridMap.tiles[tileIndex[1]][0] = this; + mainThread.gridMap.tiles[tileIndex[2]][0] = this; + mainThread.gridMap.tiles[tileIndex[3]][0] = this; + mainThread.gridMap.tiles[tileIndex[4]][0] = this; + mainThread.gridMap.tiles[tileIndex[5]][0] = this; + + + mainThread.gridMap.tiles[tileIndex[0]][1] = this; + mainThread.gridMap.tiles[tileIndex[1]][1] = this; + mainThread.gridMap.tiles[tileIndex[2]][1] = this; + mainThread.gridMap.tiles[tileIndex[3]][1] = this; + mainThread.gridMap.tiles[tileIndex[4]][1] = this; + mainThread.gridMap.tiles[tileIndex[5]][1] = this; + + mainThread.gridMap.tiles[tileIndex[0]][2] = this; + mainThread.gridMap.tiles[tileIndex[1]][2] = this; + mainThread.gridMap.tiles[tileIndex[2]][2] = this; + mainThread.gridMap.tiles[tileIndex[3]][2] = this; + mainThread.gridMap.tiles[tileIndex[4]][2] = this; + mainThread.gridMap.tiles[tileIndex[5]][2] = this; + + mainThread.gridMap.tiles[tileIndex[0]][3] = this; + mainThread.gridMap.tiles[tileIndex[1]][3] = this; + mainThread.gridMap.tiles[tileIndex[2]][3] = this; + mainThread.gridMap.tiles[tileIndex[3]][3] = this; + mainThread.gridMap.tiles[tileIndex[4]][3] = this; + mainThread.gridMap.tiles[tileIndex[5]][3] = this; + + + mainThread.gridMap.tiles[tileIndex[0]][4] = this; + mainThread.gridMap.tiles[tileIndex[1]][4] = this; + mainThread.gridMap.tiles[tileIndex[2]][4] = this; + mainThread.gridMap.tiles[tileIndex[3]][4] = this; + mainThread.gridMap.tiles[tileIndex[4]][4] = this; + mainThread.gridMap.tiles[tileIndex[5]][4] = this; + + int tileIndex6 = tileIndex[5] + 128; + int tileIndex7 = tileIndex[5] + 128 - 1; + int tileIndex8 = tileIndex[5] + 128 + 1; + mainThread.gridMap.tiles[tileIndex6][4] = this; + mainThread.gridMap.tiles[tileIndex7][4] = this; + mainThread.gridMap.tiles[tileIndex8][4] = this; + + + //init model + start = new vector(x,y,z); + iDirection = new vector(1f,0,0); + jDirection = new vector(0,1f,0); + kDirection = new vector(0,0,1f); + + + //define centre of the model in world coordinate + start = new vector(x,y,z); + centre = start.myClone(); + tempCentre = start.myClone(); + + shadowvertex0 =start.myClone(); + shadowvertex0.add(-0.45f,-0.2f, -0.3f); + tempshadowvertex0 = new vector(0,0,0); + + shadowvertex1 =start.myClone(); + shadowvertex1.add(-0.45f,-0.2f, 0.2f); + tempshadowvertex1 = new vector(0,0,0); + + shadowvertex2 =start.myClone(); + shadowvertex2.add(0.2f,-0.2f, -0.3f); + tempshadowvertex2 = new vector(0,0,0); + + shadowvertex3 =start.myClone(); + shadowvertex3.add(0.2f,-0.2f, 0.2f); + tempshadowvertex3 = new vector(0,0,0); + + makePolygons(); + + productionQueue = new byte[1000]; + for(int i = 0; i < productionQueue.length; i++) + productionQueue[i] = -1; + + doorClosed = true; + + rallyCenter = new vector(centre.x,-0.3f,centre.z-0.625f); + float l = 0.25f; + rallyPoints = new vector[]{ + new vector(0,0,-l-0.03f), new vector(l + 0.075f,0,-l-0.03f), new vector(-l -0.075f,0,-l-0.03f), + new vector(l+0.075f,0,0), new vector(-l-0.075f,0,0), new vector(0,0,0), + new vector(-l-0.1f,0,l), new vector(l,0,l), new vector(0,0,l) + + }; + + } + + + public void makePolygons(){ + polygons = new polygon3D[300]; + + int polyIndex; + + int factorySkin = 51; + int roofSkin = 44; + if(teamNo == 1) + roofSkin = 53; + + + //roof + v = new vector[]{put(-0.27, 0.56, 0.16), put(0.11, 0.56, 0.16), put(0.11, 0.56, 0.1), put(-0.27, 0.56, 0.1)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[roofSkin], 10,2,1)); + + v = new vector[]{put(0.11, 0.56, 0.16), put(-0.27, 0.56, 0.16), put(-0.27, 0.55, 0.16), put(0.11, 0.55, 0.16)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[roofSkin], 10,1,1)); + + v = new vector[]{put(0.11, 0.55, 0.1), put(-0.27, 0.55, 0.1), put(-0.27, 0.56, 0.1), put(0.11, 0.56, 0.1)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[roofSkin], 10,1,1)); + + v = new vector[]{put(0.11, 0.56, 0.1), put(0.11, 0.56, 0.16), put(0.204, 0.3, 0.16), put(0.204, 0.3, 0.1)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[roofSkin], 1,10,1)); + + v = new vector[]{put(0.11, 0.56, 0.1), put(0.204, 0.3, 0.1), put(0.19, 0.3, 0.1), put(0.094, 0.56, 0.1)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[roofSkin], 10,10,1)); + + v = new vector[]{put(0.094, 0.56, 0.16), put(0.19, 0.3, 0.16), put(0.204, 0.3, 0.16), put(0.11, 0.56, 0.16)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[roofSkin], 10,10,1)); + + v = new vector[]{put(-0.27, 0.56, 0.16), put(-0.27, 0.56, 0.1), put(-0.364, 0.3, 0.1), put(-0.364, 0.3, 0.16)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[roofSkin], 1,10,1)); + + v = new vector[]{put(-0.27, 0.56, 0.16), put(-0.364, 0.3, 0.16), put(-0.35, 0.3, 0.16), put(-0.255, 0.56, 0.16)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[roofSkin], 10,10,1)); + + v = new vector[]{put(-0.255, 0.56, 0.1), put(-0.35, 0.3, 0.1), put(-0.364, 0.3, 0.1), put(-0.27, 0.56, 0.1)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[roofSkin], 10,10,1)); + + start.z-=0.27f; + v = new vector[]{put(-0.27, 0.56, 0.16), put(0.11, 0.56, 0.16), put(0.11, 0.56, 0.1), put(-0.27, 0.56, 0.1)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[roofSkin], 10,2,1)); + + v = new vector[]{put(0.11, 0.56, 0.16), put(-0.27, 0.56, 0.16), put(-0.27, 0.55, 0.16), put(0.11, 0.55, 0.16)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[roofSkin], 10,1,1)); + + v = new vector[]{put(0.11, 0.55, 0.1), put(-0.27, 0.55, 0.1), put(-0.27, 0.56, 0.1), put(0.11, 0.56, 0.1)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[roofSkin], 10,1,1)); + + v = new vector[]{put(0.11, 0.56, 0.1), put(0.11, 0.56, 0.16), put(0.204, 0.3, 0.16), put(0.204, 0.3, 0.1)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[roofSkin], 1,10,1)); + + v = new vector[]{put(0.11, 0.56, 0.1), put(0.204, 0.3, 0.1), put(0.19, 0.3, 0.1), put(0.094, 0.56, 0.1)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[roofSkin], 10,10,1)); + + v = new vector[]{put(0.094, 0.56, 0.16), put(0.19, 0.3, 0.16), put(0.204, 0.3, 0.16), put(0.11, 0.56, 0.16)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[roofSkin], 10,10,1)); + + v = new vector[]{put(-0.27, 0.56, 0.16), put(-0.27, 0.56, 0.1), put(-0.364, 0.3, 0.1), put(-0.364, 0.3, 0.16)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[roofSkin], 1,10,1)); + + v = new vector[]{put(-0.27, 0.56, 0.16), put(-0.364, 0.3, 0.16), put(-0.35, 0.3, 0.16), put(-0.255, 0.56, 0.16)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[roofSkin], 10,10,1)); + + v = new vector[]{put(-0.255, 0.56, 0.1), put(-0.35, 0.3, 0.1), put(-0.364, 0.3, 0.1), put(-0.27, 0.56, 0.1)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[roofSkin], 10,10,1)); + start.z+=0.27f; + + + + + //main structure + v = new vector[]{put(-0.26, 0.55, 0.24), put(-0.26, 0.55, -0.24), put(-0.35, 0.3, -0.24), put(-0.35, 0.3, 0.24)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[factorySkin], 1,1,1)); + polygons[polyIndex].shadowBias = 10000; + + v = new vector[]{put(0.19, 0.3, 0.24), put(0.19, 0.3, -0.24), put(0.1, 0.55, -0.24), put(0.1, 0.55, 0.24)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[factorySkin], 1,1,1)); + polygons[polyIndex].shadowBias = 10000; + + v = new vector[]{put(-0.26, 0.55, 0.24), put(0.1, 0.55, 0.24), put(0.1, 0.55, -0.24), put(-0.26, 0.55, -0.24)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[factorySkin], 1,1,1)); + polygons[polyIndex].shadowBias = 10000; + + + v = new vector[]{put(0.085, 0.55, 0.24),put(0.085, 0.55, -0.24), put(0.175, 0.3, -0.24), put(0.175, 0.3, 0.24)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[factorySkin], 1,1,1)); + + v = new vector[]{put(0.085, 0.55, 0.24), put(0.175, 0.3, 0.24), put(0.19, 0.3, 0.24), put(0.1, 0.55, 0.24)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[factorySkin], 1,1,1)); + + + v = new vector[]{put(-0.335, 0.3, 0.24), put(-0.335, 0.3, -0.24), put(-0.245, 0.55, -0.24), put(-0.245, 0.55, 0.24)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[factorySkin], 1,1,1)); + + v = new vector[]{put(-0.245, 0.55, 0.24), put(-0.26, 0.55, 0.24), put(-0.35, 0.3, 0.24),put(-0.335, 0.3, 0.24)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[factorySkin], 1,1,1)); + + + + v = new vector[]{put(0.1, 0.55, 0.225), put(-0.26, 0.55, 0.225), put(-0.35, 0.3, 0.225), put(0.19, 0.3, 0.225)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[factorySkin], 1,1,1)); + polygons[polyIndex].shadowBias = 10000; + + v = new vector[]{put(0.1, 0.55, 0.24), put(-0.26, 0.55, 0.24), put(-0.26, 0.535, 0.24), put(0.1, 0.535, 0.24)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[factorySkin], 1,1,1)); + + v = new vector[]{put(0.1, 0.535, -0.24), put(-0.26, 0.535, -0.24), put(-0.26, 0.55, -0.24), put(0.1, 0.55, -0.24)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[factorySkin], 1,1,1)); + + v = new vector[]{put(0.1, 0.55, -0.24), put(0.19, 0.3, -0.24), put(0.175, 0.3, -0.24), put(0.085, 0.55, -0.24)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[factorySkin], 1,1,1)); + + v = new vector[]{put(-0.335, 0.3, -0.24), put(-0.35, 0.3, -0.24), put(-0.26, 0.55, -0.24),put(-0.245, 0.55, -0.24)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[factorySkin], 1,1,1)); + + v = new vector[]{put(-0.26, 0.55, -0.225),put(-0.21, 0.55, -0.225), put(-0.21, 0.3, -0.225), put(-0.35, 0.3, -0.225), }; + polyIndex = addPolygon(polygons, new polygon3D(v, put(-0.26, 0.55, -0.225), put(0.1, 0.55, -0.225), put(-0.26, 0, -0.225), mainThread.textures[12], 1,1,1)); + polygons[polyIndex].diffuse_I-=5; + + v = new vector[]{ put(0.05, 0.55, -0.225),put(0.1, 0.55, -0.225),put(0.19, 0.3, -0.225), put(0.05, 0.3, -0.225)}; + polyIndex = addPolygon(polygons, new polygon3D(v, put(-0.26, 0.55, -0.225), put(0.1, 0.55, -0.225), put(-0.26, 0, -0.225), mainThread.textures[12], 1,1,1)); + polygons[polyIndex].diffuse_I-=5; + + v= new vector[]{put(-0.21, 0.55, -0.225), put(0.05, 0.55, -0.225), put(0.05, 0.5, -0.225), put(-0.21, 0.5, -0.225)}; + polyIndex = addPolygon(polygons, new polygon3D(v, put(-0.26, 0.55, -0.225), put(0.1, 0.55, -0.225), put(-0.26, 0, -0.225), mainThread.textures[12], 1,1,1)); + polygons[polyIndex].diffuse_I-=5; + + v = new vector[]{put(-0.21, 0.55, -0.225), put(-0.21, 0.55, -0.19), put(-0.21, 0.3, -0.19), put(-0.21, 0.3, -0.225)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[27], 0.1f,0.7f,1)); + + v = new vector[]{put(0.05, 0.55, -0.19), put(0.05, 0.55, -0.225),put(0.05, 0.3, -0.225), put(0.05, 0.3, -0.19)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[27], 0.1f,0.7f,1)); + + + int doorIndex = 31; + if(teamNo != 0) + doorIndex = 32; + + + //door lower + float a = -0.215f; + float b = a +0.03f; + float c = b + 0.01f; + float d = c + 0.03f; + float e = d + 0.01f; + float f = e + 0.03f; + float g = f + 0.01f; + float h = g + 0.03f; + float i = h + 0.01f; + float j = i + 0.03f; + float k = j + 0.01f; + float l = k + 0.03f; + float m = l + 0.01f; + float n = m + 0.03f; + + + + v = new vector[]{put(-0.21, 0.38, -0.215), put(0.05, 0.38, -0.215), put(0.05, 0.3, -0.215), put(-0.21, 0.3, -0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[36], 1,0.5f,1)); + + float v1 = a; + float v2 = a; + float v3 = b; + float v4 = c; + float v5 = d; + + + v = new vector[]{put(v1, 0.38, -0.215), put(v2, 0.42, -0.215),put(v3, 0.42, -0.215), put(v4, 0.38, -0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v,put(-0.21, 0.42, -0.215), put(0.05, 0.42, -0.215), put(-0.21, 0.38, -0.215), mainThread.textures[doorIndex], 7,0.7f,1)); + + v = new vector[]{put(v2, 0.42, -0.205), put(v2, 0.42, -0.215), put(v1, 0.38, -0.215), put(v1, 0.38, -0.205)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[27], 0.1f,0.8f,1)); + + v = new vector[]{put(v2, 0.42, -0.215), put(v2, 0.42, -0.205), put(v3, 0.42, -0.205), put(v3, 0.42, -0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[27], 0.1f,0.8f,1)); + + v = new vector[]{put(v3, 0.42, -0.215), put(v3, 0.42, -0.205), put(v4, 0.38, -0.205), put(v4, 0.38, -0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[27], 0.1f,0.8f,1)); + + v = new vector[]{put(v4, 0.38, -0.215), put(v4, 0.38, -0.205), put(v5, 0.38, -0.205), put(v5, 0.38, -0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[27], 0.1f,0.8f,1)); + + v1 = d; + v2 = e; + v3 = f; + v4 = g; + v5 = h; + + + v = new vector[]{put(v1, 0.38, -0.215), put(v2, 0.42, -0.215),put(v3, 0.42, -0.215), put(v4, 0.38, -0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v,put(-0.21, 0.42, -0.215), put(0.05, 0.42, -0.215), put(-0.21, 0.38, -0.215), mainThread.textures[doorIndex], 7,0.7f,1)); + + v = new vector[]{put(v2, 0.42, -0.205), put(v2, 0.42, -0.215), put(v1, 0.38, -0.215), put(v1, 0.38, -0.205)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[27], 0.1f,1f,1)); + + v = new vector[]{put(v2, 0.42, -0.215), put(v2, 0.42, -0.205), put(v3, 0.42, -0.205), put(v3, 0.42, -0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[27], 0.1f,1f,1)); + + v = new vector[]{put(v3, 0.42, -0.215), put(v3, 0.42, -0.205), put(v4, 0.38, -0.205), put(v4, 0.38, -0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[27], 0.1f,1f,1)); + + v = new vector[]{put(v4, 0.38, -0.215), put(v4, 0.38, -0.205), put(v5, 0.38, -0.205), put(v5, 0.38, -0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[27], 0.1f,1f,1)); + + v1 = h; + v2 = i; + v3 = j; + v4 = k; + v5 = l; + + + v = new vector[]{put(v1, 0.38, -0.215), put(v2, 0.42, -0.215),put(v3, 0.42, -0.215), put(v4, 0.38, -0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v,put(-0.21, 0.42, -0.215), put(0.05, 0.42, -0.215), put(-0.21, 0.38, -0.215), mainThread.textures[doorIndex], 7,0.7f,1)); + + v = new vector[]{put(v2, 0.42, -0.205), put(v2, 0.42, -0.215), put(v1, 0.38, -0.215), put(v1, 0.38, -0.205)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[27], 0.1f,1f,1)); + + v = new vector[]{put(v2, 0.42, -0.215), put(v2, 0.42, -0.205), put(v3, 0.42, -0.205), put(v3, 0.42, -0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[27], 0.1f,1f,1)); + + v = new vector[]{put(v3, 0.42, -0.215), put(v3, 0.42, -0.205), put(v4, 0.38, -0.205), put(v4, 0.38, -0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[27], 0.1f,1f,1)); + + v = new vector[]{put(v4, 0.38, -0.215), put(v4, 0.38, -0.205), put(v5, 0.38, -0.205), put(v5, 0.38, -0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[27], 0.1f,1f,1)); + + v1 = l; + v2 = m; + v3 = n; + v4 = n; + + + + v = new vector[]{put(v1, 0.38, -0.215), put(v2, 0.42, -0.215),put(v3, 0.42, -0.215), put(v4, 0.38, -0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v,put(-0.21, 0.42, -0.215), put(0.05, 0.42, -0.215), put(-0.21, 0.38, -0.215), mainThread.textures[doorIndex], 7,0.7f,1)); + + v = new vector[]{put(v2, 0.42, -0.205), put(v2, 0.42, -0.215), put(v1, 0.38, -0.215), put(v1, 0.38, -0.205)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[27], 0.1f,1f,1)); + + v = new vector[]{put(v2, 0.42, -0.215), put(v2, 0.42, -0.205), put(v3, 0.42, -0.205), put(v3, 0.42, -0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[27], 0.1f,1f,1)); + + v = new vector[]{put(v3, 0.42, -0.215), put(v3, 0.42, -0.205), put(v4, 0.38, -0.205), put(v4, 0.38, -0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[27], 0.1f,1f,1)); + + + doorLower = new polygon3D[20]; + for(int count = 34; count < 54; count++){ + doorLower[count - 34] = polygons[count]; + } + + + + + //door upper + v = new vector[]{put(-0.21, 0.57, -0.215), put(0.05, 0.57, -0.215), put(0.05, 0.42, -0.215), put(-0.21, 0.42, -0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[36], 1,0.5f,1)); + + v = new vector[]{put(-0.21, 0.42, -0.205), put(0.05, 0.42, -0.205), put(0.05, 0.57, -0.205), put(-0.21, 0.57, -0.205)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[36], 1,0.5f,1)); + + v = new vector[]{put(-0.21, 0.57, -0.215), put(-0.21, 0.57, -0.205), put(0.05, 0.57, -0.205), put(0.05, 0.57, -0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[36], 0.1f,1f,1)); + + v = new vector[]{put(-0.21, 0.57, -0.205), put(-0.21, 0.57, -0.215), put(-0.21, 0.42, -0.215), put(-0.21, 0.42, -0.205)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[36], 0.1f,1f,1)); + + v = new vector[]{put(0.05, 0.42, -0.205), put(0.05, 0.42, -0.215), put(0.05, 0.57, -0.215), put(0.05, 0.57, -0.205)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[36], 0.1f,1f,1)); + + + v1 = b; + v2 = e; + v3 = d; + v4 = c; + + v = new vector[]{put(v1, 0.42,-0.215), put(v2, 0.42,-0.215), put(v3, 0.38,-0.215), put(v4, 0.38,-0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v,put(-0.21, 0.42, -0.215), put(0.05, 0.42, -0.215), put(-0.21, 0.38, -0.215), mainThread.textures[doorIndex], 7,0.7f,1)); + + v = new vector[]{put(v2, 0.42,-0.215), put(v2, 0.42,-0.205), put(v3, 0.38,-0.205),put(v3, 0.38,-0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[27], 0.1f,1f,1)); + + v = new vector[]{put(v1, 0.42,-0.205), put(v1, 0.42,-0.215), put(v4, 0.38,-0.215), put(v4, 0.38,-0.205)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[27], 0.1f,1f,1)); + + v1 = f; + v2 = i; + v3 = h; + v4 = g; + + v = new vector[]{put(v1, 0.42,-0.215), put(v2, 0.42,-0.215), put(v3, 0.38,-0.215), put(v4, 0.38,-0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v,put(-0.21, 0.42, -0.215), put(0.05, 0.42, -0.215), put(-0.21, 0.38, -0.215), mainThread.textures[doorIndex], 7,0.7f,1)); + + v = new vector[]{put(v2, 0.42,-0.215), put(v2, 0.42,-0.205), put(v3, 0.38,-0.205),put(v3, 0.38,-0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[27], 0.1f,1f,1)); + + v = new vector[]{put(v1, 0.42,-0.205), put(v1, 0.42,-0.215), put(v4, 0.38,-0.215), put(v4, 0.38,-0.205)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[27], 0.1f,1f,1)); + + v1 = j; + v2 = m; + v3 = l; + v4 = k; + + v = new vector[]{put(v1, 0.42,-0.215), put(v2, 0.42,-0.215), put(v3, 0.38,-0.215), put(v4, 0.38,-0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v,put(-0.21, 0.42, -0.215), put(0.05, 0.42, -0.215), put(-0.21, 0.38, -0.215), mainThread.textures[doorIndex], 7,0.7f,1)); + + v = new vector[]{put(v2, 0.42,-0.215), put(v2, 0.42,-0.205), put(v3, 0.38,-0.205),put(v3, 0.38,-0.215)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[27], 0.1f,1f,1)); + + v = new vector[]{put(v1, 0.42,-0.205), put(v1, 0.42,-0.215), put(v4, 0.38,-0.215), put(v4, 0.38,-0.205)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[27], 0.1f,1f,1)); + + doorUpper = new polygon3D[14]; + for(int count = 54; count < 68; count++){ + doorUpper[count - 54] = polygons[count]; + } + + + //power tower A + float r = 0.08f; + float delta = (float)Math.PI/8; + float w = 0.29f; + h = 0.12f; + powerTowerCenterA = put(w, 0, h); + + for(i = 0; i < 16; i++){ + v = new vector[]{put(r*Math.cos(i*delta) + w, 0.5, r*Math.sin(i*delta) + h), + put(r*Math.cos((i+1)*delta) + w, 0.5, r*Math.sin((i+1)*delta)+h), + put(r*Math.cos((i+1)*delta) + w, 0.3, r*Math.sin((i+1)*delta)+h), + put(r*Math.cos(i*delta) + w, 0.3, r*Math.sin(i*delta)+h) + }; + + tempVector.set(v[1]); + tempVector.subtract(v[0]); + tempVector0.set(v[0]); + tempVector1.set(v[1]); + tempVector3.set(v[3]); + tempVector1.add(tempVector); + + int p = (int)i % 8; + for(j = 0; j < p; j++){ + tempVector0.subtract(tempVector); + tempVector1.subtract(tempVector); + tempVector3.subtract(tempVector); + } + + change(w,0.5f,h, tempVector); + polyIndex = addPolygon(polygons, new polygon3D(v, tempVector0.myClone(),tempVector1.myClone(), tempVector3.myClone(), mainThread.textures[12], 1f,1f,1)); + polygons[polyIndex].textureScaledWidth = (int)(polygons[polyIndex].myTexture.width*0.5); + polygons[polyIndex].createShadeSpan(tempVector, v[0].myClone(), v[1]); + } + + float r1= r - 0.02f; + for(i = 0; i < 16; i++){ + v = new vector[]{put(r1*Math.cos(i*delta) + w, 0.515, r1*Math.sin(i*delta) + h), + put(r1*Math.cos((i+1)*delta) + w, 0.515, r1*Math.sin((i+1)*delta)+h), + put(r*Math.cos((i+1)*delta) + w, 0.5, r*Math.sin((i+1)*delta)+h), + put(r*Math.cos(i*delta) + w, 0.5, r*Math.sin(i*delta)+h) + }; + + + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(),v[1].myClone(), v[3].myClone(), mainThread.textures[12], 0.1f,0.1f,1)); + } + + for(i = 0; i < 16; i++){ + v = new vector[]{ put(r1*Math.cos(i*delta) + w, 0.3, r1*Math.sin(i*delta)+h), + put(r1*Math.cos((i+1)*delta) + w, 0.3, r1*Math.sin((i+1)*delta)+h), + put(r1*Math.cos((i+1)*delta) + w, 0.515, r1*Math.sin((i+1)*delta)+h), + put(r1*Math.cos(i*delta) + w, 0.515, r1*Math.sin(i*delta) + h) + }; + + + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(),v[1].myClone(), v[3].myClone(), mainThread.textures[12], 0.1f,1f,1)); + } + + float r2 = r1-0.035f; + v = new vector[16]; + for(i = 0; i < 16; i++){ + v[15 - (int)i] = put(r2*Math.cos((i+1)*delta) + w, 0.505, r2*Math.sin((i+1)*delta)+h); + } + polyIndex = addPolygon(polygons, new polygon3D(v, put(0,0.505, 1),put(1,0.505, 1), put(0,0.505, 0), mainThread.textures[26], 5f,5f,1)); + + for(i = 0; i < 16; i++){ + v = new vector[]{ put(r2*Math.cos(i*delta) + w, 0.505, r2*Math.sin(i*delta) + h), + put(r2*Math.cos((i+1)*delta) + w, 0.505, r2*Math.sin((i+1)*delta)+h), + put(r2*Math.cos((i+1)*delta) + w, 0.47, r2*Math.sin((i+1)*delta)+h), + put(r2*Math.cos(i*delta) + w, 0.47, r2*Math.sin(i*delta)+h) + }; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(),v[1].myClone(), v[3].myClone(), mainThread.textures[26], 1f,1f,1)); + } + + float r3 = r2 + 0.03f; + fanA = new polygon3D[32]; + for(i = 0; i < 16; i++){ + v = new vector[]{put(w,0.505, h), put(r3*Math.cos(i*delta) + w, 0.505, r3*Math.sin(i*delta) + h), put(r3*Math.cos(i*delta) + w, 0.47, r3*Math.sin(i*delta) + h), put(w,0.47, h)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(),v[1].myClone(), v[3].myClone(), mainThread.textures[25], 1f,1f,1)); + fanA[(int)i*2] = polygons[polyIndex]; + + v = new vector[]{put(w,0.47, h), put(r3*Math.cos(i*delta) + w, 0.47, r3*Math.sin(i*delta) + h), put(r3*Math.cos(i*delta) + w, 0.505, r3*Math.sin(i*delta) + h), put(w,0.505, h)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(),v[1].myClone(), v[3].myClone(), mainThread.textures[25], 1f,1f,1)); + fanA[(int)i*2 + 1] = polygons[polyIndex]; + } + + + v = new vector[16]; + for(i = 0; i < 16; i++){ + v[15 - (int)i] = put(r1*Math.cos((i+1)*delta) + w, 0.49, r1*Math.sin((i+1)*delta)+h); + } + distortionA = addPolygon(polygons, new polygon3D(v, put(0,0.49, 1),put(1,0.49, 1), put(0,0.49, 0), mainThread.textures[54], 5f,5f,6)); + + + + + //power tower B + h = -0.12f; + powerTowerCenterB = put(w, 0, h); + + for(i = 0; i < 16; i++){ + v = new vector[]{put(r*Math.cos(i*delta) + w, 0.5, r*Math.sin(i*delta) + h), + put(r*Math.cos((i+1)*delta) + w, 0.5, r*Math.sin((i+1)*delta)+h), + put(r*Math.cos((i+1)*delta) + w, 0.3, r*Math.sin((i+1)*delta)+h), + put(r*Math.cos(i*delta) + w, 0.3, r*Math.sin(i*delta)+h) + }; + + tempVector.set(v[1]); + tempVector.subtract(v[0]); + tempVector0.set(v[0]); + tempVector1.set(v[1]); + tempVector3.set(v[3]); + tempVector1.add(tempVector); + + int p = (int)i % 8; + for(j = 0; j < p; j++){ + tempVector0.subtract(tempVector); + tempVector1.subtract(tempVector); + tempVector3.subtract(tempVector); + } + + change(w,0.5f,h, tempVector); + polyIndex = addPolygon(polygons, new polygon3D(v, tempVector0.myClone(),tempVector1.myClone(), tempVector3.myClone(), mainThread.textures[12], 1f,1f,1)); + polygons[polyIndex].textureScaledWidth = (int)(polygons[polyIndex].myTexture.width*0.5); + polygons[polyIndex].createShadeSpan(tempVector, v[0].myClone(), v[1]); + } + + r1= r - 0.02f; + for(i = 0; i < 16; i++){ + v = new vector[]{put(r1*Math.cos(i*delta) + w, 0.515, r1*Math.sin(i*delta) + h), + put(r1*Math.cos((i+1)*delta) + w, 0.515, r1*Math.sin((i+1)*delta)+h), + put(r*Math.cos((i+1)*delta) + w, 0.5, r*Math.sin((i+1)*delta)+h), + put(r*Math.cos(i*delta) + w, 0.5, r*Math.sin(i*delta)+h) + }; + + + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(),v[1].myClone(), v[3].myClone(), mainThread.textures[12], 0.1f,0.1f,1)); + } + + for(i = 0; i < 16; i++){ + v = new vector[]{ put(r1*Math.cos(i*delta) + w, 0.3, r1*Math.sin(i*delta)+h), + put(r1*Math.cos((i+1)*delta) + w, 0.3, r1*Math.sin((i+1)*delta)+h), + put(r1*Math.cos((i+1)*delta) + w, 0.515, r1*Math.sin((i+1)*delta)+h), + put(r1*Math.cos(i*delta) + w, 0.515, r1*Math.sin(i*delta) + h) + }; + + + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(),v[1].myClone(), v[3].myClone(), mainThread.textures[12], 0.1f,1f,1)); + } + + + v = new vector[16]; + for(i = 0; i < 16; i++){ + v[15 - (int)i] = put(r2*Math.cos((i+1)*delta) + w, 0.505, r2*Math.sin((i+1)*delta)+h); + } + polyIndex = addPolygon(polygons, new polygon3D(v, put(0,0.505, 1),put(1,0.505, 1), put(0,0.505, 0), mainThread.textures[26], 5f,5f,1)); + + for(i = 0; i < 16; i++){ + v = new vector[]{ put(r2*Math.cos(i*delta) + w, 0.505, r2*Math.sin(i*delta) + h), + put(r2*Math.cos((i+1)*delta) + w, 0.505, r2*Math.sin((i+1)*delta)+h), + put(r2*Math.cos((i+1)*delta) + w, 0.47, r2*Math.sin((i+1)*delta)+h), + put(r2*Math.cos(i*delta) + w, 0.47, r2*Math.sin(i*delta)+h) + }; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(),v[1].myClone(), v[3].myClone(), mainThread.textures[26], 1f,1f,1)); + } + + fanB = new polygon3D[32]; + for(i = 0; i < 16; i++){ + v = new vector[]{put(w,0.505, h), put(r3*Math.cos(i*delta) + w, 0.505, r3*Math.sin(i*delta) + h), put(r3*Math.cos(i*delta) + w, 0.47, r3*Math.sin(i*delta) + h), put(w,0.47, h)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(),v[1].myClone(), v[3].myClone(), mainThread.textures[25], 1f,1f,1)); + fanB[(int)i*2] = polygons[polyIndex]; + + v = new vector[]{put(w,0.47, h), put(r3*Math.cos(i*delta) + w, 0.47, r3*Math.sin(i*delta) + h), put(r3*Math.cos(i*delta) + w, 0.505, r3*Math.sin(i*delta) + h), put(w,0.505, h)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(),v[1].myClone(), v[3].myClone(), mainThread.textures[25], 1f,1f,1)); + fanB[(int)i*2 + 1] = polygons[polyIndex]; + } + + v = new vector[16]; + for(i = 0; i < 16; i++){ + v[15 - (int)i] = put(r1*Math.cos((i+1)*delta) + w, 0.48, r1*Math.sin((i+1)*delta)+h); + } + distortionB = addPolygon(polygons, new polygon3D(v, put(0,0.48, 1),put(1,0.48, 1), put(0,0.48, 0), mainThread.textures[54], 5f,5f,6)); + + + + //Concrete foundation + v = new vector[]{put(-0.38, 0.3, -0.2), put(0.38, 0.3, -0.2), put(0.38, 0.3, -0.225), put(0.345, 0.3, -0.26), put(-0.345, 0.3, -0.26), put(-0.38, 0.3, -0.225)}; + polyIndex = addPolygon(polygons, new polygon3D(v, put(-0.38, 0.3, 0.26), put(0.38, 0.3, 0.26), put(-0.38, 0.3, -0.26), mainThread.textures[30], 1,1,1)); + polygons[polyIndex].shadowBias = 5000; + + v = new vector[]{put(-0.38, 0.3, 0.225), put(-0.345, 0.3, 0.26), put(0.345, 0.3, 0.26), put(0.38, 0.3, 0.225), put(0.38, 0.3, 0.2), put(-0.38, 0.3, 0.2)}; + polyIndex = addPolygon(polygons, new polygon3D(v, put(-0.38, 0.3, 0.26), put(0.38, 0.3, 0.26), put(-0.38, 0.3, -0.26), mainThread.textures[30], 1,1,1)); + polygons[polyIndex].shadowBias = 5000; + + v = new vector[]{put(-0.14, 0.3, 0.225), put(0.38, 0.3, 0.225), put(0.38, 0.3, -0.225), put(-0.14, 0.3, -0.225) }; + polyIndex = addPolygon(polygons, new polygon3D(v, put(-0.38, 0.3, 0.26), put(0.38, 0.3, 0.26), put(-0.38, 0.3, -0.26), mainThread.textures[30], 1,1,1)); + polygons[polyIndex].shadowBias = 5000; + + v = new vector[]{put(-0.38, 0.3, 0.225), put(-0.33, 0.3, 0.225), put(-0.33, 0.3, -0.225), put(-0.38, 0.3, -0.225) }; + polyIndex = addPolygon(polygons, new polygon3D(v, put(-0.38, 0.3, 0.26), put(0.38, 0.3, 0.26), put(-0.38, 0.3, -0.26), mainThread.textures[30], 1,1,1)); + polygons[polyIndex].shadowBias = 5000; + + v = new vector[]{put(-0.345, 0.3, 0.225), put(-0.14, 0.3, 0.225), put(-0.14, 0.3, -0.225), put(-0.345, 0.3, -0.225) }; + polyIndex = addPolygon(polygons, new polygon3D(v, put(-0.38, 0.3, 0.26), put(0.38, 0.3, 0.26), put(-0.38, 0.3, -0.26), mainThread.textures[30], 1,1,1)); + polygons[polyIndex].shadowBias = 5000; + + v = new vector[]{put(-0.345, 0.3, -0.26), put(0.345, 0.3, -0.26), put(0.345, 0.28, -0.26), put(-0.345, 0.28, -0.26)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[30], 1,1f,1)); + polygons[polyIndex].shadowBias = 5000; + + v = new vector[]{put(-0.345, 0.28,0.26), put(0.345, 0.28, 0.26), put(0.345, 0.3, 0.26), put(-0.345, 0.3, 0.26)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[30], 1,1f,1)); + + v = new vector[]{put(-0.38, 0.3, 0.225), put(-0.38, 0.3, -0.225), put(-0.38, 0.28, -0.225), put(-0.38, 0.28, 0.225)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[30], 1,1f,1)); + + v = new vector[]{put(0.38, 0.28, 0.225), put(0.38, 0.28, -0.225), put(0.38, 0.3, -0.225), put(0.38, 0.3, 0.225)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[30], 1,1f,1)); + + v = new vector[]{put(-0.345, 0.3, 0.26), put(-0.38, 0.3, 0.225), put(-0.38, 0.28, 0.225), put(-0.345, 0.28, 0.26)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[30], 1,1f,1)); + + v = new vector[]{put(0.345, 0.28, 0.26), put(0.38, 0.28, 0.225), put(0.38, 0.3, 0.225), put(0.345, 0.3, 0.26)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[30], 1,1f,1)); + + v = new vector[]{put(-0.345, 0.28, -0.26), put(-0.38, 0.28, -0.225), put(-0.38, 0.3, -0.225), put(-0.345, 0.3, -0.26)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[30], 1,1f,1)); + + v = new vector[]{put(0.345, 0.3, -0.26), put(0.38, 0.3, -0.225), put(0.38, 0.28, -0.225), put(0.345, 0.28, -0.26)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[30], 1,1f,1)); + + + for(int z = 0; z < numOfPolygons; z++){ + polygons[z].findDiffuse(); + polygons[z].parentObject = this; + + } + } + + + public int addPolygon(polygon3D[] polys, polygon3D poly){ + for(int i = 0; i < polys.length; i++){ + if(polys[i] == null){ + polys[i] = poly; + numOfPolygons++; + return i; + } + } + return -1; + } + + //update the model + public void update(){ + + //update tech tree info + canBuildLightTank = theBaseInfo.canBuildLightTank; + canBuildRocketTank = theBaseInfo.canBuildRocketTank; + canBuildHarvester = theBaseInfo.canBuildHarvester; + canBuildDrone = theBaseInfo.canBuildDrone; + canBuildMCV = theBaseInfo.canBuildMCV; + canBuildStealthTank = theBaseInfo.canBuildStealthTank; + canBuildHeavyTank = theBaseInfo.canBuildHeavyTank; + + + //process emerging from ground animation + if(centre.y < -0.79f){ + centre.y+=0.02f; + + float delta_h = 0.02f; + if(centre.y > -0.79f){ + delta_h = 0.02f -0.79f - centre.y; + centre.y = -0.79f; + } + + for(int i = 0; i < numOfPolygons; i++){ + polygons[i].origin.y+=delta_h; + polygons[i].rightEnd.y+=delta_h; + polygons[i].bottomEnd.y+=delta_h; + + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + polygons[i].vertex3D[j].y+=delta_h; + } + } + + shadowvertex0.y+=delta_h; + shadowvertex1.y+=delta_h; + shadowvertex2.y+=delta_h; + shadowvertex3.y+=delta_h; + + + //the building is invulnerable during emerging stage + currentHP = maxHP; + } + + if(underAttackCountDown > 0) + underAttackCountDown--; + + + //check if building has been destroyed + if(currentHP <= 0){ + countDownToDeath--; + + if(countDownToDeath == 0){ + //spawn an explosion when the object is destroyed + float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount]; + tempFloat[0] = centre.x; + tempFloat[1] = centre.y + 0.45f; + tempFloat[2] = centre.z; + tempFloat[3] = 3.5f; + tempFloat[4] = 1; + tempFloat[5] = 0; + tempFloat[6] = 7; + tempFloat[7] = this.height; + theAssetManager.explosionCount++; + theAssetManager.removeObject(this); + + + //removeFromGridMap(); + mainThread.gridMap.tiles[tileIndex[0]][0] = null; + mainThread.gridMap.tiles[tileIndex[1]][0] = null; + mainThread.gridMap.tiles[tileIndex[2]][0] = null; + mainThread.gridMap.tiles[tileIndex[3]][0] = null; + mainThread.gridMap.tiles[tileIndex[4]][0] = null; + mainThread.gridMap.tiles[tileIndex[5]][0] = null; + + + mainThread.gridMap.tiles[tileIndex[0]][1] = null; + mainThread.gridMap.tiles[tileIndex[1]][1] = null; + mainThread.gridMap.tiles[tileIndex[2]][1] = null; + mainThread.gridMap.tiles[tileIndex[3]][1] = null; + mainThread.gridMap.tiles[tileIndex[4]][1] = null; + mainThread.gridMap.tiles[tileIndex[5]][1] = null; + + mainThread.gridMap.tiles[tileIndex[0]][2] = null; + mainThread.gridMap.tiles[tileIndex[1]][2] = null; + mainThread.gridMap.tiles[tileIndex[2]][2] = null; + mainThread.gridMap.tiles[tileIndex[3]][2] = null; + mainThread.gridMap.tiles[tileIndex[4]][2] = null; + mainThread.gridMap.tiles[tileIndex[5]][2] = null; + + mainThread.gridMap.tiles[tileIndex[0]][3] = null; + mainThread.gridMap.tiles[tileIndex[1]][3] = null; + mainThread.gridMap.tiles[tileIndex[2]][3] = null; + mainThread.gridMap.tiles[tileIndex[3]][3] = null; + mainThread.gridMap.tiles[tileIndex[4]][3] = null; + mainThread.gridMap.tiles[tileIndex[5]][3] = null; + + + mainThread.gridMap.tiles[tileIndex[0]][4] = null; + mainThread.gridMap.tiles[tileIndex[1]][4] = null; + mainThread.gridMap.tiles[tileIndex[2]][4] = null; + mainThread.gridMap.tiles[tileIndex[3]][4] = null; + mainThread.gridMap.tiles[tileIndex[4]][4] = null; + mainThread.gridMap.tiles[tileIndex[5]][4] = null; + + int tileIndex6 = tileIndex[5] + 128; + int tileIndex7 = tileIndex[5] + 128 - 1; + int tileIndex8 = tileIndex[5] + 128 + 1; + mainThread.gridMap.tiles[tileIndex6][4] = null; + mainThread.gridMap.tiles[tileIndex7][4] = null; + mainThread.gridMap.tiles[tileIndex8][4] = null; + + + theBaseInfo.numberOfFactory--; + + if(deliveredUnit != null) + deliveredUnit.disableUnitLevelAI = false; + + cancelBuilding(); + + if(attacker.teamNo != teamNo) + attacker.experience+=40; + + return; + }else{ + + float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount]; + tempFloat[0] = centre.x + (float)Math.random()*0.6f - 0.3f; + tempFloat[1] = centre.y + 0.45f; + tempFloat[2] = centre.z + (float)Math.random()/2.5f - 0.2f; + tempFloat[3] = 1.5f; + tempFloat[4] = 1; + tempFloat[5] = 0; + tempFloat[6] = 6 + (gameData.getRandom()%4); + tempFloat[7] = this.height; + theAssetManager.explosionCount++; + + } + } + + if(isRepairing && currentHP >0){ + if(mainThread.frameIndex%8==0 && theBaseInfo.currentCredit > 0 && currentHP maxHP) + currentHP = maxHP; + } + } + + //process building event (at half speed when lower power) + if(currentStatus == isBuilding){ + + if(!(theBaseInfo.lowPower && mainThread.frameIndex%2==0)){ + + //light tank event + if(lightTankProgress < 240){ + grayAllOtherIcons(lightTankType, lightTankProgress); + if(theBaseInfo.currentCredit >0){ + + theBaseInfo.currentCredit--; + creditSpentOnBuilding++; + lightTankProgress = 240 * creditSpentOnBuilding/300; + } + } + if(lightTankProgress == 240){ + if(!isDeliveringUnit){ + lightTank o = new lightTank(new vector(centre.x -0.07f,-0.3f, centre.z - 0.03f), 180, teamNo); + + if(teamNo == 0 && techCenter.lightTankResearched_player){ + o.attackRange = 1.99f; + }else if(teamNo != 0 && techCenter.lightTankResearched_enemy){ + o.attackRange = 1.99f; + } + + deliveredUnit = o; + o.disableUnitLevelAI = true; + + mainThread.theAssetManager.addLightTank(o); + lightTankProgress = 255; + removelItemFromProductionQueue(lightTankType); + isDeliveringUnit = true; + } + } + + //rocket tank event + if(rocketTankProgress < 240){ + grayAllOtherIcons(rocketTankType, rocketTankProgress); + if(theBaseInfo.currentCredit >0){ + + theBaseInfo.currentCredit--; + creditSpentOnBuilding++; + rocketTankProgress = 240 * creditSpentOnBuilding/450; + } + } + if(rocketTankProgress == 240){ + if(!isDeliveringUnit){ + rocketTank o = new rocketTank(new vector(centre.x -0.07f,-0.3f, centre.z - 0.03f), 180, teamNo); + if(teamNo == 0 && techCenter.rocketTankResearched_player){ + o.damageMultiplier =2; + }else if(teamNo != 0 && techCenter.rocketTankResearched_enemy){ + o.damageMultiplier =2; + } + + deliveredUnit = o; + o.disableUnitLevelAI = true; + + mainThread.theAssetManager.addRocketTank(o); + rocketTankProgress = 255; + removelItemFromProductionQueue(rocketTankType); + isDeliveringUnit = true; + } + } + + //harvester event + if(harvesterProgress < 240){ + grayAllOtherIcons(harvesterType, harvesterProgress); + + if(!canBuildHarvester){ + int num = numOfHarvesterOnQueue; + for(int i = 0; i <= num; i++) + cancelItemFromProductionQueue(harvesterType); + }else{ + if(theBaseInfo.currentCredit >0){ + + theBaseInfo.currentCredit--; + creditSpentOnBuilding++; + harvesterProgress = 240 * creditSpentOnBuilding/800; + } + } + } + if(harvesterProgress == 240){ + if(!canBuildHarvester){ + int num = numOfHarvesterOnQueue; + for(int i = 0; i <= num; i++) + cancelItemFromProductionQueue(harvesterType); + }else{ + if(!isDeliveringUnit){ + harvester o = new harvester(new vector(centre.x -0.07f,-0.3f, centre.z - 0.03f), 180, teamNo); + + if(teamNo == 0 && communicationCenter.harvesterSpeedResearched_player){ + o.speed = 0.014f; + o.bodyTurnRate = 8; + }else if(teamNo != 0 && communicationCenter.harvesterSpeedResearched_enemy){ + o.speed = 0.014f; + o.bodyTurnRate = 8; + } + + deliveredUnit = o; + o.disableUnitLevelAI = true; + + mainThread.theAssetManager.addHarvester(o); + harvesterProgress = 255; + removelItemFromProductionQueue(harvesterType); + isDeliveringUnit = true; + } + } + } + + //MCV event + if(MCVProgress < 240){ + grayAllOtherIcons(MCVType, MCVProgress); + + if(!canBuildMCV){ + int num = numOfMCVOnQueue; + for(int i = 0; i <= num; i++) + cancelItemFromProductionQueue(MCVType); + }else{ + if(theBaseInfo.currentCredit >0){ + theBaseInfo.currentCredit--; + creditSpentOnBuilding++; + MCVProgress = 240 * creditSpentOnBuilding/1700; + } + } + } + if(MCVProgress == 240){ + if(!canBuildMCV){ + int num = numOfMCVOnQueue; + for(int i = 0; i <= num; i++) + cancelItemFromProductionQueue(MCVType); + }else{ + if(!isDeliveringUnit){ + constructionVehicle o = new constructionVehicle(new vector(centre.x -0.07f,-0.3f, centre.z - 0.03f), 180, teamNo); + deliveredUnit = o; + o.disableUnitLevelAI = true; + + mainThread.theAssetManager.addConstructionVehicle(o); + MCVProgress = 255; + removelItemFromProductionQueue(MCVType); + isDeliveringUnit = true; + } + } + } + + + //drone event + if(droneProgress < 240){ + grayAllOtherIcons(droneType, droneProgress); + if(theBaseInfo.currentCredit >0){ + + theBaseInfo.currentCredit--; + creditSpentOnBuilding++; + droneProgress = 240 * creditSpentOnBuilding/250; + } + } + if(droneProgress == 240){ + if(!isDeliveringUnit){ + drone o = new drone(new vector(centre.x -0.07f,-0.27f, centre.z - 0.03f), 180, this); + numOfDrones++; + deliveredUnit = o; + o.disableUnitLevelAI = true; + + mainThread.theAssetManager.addDrone(o); + droneProgress = 255; + removelItemFromProductionQueue(droneType); + isDeliveringUnit = true; + } + } + + //stealth tank event + if(stealthTankProgress < 240){ + grayAllOtherIcons(stealthTankType, stealthTankProgress); + if(!canBuildStealthTank){ + int num = numOfStealthTankOnQueue; + for(int i = 0; i <= num; i++) + cancelItemFromProductionQueue(stealthTankType); + }else{ + + if(theBaseInfo.currentCredit >0){ + + theBaseInfo.currentCredit--; + creditSpentOnBuilding++; + stealthTankProgress = 240 * creditSpentOnBuilding/600; + } + } + } + if(stealthTankProgress == 240){ + if(!canBuildStealthTank){ + int num = numOfStealthTankOnQueue; + for(int i = 0; i <= num; i++) + cancelItemFromProductionQueue(stealthTankType); + }else{ + if(!isDeliveringUnit){ + stealthTank o = new stealthTank(new vector(centre.x -0.07f,-0.3f, centre.z - 0.03f), 180, teamNo); + if(teamNo == 0 && techCenter.stealthTankResearched_player){ + o.hasMultiShotUpgrade = true; + }else if(teamNo != 0 && techCenter.stealthTankResearched_enemy){ + o.hasMultiShotUpgrade = true; + } + + deliveredUnit = o; + o.disableUnitLevelAI = true; + + mainThread.theAssetManager.addStealthTank(o); + stealthTankProgress = 255; + removelItemFromProductionQueue(stealthTankType); + isDeliveringUnit = true; + } + } + } + + //heavy tank event + if(heavyTankProgress < 240){ + grayAllOtherIcons(heavyTankType, heavyTankProgress); + if(!canBuildHeavyTank){ + int num = numOfHeavyTankOnQueue; + for(int i = 0; i <= num; i++) + cancelItemFromProductionQueue(heavyTankType); + }else{ + + if(theBaseInfo.currentCredit >0){ + + theBaseInfo.currentCredit--; + creditSpentOnBuilding++; + heavyTankProgress = 240 * creditSpentOnBuilding/1100; + } + } + } + if(heavyTankProgress == 240){ + if(!canBuildHeavyTank){ + int num = numOfHeavyTankOnQueue; + for(int i = 0; i <= num; i++) + cancelItemFromProductionQueue(heavyTankType); + }else{ + if(!isDeliveringUnit){ + heavyTank o = new heavyTank(new vector(centre.x -0.07f,-0.3f, centre.z - 0.03f), 180, teamNo); + if(teamNo == 0 && techCenter.heavyTankResearched_player){ + o.canSelfRepair = true; + }else if(teamNo != 0 && techCenter.heavyTankResearched_enemy){ + o.canSelfRepair = true; + } + deliveredUnit = o; + o.disableUnitLevelAI = true; + + mainThread.theAssetManager.addHeavyTank(o); + heavyTankProgress = 255; + removelItemFromProductionQueue(heavyTankType); + isDeliveringUnit = true; + } + } + } + + } + }else{ + lightTankProgress = 255; + rocketTankProgress = 255; + harvesterProgress = 255; + droneProgress = 255; + MCVProgress = 255; + stealthTankProgress = 255; + heavyTankProgress = 255; + } + + + //process delivering Unit event + if(isDeliveringUnit){ + + if(deliveredUnit != null && deliveredUnit.currentHP <=0){ + deliveredUnit = null; + closingDoor = true; + openingDoor = false; + } + + if(deliveredUnit!= null){ + if(doorClosed){ + closingDoor = false; + doorClosed = false; + openingDoor = true; + } + + if(doorOpened){ + + xPos = (int)((deliveredUnit.centre.x)*64) - 8; + + if(deliveredUnit.centre.z - (centre.z - 0.375f) <= 0.01f){ + if(deliveredUnit.type == droneType){ + deliveredUnit.disableUnitLevelAI = false; + }else{ + deliveredUnit.movement.set(0,0,deliveredUnit.centre.z - (centre.z - 0.375f)); + deliveredUnit.disableUnitLevelAI = false; + deliveredUnit.leftFactory = true; + + if(deliveredUnit.type == harvesterType){ + + if(targetGoldMine != null) + deliveredUnit.harvest(targetGoldMine); + else + moveDeliveredUnitToRallyPoint(); + harvester o = (harvester)deliveredUnit; + o.heuristicRecalculationCountDown = 1; + + + }else{ + moveDeliveredUnitToRallyPoint(); + } + } + + deliveredUnit = null; + closingDoor = true; + openingDoor = false; + doorOpened = false; + + }else{ + + yPos = (int)((deliveredUnit.centre.z -0.01f)*64) + 8; + boolean canMove = true; + + if(deliveredUnit.type != droneType){ + + + xPos_old = deliveredUnit.boundary2D.x1; + yPos_old = deliveredUnit.boundary2D.y1; + + deliveredUnit.boundary2D.setOrigin(xPos, yPos); + + + for(int i = 0; i < 4; i++){ + solidObject o = mainThread.gridMap.tiles[tileIndex[5]+128][i]; + if(o != null && o != deliveredUnit){ + if(o.boundary2D.intersect(deliveredUnit.boundary2D)){ + canMove = false; + break; + } + } + } + + for(int i = 0; i < 4; i++){ + solidObject o = mainThread.gridMap.tiles[tileIndex[5]+127][i]; + if(o != null && o != deliveredUnit){ + if(o.boundary2D.intersect(deliveredUnit.boundary2D)){ + canMove = false; + break; + } + } + } + + } + if(!canMove){ + deliveredUnit.movement.reset(); + deliveredUnit.boundary2D.setOrigin(xPos_old, yPos_old); + }else{ + + if(deliveredUnit.type != droneType){ + deliveredUnit.boundary2D.setOrigin(xPos_old, yPos_old); + deliveredUnit.movement.set(0,0,-0.01f); + }else{ + deliveredUnit.centre.z-=0.01f; + } + } + } + + + + + + } + } + + float dHeight = 0.005f; + if(openingDoor){ + for(int i = 0; i < doorUpper.length; i++){ + if(i == 0 && !doorHeightMarked){ + doorHeightMark = doorUpper[i].origin.y; + doorHeightMarked = true; + } + + doorUpper[i].origin.y+=dHeight; + doorUpper[i].bottomEnd.y+=dHeight; + doorUpper[i].rightEnd.y+=dHeight; + + for(int j = 0; j < doorUpper[i].vertex3D.length; j++){ + doorUpper[i].vertex3D[j].y+=dHeight; + } + } + + for(int i = 0; i < doorLower.length; i++){ + doorLower[i].origin.y-=dHeight; + doorLower[i].bottomEnd.y-=dHeight; + doorLower[i].rightEnd.y-=dHeight; + + for(int j = 0; j < doorLower[i].vertex3D.length; j++){ + doorLower[i].vertex3D[j].y-=dHeight; + } + } + if(doorUpper[0].origin.y > -0.256){ + openingDoor = false; + doorOpened = true; + } + } + + if(closingDoor){ + for(int i = 0; i < doorUpper.length; i++){ + doorUpper[i].origin.y-=dHeight; + doorUpper[i].bottomEnd.y-=dHeight; + doorUpper[i].rightEnd.y-=dHeight; + + for(int j = 0; j < doorUpper[i].vertex3D.length; j++){ + doorUpper[i].vertex3D[j].y-=dHeight; + } + } + for(int i = 0; i < doorLower.length; i++){ + doorLower[i].origin.y+=dHeight; + doorLower[i].bottomEnd.y+=dHeight; + doorLower[i].rightEnd.y+=dHeight; + + for(int j = 0; j < doorLower[i].vertex3D.length; j++){ + doorLower[i].vertex3D[j].y+=dHeight; + } + } + if(doorUpper[0].origin.y <= doorHeightMark){ + closingDoor = false; + isDeliveringUnit = false; + doorClosed = true; + } + } + + + } + + //mark itself on obstacle map + mainThread.gridMap.currentObstacleMap[tileIndex[0]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[1]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[2]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[3]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[4]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[5]] = false; + + + //update center in camera coordinate + tempCentre.set(centre); + tempCentre.subtract(camera.position); + tempCentre.rotate_XZ(camera.XZ_angle); + tempCentre.rotate_YZ(camera.YZ_angle); + tempCentre.updateLocation(); + + theAssetManager = mainThread.theAssetManager; + + //test if the object is visible in camera point of view + if(visibleBoundary.contains(tempCentre.screenX, tempCentre.screenY) && isRevealed){ + visible = true; + + if(screenBoundary.contains(tempCentre.screenX, tempCentre.screenY)) + withinViewScreen = true; + else + withinViewScreen = false; + + tempshadowvertex0.set(shadowvertex0); + tempshadowvertex0.subtract(camera.position); + tempshadowvertex0.rotate_XZ(camera.XZ_angle); + tempshadowvertex0.rotate_YZ(camera.YZ_angle); + tempshadowvertex0.updateLocation(); + + tempshadowvertex1.set(shadowvertex1); + tempshadowvertex1.subtract(camera.position); + tempshadowvertex1.rotate_XZ(camera.XZ_angle); + tempshadowvertex1.rotate_YZ(camera.YZ_angle); + tempshadowvertex1.updateLocation(); + + tempshadowvertex2.set(shadowvertex2); + tempshadowvertex2.subtract(camera.position); + tempshadowvertex2.rotate_XZ(camera.XZ_angle); + tempshadowvertex2.rotate_YZ(camera.YZ_angle); + tempshadowvertex2.updateLocation(); + + tempshadowvertex3.set(shadowvertex3); + tempshadowvertex3.subtract(camera.position); + tempshadowvertex3.rotate_XZ(camera.XZ_angle); + tempshadowvertex3.rotate_YZ(camera.YZ_angle); + tempshadowvertex3.updateLocation(); + + + + //if the object is visible then draw it on the shadow buffer from light point of view + if(shadowBoundary1.contains(tempshadowvertex0.screenX, tempshadowvertex0.screenY) || + shadowBoundary1.contains(tempshadowvertex1.screenX, tempshadowvertex1.screenY) || + shadowBoundary1.contains(tempshadowvertex2.screenX, tempshadowvertex2.screenY) || + shadowBoundary1.contains(tempshadowvertex3.screenX, tempshadowvertex3.screenY) + ){ + for(int i = 0; i < numOfPolygons; i++){ + polygons[i].update_lightspace(); + + + } + + } + + //add this object to visible unit list + theAssetManager.visibleUnit[theAssetManager.visibleUnitCount] = this; + theAssetManager.visibleUnitCount++; + + + }else{ + visible = false; + } + + + //create vision for enemy commander + if(teamNo == 1){ + int xPos = boundary2D.x1/16 - 8 + 10 + 1; + int yPos = 127 - boundary2D.y1/16 - 8 + 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; + } + } + } + + visionBoundary.x = (int)(tempCentre.screenX - 800); + visionBoundary.y = (int)(tempCentre.screenY - 1000); + visionInsideScreen = camera.screen.intersects(visionBoundary); + + + if(visionInsideScreen){ + if(teamNo == 0){ + 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++; + } + } + + if(theAssetManager.minimapBitmap[tileIndex[0]] || + theAssetManager.minimapBitmap[tileIndex[1]] || + theAssetManager.minimapBitmap[tileIndex[2]] || + theAssetManager.minimapBitmap[tileIndex[3]] || + theAssetManager.minimapBitmap[tileIndex[4]] || + theAssetManager.minimapBitmap[tileIndex[5]]) + isRevealed = true; + + visible_minimap = isRevealed; + + if(visible_minimap){ + tempInt = theAssetManager.unitsForMiniMap[theAssetManager.unitsForMiniMapCount]; + tempInt[0] = teamNo; + 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] = 10000; + theAssetManager.unitsForMiniMapCount++; + + } + + //update power tower animation + if(!visible) + return; + + polygons[distortionA].origin.x-=0.001f; + polygons[distortionA].rightEnd.x-=0.001f; + polygons[distortionA].bottomEnd.x -= 0.001f; + polygons[distortionA].origin.z-=0.001f; + polygons[distortionA].rightEnd.z-=0.001f; + polygons[distortionA].bottomEnd.z -= 0.001f; + + for(int i = 0; i < fanA.length; i++){ + fanA[i].origin.subtract(powerTowerCenterA); + fanA[i].origin.rotate_XZ(4); + fanA[i].origin.add(powerTowerCenterA); + + + fanA[i].bottomEnd.subtract(powerTowerCenterA); + fanA[i].bottomEnd.rotate_XZ(4); + fanA[i].bottomEnd.add(powerTowerCenterA); + + + fanA[i].rightEnd.subtract(powerTowerCenterA); + fanA[i].rightEnd.rotate_XZ(4); + fanA[i].rightEnd.add(powerTowerCenterA); + + for(int j = 0; j < fanA[i].vertex3D.length; j++){ + fanA[i].vertex3D[j].subtract(powerTowerCenterA); + fanA[i].vertex3D[j].rotate_XZ(4); + fanA[i].vertex3D[j].add(powerTowerCenterA); + } + fanA[i].normal.rotate_XZ(4); + fanA[i].findDiffuse(); + } + + polygons[distortionB].origin.x-=0.001f; + polygons[distortionB].rightEnd.x-=0.001f; + polygons[distortionB].bottomEnd.x -= 0.001f; + polygons[distortionB].origin.z-=0.001f; + polygons[distortionB].rightEnd.z-=0.001f; + polygons[distortionB].bottomEnd.z -= 0.001f; + + for(int i = 0; i < fanB.length; i++){ + fanB[i].origin.subtract(powerTowerCenterB); + fanB[i].origin.rotate_XZ(4); + fanB[i].origin.add(powerTowerCenterB); + + + fanB[i].bottomEnd.subtract(powerTowerCenterB); + fanB[i].bottomEnd.rotate_XZ(4); + fanB[i].bottomEnd.add(powerTowerCenterB); + + + fanB[i].rightEnd.subtract(powerTowerCenterB); + fanB[i].rightEnd.rotate_XZ(4); + fanB[i].rightEnd.add(powerTowerCenterB); + + for(int j = 0; j < fanB[i].vertex3D.length; j++){ + fanB[i].vertex3D[j].subtract(powerTowerCenterB); + fanB[i].vertex3D[j].rotate_XZ(4); + fanB[i].vertex3D[j].add(powerTowerCenterB); + } + fanB[i].normal.rotate_XZ(4); + fanB[i].findDiffuse(); + } + } + + public void buildLightTank(){ + if(numOfLightTankOnQueue >= 100) + return; + if(canBuildLightTank){ + if(currentStatus != isBuilding){ + lightTankProgress = 0; + + currentStatus = isBuilding; + creditSpentOnBuilding = 0; + } + numOfLightTankOnQueue++; + addToProductionQueue(lightTankType); + } + } + + public void buildRocketTank(){ + if(numOfRocketTankOnQueue >= 100) + return; + if(canBuildRocketTank){ + if(currentStatus != isBuilding){ + rocketTankProgress = 0; + + currentStatus = isBuilding; + creditSpentOnBuilding = 0; + } + numOfRocketTankOnQueue++; + addToProductionQueue(rocketTankType); + } + } + + public void buildHarvester(){ + if(numOfHarvesterOnQueue >= 100) + return; + if(canBuildHarvester){ + if(currentStatus != isBuilding){ + harvesterProgress = 0; + + currentStatus = isBuilding; + creditSpentOnBuilding = 0; + } + numOfHarvesterOnQueue++; + addToProductionQueue(harvesterType); + } + } + + public void buildDrone(){ + if(numOfDroneOnQueue + numOfDrones == 3) + return; + if(canBuildDrone){ + if(currentStatus != isBuilding){ + droneProgress = 0; + + currentStatus = isBuilding; + creditSpentOnBuilding = 0; + } + numOfDroneOnQueue++; + addToProductionQueue(droneType); + } + } + + public void buildMCV(){ + if(numOfMCVOnQueue >= 100) + return; + if(canBuildMCV){ + if(currentStatus != isBuilding){ + MCVProgress = 0; + + currentStatus = isBuilding; + creditSpentOnBuilding = 0; + } + numOfMCVOnQueue++; + addToProductionQueue(MCVType); + } + } + + public void buildStealthTank(){ + if(numOfStealthTankOnQueue >= 100) + return; + if(canBuildStealthTank){ + if(currentStatus != isBuilding){ + stealthTankProgress = 0; + + currentStatus = isBuilding; + creditSpentOnBuilding = 0; + } + numOfStealthTankOnQueue++; + addToProductionQueue(stealthTankType); + } + } + + public void buildHeavyTank(){ + if(numOfHeavyTankOnQueue >= 100) + return; + if(canBuildHeavyTank){ + if(currentStatus != isBuilding){ + heavyTankProgress = 0; + + currentStatus = isBuilding; + creditSpentOnBuilding = 0; + } + numOfHeavyTankOnQueue++; + addToProductionQueue(heavyTankType); + } + } + + + public void grayAllOtherIcons(int type, int progress){ + lightTankProgress = 254; + rocketTankProgress = 254; + harvesterProgress = 254; + droneProgress = 254; + MCVProgress = 254; + stealthTankProgress = 254; + heavyTankProgress = 254; + + if(type == lightTankType){ + lightTankProgress = progress; + } + if(type == rocketTankType){ + rocketTankProgress = progress; + } + if(type == harvesterType){ + harvesterProgress = progress; + } + if(type == droneType){ + droneProgress = progress; + } + if(type == MCVType){ + MCVProgress = progress; + } + if(type == stealthTankType){ + stealthTankProgress = progress; + } + if(type == heavyTankType){ + heavyTankProgress = progress; + } + + + } + + public void addToProductionQueue(int type){ + for(int i = 0; i < productionQueue.length; i++){ + if(productionQueue[i] == -1){ + productionQueue[i] = (byte)type; + return; + } + } + } + + public void cancelItemFromProductionQueue(int type){ + for(int i = productionQueue.length - 1; i >= 0; i--){ + if(productionQueue[i] == type){ + if(type == lightTankType){ + numOfLightTankOnQueue--; + if(i == 0){ + theBaseInfo.currentCredit+=creditSpentOnBuilding; + creditSpentOnBuilding = 0; + lightTankProgress = 255; + currentStatus = isIdle; + } + } + if(type == rocketTankType){ + numOfRocketTankOnQueue--; + if(i == 0){ + theBaseInfo.currentCredit+=creditSpentOnBuilding; + creditSpentOnBuilding = 0; + rocketTankProgress = 255; + currentStatus = isIdle; + } + } + if(type == harvesterType){ + numOfHarvesterOnQueue--; + if(i == 0){ + theBaseInfo.currentCredit+=creditSpentOnBuilding; + creditSpentOnBuilding = 0; + harvesterProgress = 255; + currentStatus = isIdle; + } + } + if(type == droneType){ + numOfDroneOnQueue--; + if(i == 0){ + theBaseInfo.currentCredit+=creditSpentOnBuilding; + creditSpentOnBuilding = 0; + droneProgress = 255; + currentStatus = isIdle; + } + } + if(type == MCVType){ + numOfMCVOnQueue--; + if(i == 0){ + theBaseInfo.currentCredit+=creditSpentOnBuilding; + creditSpentOnBuilding = 0; + MCVProgress = 255; + currentStatus = isIdle; + } + } + if(type == stealthTankType){ + numOfStealthTankOnQueue--; + if(i == 0){ + theBaseInfo.currentCredit+=creditSpentOnBuilding; + creditSpentOnBuilding = 0; + stealthTankProgress = 255; + currentStatus = isIdle; + } + } + if(type == heavyTankType){ + numOfHeavyTankOnQueue--; + if(i == 0){ + theBaseInfo.currentCredit+=creditSpentOnBuilding; + creditSpentOnBuilding = 0; + heavyTankProgress = 255; + currentStatus = isIdle; + } + } + + for(int j = i; j < productionQueue.length - 1; j++){ + productionQueue[j] = productionQueue[j+1]; + if(productionQueue[j+1] == -1) + break; + } + productionQueue[productionQueue.length - 1] = -1; + + if(i == 0){ + if(productionQueue[i] == lightTankType){ + lightTankProgress = 0; + currentStatus = isBuilding; + creditSpentOnBuilding = 0; + }else if(productionQueue[i] == rocketTankType){ + rocketTankProgress = 0; + currentStatus = isBuilding; + creditSpentOnBuilding = 0; + }else if(productionQueue[i] == harvesterType){ + harvesterProgress = 0; + currentStatus = isBuilding; + creditSpentOnBuilding = 0; + }else if(productionQueue[i] == droneType){ + droneProgress = 0; + currentStatus = isBuilding; + creditSpentOnBuilding = 0; + }else if(productionQueue[i] == MCVType){ + MCVProgress = 0; + currentStatus = isBuilding; + creditSpentOnBuilding = 0; + }else if(productionQueue[i] == stealthTankType){ + stealthTankProgress = 0; + currentStatus = isBuilding; + creditSpentOnBuilding = 0; + }else if(productionQueue[i] == heavyTankType){ + heavyTankProgress = 0; + currentStatus = isBuilding; + creditSpentOnBuilding = 0; + } + } + + return; + } + } + } + + public void removelItemFromProductionQueue(int type){ + + if(type == lightTankType){ + numOfLightTankOnQueue--; + creditSpentOnBuilding = 0; + lightTankProgress = 255; + currentStatus = isIdle; + } + if(type == rocketTankType){ + numOfRocketTankOnQueue--; + creditSpentOnBuilding = 0; + rocketTankProgress = 255; + currentStatus = isIdle; + } + if(type == harvesterType){ + numOfHarvesterOnQueue--; + creditSpentOnBuilding = 0; + harvesterProgress = 255; + currentStatus = isIdle; + } + if(type == droneType){ + numOfDroneOnQueue--; + creditSpentOnBuilding = 0; + droneProgress = 255; + currentStatus = isIdle; + } + if(type == MCVType){ + numOfMCVOnQueue--; + creditSpentOnBuilding = 0; + MCVProgress = 255; + currentStatus = isIdle; + } + if(type == stealthTankType){ + numOfStealthTankOnQueue--; + creditSpentOnBuilding = 0; + stealthTankProgress = 255; + currentStatus = isIdle; + } + if(type == heavyTankType){ + numOfHeavyTankOnQueue--; + creditSpentOnBuilding = 0; + heavyTankProgress = 255; + currentStatus = isIdle; + } + + + for(int j = 0; j < productionQueue.length - 1; j++){ + productionQueue[j] = productionQueue[j+1]; + if(productionQueue[j+1] == -1) + break; + } + productionQueue[productionQueue.length - 1] = -1; + + if(productionQueue[0] != -1){ + if(productionQueue[0] == lightTankType){ + lightTankProgress = 0; + currentStatus = isBuilding; + creditSpentOnBuilding = 0; + } + if(productionQueue[0] == rocketTankType){ + rocketTankProgress = 0; + currentStatus = isBuilding; + creditSpentOnBuilding = 0; + } + if(productionQueue[0] == harvesterType){ + harvesterProgress = 0; + currentStatus = isBuilding; + creditSpentOnBuilding = 0; + } + if(productionQueue[0] == droneType){ + droneProgress = 0; + currentStatus = isBuilding; + creditSpentOnBuilding = 0; + } + if(productionQueue[0] == MCVType){ + MCVProgress = 0; + currentStatus = isBuilding; + creditSpentOnBuilding = 0; + } + if(productionQueue[0] == stealthTankType){ + stealthTankProgress = 0; + currentStatus = isBuilding; + creditSpentOnBuilding = 0; + } + if(productionQueue[0] == heavyTankType){ + heavyTankProgress = 0; + currentStatus = isBuilding; + creditSpentOnBuilding = 0; + } + + } + } + + //cancel all the building process, refund money spent on current process + public void cancelBuilding(){ + theBaseInfo.currentCredit+=creditSpentOnBuilding; + creditSpentOnBuilding = 0; + currentStatus = isIdle; + } + + //draw the model + public void draw(){ + if(!visible) + return; + for(int i = 0; i < numOfPolygons; i++){ + + polygons[i].update(); + } + + if(centre.y < -0.8f){ + polygons[distortionA].visible = false; + polygons[distortionB].visible = false; + } + + for(int i = 0; i < numOfPolygons; i++){ + polygons[i].draw(); + } + } + + public void drawRallyPointLine(){ + if(isSelected && teamNo == 0 && mainThread.pc.theSideBarManager.onlyFactorySelected){ + geometry.drawLine(centre, rallyCenter, 0xff00, (byte)16); + } + + if(isSelected && teamNo == 0 && mainThread.pc.theSideBarManager.onlyFactorySelected && targetGoldMine != null){ + geometry.drawLine(centre, targetGoldMine.centre, 0xffff00, (byte)15); + } + } + + public vector getMovement(){ + return movenment; + } + + + //factory can't not move, instead it will set its rally point to the destination position + public void moveTo(float destinationX, float destinationY){ + if(teamNo != 0 || mainThread.pc.theSideBarManager.onlyFactorySelected){ + + rallyCenter.set(destinationX, -0.3f, destinationY); + rallyPointChanged = true; + } + } + + public void moveDeliveredUnitToRallyPoint(){ + + + if(rallyPointChanged){ + if(deliveredUnit.type != 0 && deliveredUnit.type != 1 && deliveredUnit.type != 6 && deliveredUnit.type !=7 ){ + deliveredUnit.moveTo(rallyCenter.x, rallyCenter.z); + deliveredUnit.currentCommand = solidObject.move; + deliveredUnit.secondaryCommand = solidObject.StandBy; + return; + }else{ + deliveredUnit.attackMoveTo(rallyCenter.x, rallyCenter.z); + deliveredUnit.currentCommand = solidObject.attackMove; + deliveredUnit.secondaryCommand = solidObject.attackMove; + return; + } + } + + //default rally points + for(int i = 0; i < rallyPoints.length; i++){ + float rallyX = rallyCenter.x + rallyPoints[i].x; + float rallyY = rallyCenter.z + rallyPoints[i].z; + + + + int tileIndex = ((int)(rallyX*64) - 8) /16 + (127 - (((int)(rallyY*64) + 8) - 1)/16)*128; + + + + + + boolean rallyPointClear = true; + for(int j = 0; j < 4; j ++){ + if(mainThread.gridMap.tiles[tileIndex][j]!= null && mainThread.gridMap.tiles[tileIndex][j] != deliveredUnit){ + probeBlock.width = 8; + probeBlock.height = 8; + probeBlock.setOrigin((int)(rallyX*64)-4, (int)(rallyY*64)+4); + + if(mainThread.gridMap.tiles[tileIndex][j].boundary2D.intersect(probeBlock)){ + + rallyPointClear = false; + break; + } + } + } + + if(rallyPointClear){ + deliveredUnit.moveTo(rallyX, rallyY); + deliveredUnit.currentCommand = solidObject.move; + deliveredUnit.secondaryCommand = solidObject.StandBy; + return; + } + } + + } + + public boolean isIdle(){ + return lightTankProgress == 255 && rocketTankProgress == 255 && harvesterProgress == 255 && droneProgress == 255 && MCVProgress == 255 && stealthTankProgress == 255 && heavyTankProgress == 255; + } + + public void harvest(solidObject o){ + if(targetGoldMine != o) + targetGoldMine = (goldMine)o; + else if(targetGoldMine == o && mainThread.pc.theSideBarManager.factoryRallyOnSameGoldMine) + targetGoldMine = null; + } +} diff --git a/entity/goldMine.java b/entity/goldMine.java new file mode 100644 index 0000000..133c897 --- /dev/null +++ b/entity/goldMine.java @@ -0,0 +1,401 @@ +package entity; + +import java.awt.Rectangle; + +import core.*; + +public class goldMine extends solidObject{ + //the polygons of the model + private polygon3D[] polygons; + + //the amount of gold available + public int goldDeposite; + public int maxDeposite; + + public int textureIndex; + + public static int maxHP = 9999; + + public static vector tempVector0 = new vector(0,0,0); + public static vector tempVector1 = new vector(0,0,0); + public static vector tempVector2 = new vector(0,0,0); + public static vector tempVector3 = new vector(0,0,0); + + public static vector origin = new vector(0,0,0); + public static vector top = new vector(0,0,0); + public static vector bot = new vector(0,0,0); + public static vector deltaX = new vector(0,0,0); + public static vector deltaZ = new vector(0,0,0); + + + //gold mine occupies 4 tiles + public int [] tileIndex = new int[6]; + + + public vector shadowvertex0, tempshadowvertex0,shadowvertex1, tempshadowvertex1,shadowvertex2, tempshadowvertex2,shadowvertex3, tempshadowvertex3; + + //a screen space boundary which is used to test if the object is visible from camera point of view + public final static Rectangle visibleBoundary = new Rectangle(-85,-85,920, 762); + + //a screen space boundary which is used to test if the entire object is within the screen + public final static Rectangle screenBoundary = new Rectangle(60,60,648, 402); + + //screen space boundary which is used to test if the shadow of the object is within the screen + public final static Rectangle shadowBoundary1 = new Rectangle(40,40,728, 472); + + //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,1600, 2000); + + //gold mine never moves + public final static vector movenment = new vector(0,0,0); + + public int polygonCount; + + public goldMine(float x, float y, float z, int amount){ + + goldDeposite =amount; + maxDeposite = amount; + + //uncontrollable unit, but act as a big sized static collidable agent + ID = -1; + type = 103; + teamNo = -1; + currentHP = 9999; + progressStatus = 100; + textureIndex = 39; + + currentCommand = StandBy; + + start = new vector(x,y,z); + + if(start.y < -0.515f) + isSelectable = false; + + + //create 2D boundary + boundary2D = new Rect((int)(x*64) - 16, (int)(z*64) + 16, 32, 32); + boundary2D.owner = this; + int centerX = (int)(x*64); + int centerY = (int)(z*64); + + if(!(start.y < -0.515f)){ + + tileIndex[0] = (centerX - 8)/16 + (127 - (centerY + 8)/16)*128; + tileIndex[1] = (centerX + 8)/16 + (127 - (centerY + 8)/16)*128; + tileIndex[2] = (centerX + 8)/16 + (127 - (centerY - 8)/16)*128; + tileIndex[3] = (centerX - 8)/16 + (127 - (centerY - 8)/16)*128; + + + mainThread.gridMap.tiles[tileIndex[0]][0] = this; + mainThread.gridMap.tiles[tileIndex[1]][0] = this; + mainThread.gridMap.tiles[tileIndex[2]][0] = this; + mainThread.gridMap.tiles[tileIndex[3]][0] = this; + + mainThread.gridMap.tiles[tileIndex[0]][1] = this; + mainThread.gridMap.tiles[tileIndex[1]][1] = this; + mainThread.gridMap.tiles[tileIndex[2]][1] = this; + mainThread.gridMap.tiles[tileIndex[3]][1] = this; + + mainThread.gridMap.tiles[tileIndex[0]][2] = this; + mainThread.gridMap.tiles[tileIndex[1]][2] = this; + mainThread.gridMap.tiles[tileIndex[2]][2] = this; + mainThread.gridMap.tiles[tileIndex[3]][2] = this; + + mainThread.gridMap.tiles[tileIndex[0]][3] = this; + mainThread.gridMap.tiles[tileIndex[1]][3] = this; + mainThread.gridMap.tiles[tileIndex[2]][3] = this; + mainThread.gridMap.tiles[tileIndex[3]][3] = this; + + mainThread.gridMap.tiles[tileIndex[0]][4] = this; + mainThread.gridMap.tiles[tileIndex[1]][4] = this; + mainThread.gridMap.tiles[tileIndex[2]][4] = this; + mainThread.gridMap.tiles[tileIndex[3]][4] = this; + } + + + + //init model + iDirection = new vector(1f,0,0); + jDirection = new vector(0,1f,0); + kDirection = new vector(0,0,1f); + centre = start.myClone(); + tempCentre = start.myClone(); + + shadowvertex0 =start.myClone(); + shadowvertex0.add(-0.45f,-0.2f, -0.45f); + tempshadowvertex0 = new vector(0,0,0); + + shadowvertex1 =start.myClone(); + shadowvertex1.add(-0.45f,-0.2f, 0.2f); + tempshadowvertex1 = new vector(0,0,0); + + shadowvertex2 =start.myClone(); + shadowvertex2.add(0.2f,-0.2f, -0.45f); + tempshadowvertex2 = new vector(0,0,0); + + shadowvertex3 =start.myClone(); + shadowvertex3.add(0.2f,-0.2f, 0.2f); + tempshadowvertex3 = new vector(0,0,0); + + if(!(start.y < -0.515f)){ + int color = 12 << 24 | 245 << 16 | 198 << 8 | 20; + + int position = tileIndex[0]; + postProcessingThread.theMiniMap.background[position -128] = color; + + postProcessingThread.theMiniMap.background[position - 129] = color; + postProcessingThread.theMiniMap.background[position - 127] = color; + postProcessingThread.theMiniMap.background[position-1] = color; + postProcessingThread.theMiniMap.background[position] = color; + postProcessingThread.theMiniMap.background[position+1] = color; + postProcessingThread.theMiniMap.background[position + 127] = color; + postProcessingThread.theMiniMap.background[position + 128] = color; + postProcessingThread.theMiniMap.background[position + 129] = color; + + } + + + makePolygons(); + } + + private void makePolygons(){ + polygons = new polygon3D[32*32*2]; + + //load height map + float[] heightmap = new float[(32+1)*(32+1)]; + + int[] hm = mainThread.textures[38].heightmap; + + + + + + for(int i = 0; i < 33; i++){ + for(int j =0; j< 33; j++){ + heightmap[j + i * 33] = ((float)hm[j*8 + i*8*257])*0.0014f + centre.y; + + } + } + + + + float dx = 0.56f / 32; + float dz = -0.56f / 32; + float x_start = start.x - 0.32f; + float z_start = start.z + 0.30f; + + int index = 0; + + for(int i = 0; i < 32; i++){ + for(int j = 0; j < 32; j++){ + + + + tempVector0.set(x_start + dx*j, heightmap[j + i*33], z_start + dz*i); + tempVector1.set(x_start + dx*(j+1), heightmap[j + 1 + i*33], z_start + dz*i); + tempVector2.set(x_start + dx*(j+1), heightmap[j + 1 + (i +1)*33], z_start + dz*(i+1)); + tempVector3.set(x_start + dx*j, heightmap[j + (i +1)*33], z_start + dz*(i+1)); + + if(start.y < -0.515f){ + + if(tempVector0.y < -0.755){ + continue; + } + + } + + + v = new vector[]{tempVector0.myClone(), tempVector1.myClone(), tempVector3.myClone()}; + deltaX.set(tempVector0); + deltaX.subtract(tempVector1); + + deltaZ.set(tempVector0); + deltaZ.subtract(tempVector3); + + origin.set(tempVector0); + origin.add(deltaX, j); + origin.add(deltaZ, i); + + top.set(origin); + top.add(deltaX, -32); + + bot.set(origin); + bot.add(deltaZ, -32); + + polygons[index] = new polygon3D(v, origin.myClone(), top.myClone(), bot.myClone(), mainThread.textures[textureIndex], 1,1,1); + deltaX.set(tempVector3); + deltaX.subtract(tempVector2); + + deltaZ.set(tempVector1); + deltaZ.subtract(tempVector2); + + origin.set(tempVector2); + origin.add(deltaX); + origin.add(deltaZ); + origin.add(deltaX, j); + origin.add(deltaZ, i); + + top.set(origin); + top.add(deltaX, -32); + + bot.set(origin); + bot.add(deltaZ, -32); + + v = new vector[]{tempVector1.myClone(), tempVector2.myClone(), tempVector3.myClone()}; + + + + polygons[index+1] = new polygon3D(v, origin.myClone(), top.myClone(), bot.myClone(), mainThread.textures[39], 1,1,1); + + + + index+=2; + } + } + polygonCount = index; + + for(int i = 0; i < polygonCount; i++){ + polygons[i].findDiffuse(); + polygons[i].parentObject = this; + + } + } + + //update the model + public void update(){ + + if(mainThread.theAssetManager.minimapBitmap[tileIndex[0]] || + mainThread.theAssetManager.minimapBitmap[tileIndex[1]] || + mainThread.theAssetManager.minimapBitmap[tileIndex[2]] || + mainThread.theAssetManager.minimapBitmap[tileIndex[3]] ) + isRevealed = true; + else + isRevealed = false; + + if(isRevealed){ + //check if gold mine has been depleted + progressStatus = 100*goldDeposite/maxDeposite; + + if(progressStatus == 0 && textureIndex != 41){ + textureIndex = 41; + for(int i = 0; i < polygons.length; i++) + polygons[i].myTexture = mainThread.textures[textureIndex]; + } + } + + + //mark itself on obstacle map + mainThread.gridMap.currentObstacleMap[tileIndex[0]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[1]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[2]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[3]] = false; + + + + + //update center in camera coordinate + tempCentre.set(centre); + tempCentre.subtract(camera.position); + tempCentre.rotate_XZ(camera.XZ_angle); + tempCentre.rotate_YZ(camera.YZ_angle); + tempCentre.updateLocation(); + + theAssetManager = mainThread.theAssetManager; + + //test if the palm tree is visible in camera point of view + if(visibleBoundary.contains(tempCentre.screenX, tempCentre.screenY)){ + visible = true; + + + + if(screenBoundary.contains(tempCentre.screenX, tempCentre.screenY)) + withinViewScreen = true; + else + withinViewScreen = false; + + tempshadowvertex0.set(shadowvertex0); + tempshadowvertex0.subtract(camera.position); + tempshadowvertex0.rotate_XZ(camera.XZ_angle); + tempshadowvertex0.rotate_YZ(camera.YZ_angle); + tempshadowvertex0.updateLocation(); + + + + tempshadowvertex1.set(shadowvertex1); + tempshadowvertex1.subtract(camera.position); + tempshadowvertex1.rotate_XZ(camera.XZ_angle); + tempshadowvertex1.rotate_YZ(camera.YZ_angle); + tempshadowvertex1.updateLocation(); + + tempshadowvertex2.set(shadowvertex2); + tempshadowvertex2.subtract(camera.position); + tempshadowvertex2.rotate_XZ(camera.XZ_angle); + tempshadowvertex2.rotate_YZ(camera.YZ_angle); + tempshadowvertex2.updateLocation(); + + tempshadowvertex3.set(shadowvertex3); + tempshadowvertex3.subtract(camera.position); + tempshadowvertex3.rotate_XZ(camera.XZ_angle); + tempshadowvertex3.rotate_YZ(camera.YZ_angle); + tempshadowvertex3.updateLocation(); + + + + //if the object is visible then draw it on the shadow buffer from light point of view + if(shadowBoundary1.contains(tempshadowvertex0.screenX, tempshadowvertex0.screenY) || + shadowBoundary1.contains(tempshadowvertex1.screenX, tempshadowvertex1.screenY) || + shadowBoundary1.contains(tempshadowvertex2.screenX, tempshadowvertex2.screenY) || + shadowBoundary1.contains(tempshadowvertex3.screenX, tempshadowvertex3.screenY) + ){ + for(int i = 0; i < polygonCount; i++){ + polygons[i].update_lightspace(); + + + } + + } + + //add this object to visible unit list + theAssetManager.visibleUnit[theAssetManager.visibleUnitCount] = this; + theAssetManager.visibleUnitCount++; + + }else{ + visible = false; + } + + + if(visible_minimap){ + tempInt = theAssetManager.unitsForMiniMap[theAssetManager.unitsForMiniMapCount]; + tempInt[0] = teamNo; + tempInt[1] = boundary2D.x1/16; + tempInt[2] = 127 - boundary2D.y1/16; + tempInt[3] = 2; + tempInt[4] = 10000; + theAssetManager.unitsForMiniMapCount++; + } + } + + + + + //draw the model + public void draw(){ + if(!visible) + return; + + for(int i = 0; i < polygonCount; i++){ + + polygons[i].update(); + } + + for(int i = 0; i < polygonCount; i++){ + polygons[i].draw(); + } + } + + public vector getMovement(){ + return movenment; + } + + +} diff --git a/entity/gunTurret.java b/entity/gunTurret.java new file mode 100644 index 0000000..bc3668b --- /dev/null +++ b/entity/gunTurret.java @@ -0,0 +1,789 @@ +package entity; + +import java.awt.Rectangle; + +import core.*; +import enemyAI.enemyCommander; + +//the power plant model +public class gunTurret extends solidObject{ + + public static int maxHP = 250; + + public int countDownToDeath = 16; + + public vector tempVector = new vector(0,0,0); + public vector tempVector0 = new vector(0,0,0); + public vector tempVector1 = new vector(0,0,0); + public vector tempVector2 = new vector(0,0,0); + public vector tempVector3 = new vector(0,0,0); + + public int [] tileIndex = new int[1]; + public int[] tempInt; + + public float[] tempFloat; + + public vector shadowvertex0, tempshadowvertex0,shadowvertex1, tempshadowvertex1,shadowvertex2, tempshadowvertex2,shadowvertex3, tempshadowvertex3; + + //a screen space boundary which is used to test if the object is visible from camera point of view + public final static Rectangle visibleBoundary = new Rectangle(-85,-85,920, 762); + + //a screen space boundary which is used to test if the entire object is within the screen + public final static Rectangle screenBoundary = new Rectangle(60,60,648, 402); + + //screen space boundary which is used to test if the shadow of the object is within the screen + public final static Rectangle shadowBoundary1 = new Rectangle(0,0,768, 512); + + //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,1600, 2000); + + //a bitmap representation of the vision of the power plant for enemy commander + public static boolean[] bitmapVisionForEnemy; + public static boolean[] bitmapVisionGainFromAttackingUnit; + + //gunTurret never moves + public final static vector movenment = new vector(0,0,0); + + + //the oreintation of the turret + public int turretAngle; + + //attack range + public float attackRange = 2f; + + //the angle that the turret have rotated between current frame and previous frame + public int turretAngleDelta, accumulatedDelta; + + public int turretTurnRate = 8; + public int myAttackCooldown= 25; + public int attackCoolDown; + public vector firingPosition; + + + //index of the tiles to check when the turret is in standby mode + public static int[] tileCheckList; + + //once the turret starts attacking, it exposed itself to the enemy + public int exposedCountDown; + + public baseInfo theBaseInfo; + + public int attackAngle; + public int randomInt; + + public gunTurret(float x, float y, float z, int teamNo){ + //uncontrollable unit, but act as a big sized static collidable agent + type = 200; + + myDamage = 15; + + ID = globalUniqID++; + randomInt = gameData.getRandom(); + + if(teamNo == 0){ + isRevealed = true; + theBaseInfo = mainThread.pc.theBaseInfo; + }else{ + theBaseInfo = mainThread.ec.theBaseInfo; + } + + theBaseInfo.numberOfGunTurret++; + + + currentHP = maxHP; + + this.teamNo = teamNo; + + currentCommand = StandBy; + + if(teamNo == 0){ + isRevealed = true; + } + + if(tileCheckList == null){ + tileCheckList = generateTileCheckList(8f); + } + + if(bitmapVisionForEnemy == null){ + bitmapVisionForEnemy = createBitmapVision(6); + bitmapVisionGainFromAttackingUnit = createBitmapVision(2); + } + + //create 2D boundary + boundary2D = new Rect((int)(x*64) - 8, (int)(z*64) + 8, 16, 16); + boundary2D.owner = this; + int centerX = (int)(x*64); + int centerY = (int)(z*64); + + tileIndex[0] = centerX/16 + (127 - centerY/16)*128; + + + mainThread.gridMap.tiles[tileIndex[0]][0] = this; + mainThread.gridMap.tiles[tileIndex[0]][1] = this; + mainThread.gridMap.tiles[tileIndex[0]][2] = this; + mainThread.gridMap.tiles[tileIndex[0]][3] = this; + mainThread.gridMap.tiles[tileIndex[0]][4] = this; + + + + //init model + start = new vector(x,y,z); + iDirection = new vector(1f,0,0); + jDirection = new vector(0,1f,0); + kDirection = new vector(0,0,1f); + + firingPosition = new vector(0,0,0); + + + //define centre of the model in world coordinate + start = new vector(x,y,z); + centre = start.myClone(); + tempCentre = start.myClone(); + + shadowvertex0 =start.myClone(); + shadowvertex0.add(-0.45f,-0.2f, -0.15f); + tempshadowvertex0 = new vector(0,0,0); + + shadowvertex1 =start.myClone(); + shadowvertex1.add(-0.45f,-0.2f, 0.2f); + tempshadowvertex1 = new vector(0,0,0); + + shadowvertex2 =start.myClone(); + shadowvertex2.add(0.2f,-0.2f, -0.15f); + tempshadowvertex2 = new vector(0,0,0); + + shadowvertex3 =start.myClone(); + shadowvertex3.add(0.2f,-0.2f, 0.2f); + tempshadowvertex3 = new vector(0,0,0); + + turretAngle = (int)(360*Math.random()); + + makePolygons(); + + } + + //create polygons + public void makePolygons(){ + polygons = new polygon3D[46]; + vector[] v; + + //turret base + + float l =0.07f; + float h = 0.07f; + v = new vector[]{put(-l,h, l), put(l,h, l), put(l,h, -l), put(-l,h, -l)}; + polygons[0] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[12], 0.5f, 0.5f, 1); + + v = new vector[]{put(-l,h, -l), put(l,h, -l), put(l+0.04,h - 0.15f, -l-0.04), put(-l-0.04,h - 0.15f, -l-0.04)}; + polygons[1] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[12], 0.5f, 0.5f, 1); + + + v = new vector[]{put(-l-0.04,h - 0.15f, l+0.04), put(l+0.04,h - 0.15f, l+0.04), put(l,h, l), put(-l,h, l)}; + polygons[2] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[12], 0.5f, 0.5f, 1); + + + v = new vector[]{put(l,h, -l), put(l,h, l), put(l+0.04,h - 0.15f, l+0.04), put(l+0.04,h - 0.15f, -l-0.04)}; + polygons[3] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[12], 0.5f, 0.5f, 1); + + v = new vector[]{put(-l-0.04,h - 0.15f, -l-0.04), put(-l-0.04,h - 0.15f, l+0.04), put(-l,h, l), put(-l,h, -l)}; + polygons[4] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[12], 0.5f, 0.5f, 1); + + + for(int i = 0; i < 5; i++){ + polygons[i].Ambient_I-=5; + polygons[i].findDiffuse(); + polygons[i].parentObject = this; + + } + + //turret tower + iDirection.scale(0.82f); + kDirection.scale(0.75f); + + iDirection.rotate_XZ(360-turretAngle); + jDirection.rotate_XZ(360-turretAngle); + kDirection.rotate_XZ(360-turretAngle); + + h = 0.11f; + + + vector a1 = put(-0.035, h, 0.08); + vector a2 = put(0.035, h, 0.08); + vector a3 = put(0.06, h, 0.03); + vector a4 = put(0.06, h, -0.05); + vector a5 = put(0.04, h, -0.07); + vector a6 = put(-0.04, h, -0.07); + vector a7 = put(-0.06, h, -0.05); + vector a8 = put(-0.06, h, 0.03); + + int textureIndex = 66; + if(teamNo != 0) + textureIndex = 67; + + v = new vector[]{a1, a2, a3, a4,a5, a6, a7, a8}; + polygons[5] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[5].myClone(), mainThread.textures[textureIndex], 0.7f, 1f, 1); + + iDirection.scale(1.2f); + kDirection.scale(1.2f); + + vector b1 = put(-0.035, 0.07, 0.08); + vector b2 = put(0.035, 0.07, 0.08); + vector b3 = put(0.06, 0.07, 0.03); + vector b4 = put(0.06, 0.07, -0.05); + vector b5 = put(0.04, 0.07, -0.07); + vector b6 = put(-0.04, 0.07, -0.07); + vector b7 = put(-0.06, 0.07, -0.05); + vector b8 = put(-0.06, 0.07, 0.03); + + + v = new vector[]{a2.myClone(), a1.myClone(), b1.myClone(), b2.myClone()}; + polygons[6] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 0.5f, 0.1f, 1); + polygons[6].shadowBias = 20000; + + + v = new vector[]{a1.myClone(), a8.myClone(), b8.myClone(), b1.myClone()}; + polygons[7] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[2].myClone(), mainThread.textures[textureIndex], 0.5f, 0.1f, 1); + + v = new vector[]{a3.myClone(), a2.myClone(), b2.myClone(), b3.myClone()}; + polygons[8] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 0.5f, 0.1f, 1); + + v = new vector[]{a4.myClone(), a3.myClone(), b3.myClone(), b4.myClone()}; + polygons[9] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 0.5f, 0.1f, 1); + + v = new vector[]{a5.myClone(), a4.myClone(), b4.myClone(), b5.myClone()}; + polygons[10] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 0.5f, 0.1f, 1); + + v = new vector[]{a6.myClone(), a5.myClone(), b5.myClone(), b6.myClone()}; + polygons[11] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 0.5f, 0.1f, 1); + + v = new vector[]{a7.myClone(), a6.myClone(), b6.myClone(), b7.myClone()}; + polygons[12] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 0.5f, 0.1f, 1); + + v = new vector[]{a8.myClone(), a7.myClone(), b7.myClone(), b8.myClone()}; + polygons[13] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 0.5f, 0.1f, 1); + + + double r1 = 0.007; + double r2 = 0.01; + + 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.093, 0.05), + put(r2*Math.cos((i+1)*theta), r2*Math.sin((i+1)*theta)+0.093, 0.05), + put(r1*Math.cos((i+1)*theta), r1*Math.sin((i+1)*theta)+0.093, 0.17), + put(r1*Math.cos(i*theta), r1*Math.sin(i*theta)+0.093, 0.17) + }; + polygons[14 +i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[33], 10,10,1); + polygons[14 +i].Ambient_I -=15; + polygons[14 +i].reflectance -=30; + polygons[14 +i].findDiffuse(); + } + + } + + + + //update the model + public void update(){ + //process emerging from ground animation + if(centre.y < -0.5f){ + centre.y+=0.01f; + + if(centre.y > -0.5){ + for(int i = 0; i < polygons.length; i++){ + polygons[i].origin.y+=0.0000005; + polygons[i].rightEnd.y+=0.0000005; + polygons[i].bottomEnd.y+=0.0000005; + + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + polygons[i].vertex3D[j].y+=0.0000005; + } + + } + shadowvertex0.y+=0.0000005; + shadowvertex1.y+=0.0000005; + shadowvertex2.y+=0.0000005; + shadowvertex3.y+=0.0000005; + + centre.y = -0.5f; + }else{ + for(int i = 0; i < polygons.length; i++){ + polygons[i].origin.y+=0.01; + polygons[i].rightEnd.y+=0.01; + polygons[i].bottomEnd.y+=0.01; + + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + polygons[i].vertex3D[j].y+=0.01; + } + + + } + shadowvertex0.y+=0.01; + shadowvertex1.y+=0.01; + shadowvertex2.y+=0.01; + shadowvertex3.y+=0.01; + } + + //the building is invulnerable during emerging stage + currentHP = maxHP; + } + + if(underAttackCountDown > 0) + underAttackCountDown--; + + //check if power plant has been destroyed + if(currentHP <= 0){ + countDownToDeath--; + + if(countDownToDeath == 0){ + //spawn an explosion when the tank is destroyed + float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount]; + tempFloat[0] = centre.x; + tempFloat[1] = centre.y + 0.15f; + 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); + + if(teamNo == 0) + mainThread.pc.theBaseInfo.numberOfGunTurret--; + else + mainThread.ec.theBaseInfo.numberOfGunTurret--; + + + //removeFromGridMap(); + mainThread.gridMap.tiles[tileIndex[0]][0] = null; + mainThread.gridMap.tiles[tileIndex[0]][1] = null; + mainThread.gridMap.tiles[tileIndex[0]][2] = null; + mainThread.gridMap.tiles[tileIndex[0]][3] = null; + mainThread.gridMap.tiles[tileIndex[0]][4] = null; + + if(attacker.teamNo != teamNo) + attacker.experience+=20; + + return; + }else{ + + if(mainThread.frameIndex%2==0){ + float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount]; + tempFloat[0] = centre.x + (float)Math.random()/4f - 0.125f; + tempFloat[1] = centre.y + 0.15f; + tempFloat[2] = centre.z + (float)Math.random()/4f - 0.125f; + tempFloat[3] = 1.5f; + tempFloat[4] = 1; + tempFloat[5] = 0; + tempFloat[6] = 6 + (gameData.getRandom()%4); + tempFloat[7] = this.height; + theAssetManager.explosionCount++; + } + return; + } + } + + if(isRepairing && currentHP >0){ + if(mainThread.frameIndex%5==0 && theBaseInfo.currentCredit > 0 && currentHP 0) + attackCoolDown--; + + if(exposedCountDown > 0) + exposedCountDown --; + + //mark itself on obstacle map + mainThread.gridMap.currentObstacleMap[tileIndex[0]] = false; + + + //update center in camera coordinate + tempCentre.set(centre); + tempCentre.subtract(camera.position); + tempCentre.rotate_XZ(camera.XZ_angle); + tempCentre.rotate_YZ(camera.YZ_angle); + tempCentre.updateLocation(); + + theAssetManager = mainThread.theAssetManager; + + //test if the gun turret is visible in camera point of view + if(visibleBoundary.contains(tempCentre.screenX, tempCentre.screenY) && isRevealed){ + visible = true; + + if(screenBoundary.contains(tempCentre.screenX, tempCentre.screenY)) + withinViewScreen = true; + else + withinViewScreen = false; + + tempshadowvertex0.set(shadowvertex0); + tempshadowvertex0.subtract(camera.position); + tempshadowvertex0.rotate_XZ(camera.XZ_angle); + tempshadowvertex0.rotate_YZ(camera.YZ_angle); + tempshadowvertex0.updateLocation(); + + tempshadowvertex1.set(shadowvertex1); + tempshadowvertex1.subtract(camera.position); + tempshadowvertex1.rotate_XZ(camera.XZ_angle); + tempshadowvertex1.rotate_YZ(camera.YZ_angle); + tempshadowvertex1.updateLocation(); + + tempshadowvertex2.set(shadowvertex2); + tempshadowvertex2.subtract(camera.position); + tempshadowvertex2.rotate_XZ(camera.XZ_angle); + tempshadowvertex2.rotate_YZ(camera.YZ_angle); + tempshadowvertex2.updateLocation(); + + tempshadowvertex3.set(shadowvertex3); + tempshadowvertex3.subtract(camera.position); + tempshadowvertex3.rotate_XZ(camera.XZ_angle); + tempshadowvertex3.rotate_YZ(camera.YZ_angle); + tempshadowvertex3.updateLocation(); + + + + //if the object is visible then draw it on the shadow buffer from light point of view + if(shadowBoundary1.contains(tempshadowvertex0.screenX, tempshadowvertex0.screenY) || + shadowBoundary1.contains(tempshadowvertex1.screenX, tempshadowvertex1.screenY) || + shadowBoundary1.contains(tempshadowvertex2.screenX, tempshadowvertex2.screenY) || + shadowBoundary1.contains(tempshadowvertex3.screenX, tempshadowvertex3.screenY) + ){ + for(int i = 0; i < polygons.length; i++){ + polygons[i].update_lightspace(); + + + } + + } + + //add this object to visible unit list + theAssetManager.visibleUnit[theAssetManager.visibleUnitCount] = this; + theAssetManager.visibleUnitCount++; + + + }else{ + visible = false; + } + + + //create vision for enemy commander + if(teamNo == 1){ + int xPos = boundary2D.x1/16 - 6 + 10; + int 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; + } + } + } + + + visionBoundary.x = (int)(tempCentre.screenX - 800); + visionBoundary.y = (int)(tempCentre.screenY - 1000); + visionInsideScreen = camera.screen.intersects(visionBoundary); + + + if(visionInsideScreen){ + if(teamNo != 0){ + if(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++; + } + } + + + if(theAssetManager.minimapBitmap[tileIndex[0]]){ + isRevealed = true; + } + visible_minimap = isRevealed; + + + 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{ + if(exposedCountDown > 0) + tempInt[4] = exposedCountDown; + else + tempInt[4] = 10000; + } + theAssetManager.unitsForMiniMapCount++; + + } + + + + + accumulatedDelta+=turretAngleDelta; + accumulatedDelta= accumulatedDelta%360; + if(visible){ + //update turret polygons + for(int i = 5; i < 46; i++){ + + polygons[i].origin.subtract(centre); + polygons[i].origin.rotate_XZ(accumulatedDelta); + polygons[i].origin.add(centre); + + + polygons[i].bottomEnd.subtract(centre); + polygons[i].bottomEnd.rotate_XZ(accumulatedDelta); + polygons[i].bottomEnd.add(centre); + + + polygons[i].rightEnd.subtract(centre); + polygons[i].rightEnd.rotate_XZ(accumulatedDelta); + polygons[i].rightEnd.add(centre); + + + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + + polygons[i].vertex3D[j].subtract(centre); + polygons[i].vertex3D[j].rotate_XZ(accumulatedDelta); + polygons[i].vertex3D[j].add(centre); + } + + + polygons[i].normal.rotate_XZ(accumulatedDelta); + polygons[i].findDiffuse(); + } + accumulatedDelta = 0; + + } + + } + + //process turret AI + public void carryOutCommands(){ + if(targetObject != null){ + destinationX = targetObject.getRealCentre().x; + destinationY = targetObject.getRealCentre().z; + + 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 + boolean 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; + } + } + } + + }else{ + hasLineOfSightToTarget = false; + } + + + if(targetObject.currentHP <=0 || (targetObject.isCloaked && teamNo != targetObject.teamNo)){ + targetObject = null; + turretAngleDelta = 0; + return; + } + + if(hasLineOfSightToTarget){ + 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) + fireBullet(attackAngle); + }else{ + fireBullet(attackAngle); + turretAngleDelta = 0; + } + }else{ + turretAngleDelta = 0; + targetObject = null; + } + }else{ + //if there is no target, perform standby logic + //scan for hostile unit + + if((randomInt + mainThread.frameIndex)%240 == 0){ + attackAngle = (int)(Math.random()*360); + } + if(turretAngle != attackAngle){ + + turretAngleDelta = 360 - (geometry.findAngleDelta(turretAngle, attackAngle, 2) + 360)%360; + turretAngle= (turretAngle - turretAngleDelta + 360)%360; + + }else{ + + turretAngleDelta = 0; + } + + + if((ID + mainThread.frameIndex)%4 == 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) + 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){ + targetObject = tile[j]; + return; + } + } + } + } + } + } + + + + } + } + + + //draw the model + public void draw(){ + + if(!visible) + return; + for(int i = 0; i < polygons.length; i++){ + polygons[i].update(); + polygons[i].draw(); + } + } + + public void attack(solidObject o){ + if(targetObject != o){ + + distanceToDesination = (float)Math.sqrt((o.centre.x - centre.x) * (o.centre.x - centre.x) + (o.centre.z - centre.z) * (o.centre.z - centre.z)); + + //check if target is within range + if(distanceToDesination <= attackRange){ + + + //check if there is any obstacles between target and the turret + //check if light tank has the line of sight to its target + boolean hasLineOfSightToTarget = true; + + int numberOfIterations = (int)(distanceToDesination * 8); + float dx = (o.centre.x - centre.x)/numberOfIterations; + float dy = (o.centre.z - 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 != o){ + hasLineOfSightToTarget = false; + break; + } + } + } + + if(hasLineOfSightToTarget){ + targetObject = o; + } + + } + + } + } + + public void fireBullet(int attackAngle){ + if(targetObject != null && targetObject.teamNo != teamNo){ + exposedCountDown = 64; + isRevealed = true; + } + + int theDamage = myDamage; + if(targetObject.type == 0) + theDamage = 20; + + if(attackCoolDown == 0 ){ + //if there is nothing between the tank and its target + firingPosition.set(0, -0.4f, 0.18f); + firingPosition.rotate_XZ(360 - attackAngle); + firingPosition.add(centre.x, 0, centre.z); + theAssetManager.spawnBullet(attackAngle, theDamage, targetObject, firingPosition, this); + attackCoolDown = myAttackCooldown; + + //spawn a mini explosion + float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount]; + tempFloat[0] = firingPosition.x; + tempFloat[1] = firingPosition.y; + tempFloat[2] = firingPosition.z; + tempFloat[3] = 0.4f; + tempFloat[4] = 3; + tempFloat[5] = 0; + tempFloat[6] = 6 + (gameData.getRandom()%4); + tempFloat[7] = centre.y; + theAssetManager.explosionCount++; + } + } + + public void hold(){ + targetObject = null; + turretAngleDelta = 0; + } + + public vector getMovement(){ + return movenment; + } +} diff --git a/entity/harvester.java b/entity/harvester.java new file mode 100644 index 0000000..265b305 --- /dev/null +++ b/entity/harvester.java @@ -0,0 +1,1806 @@ +package entity; + +import java.awt.Rectangle; + +import core.*; +import enemyAI.enemyCommander; + +public class harvester extends solidObject{ + + public vector iDirectionBody, jDirectionBody, kDirectionBody; + + public static vector cargoCenter; + public vector cargoCenterClone; + public int cargoAngle = 360; + + public static vector pillarCenter; + public vector pillarCenterClone; + public int pillarAngle = 360; + + public int unloadingCount; + + public static polygon3D[] body, drill0, drill1, drill2, cargo, pillars; + + public int drillIndex = 2; + public int drillingCount; + + public polygon3D[] bodyClone, drillClone0, drillClone1, drillClone2, cargoClone, pillarsClone; + + + public static int maxHP = 260; + + //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,908, 597); + + //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,688, 432); + + //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, 1300); + + //a bitmap representation of the vision of the harvester for enemy commander + public static boolean[] bitmapVisionForEnemy; + + //the oreintation of the harvester + public int bodyAngle; + + //destination angle + public int destinationAngle; + + public static Rect border, destinationBlock, probeBlock, pointBlock; + + public goldMine myGoldMine; + public refinery myRefinery; + public int[] miningPositions; + public int cargoDeposite; + + public int myMiningPosition; + public int myDropPosition; + public float insideRefineryPositionX; + public float insideRefineryPositionY; + + + public int jobStatus = 0; + public final int idle = 0; + public final int isDrilling = 1; + public final int headingToMine=2; + public final int returningToRefinery = 3; + public final int unloadingCargo = 4; + public final int enteringRefinery = 5; + public final int leavingRefinery = 6; + public final int facingGoldMine = 7; + public final int facingRefinery = 8; + public final int facingRight = 9; + public final int facingDownward = 10; + + public int waitingCount = 0; + + + public int heuristicRecalculationCountDown; + public byte[] heuristicMap; + public boolean pathIsFound; + public float nextNodeX, nextNodeY; + public int bodyTurnRate = 5; + + public boolean insideRefinery; + + public boolean isEvadingFromAttack; + + + public harvester(vector origin, int bodyAngle, int teamNo){ + speed = 0.008f; + start = new vector(0,0,0); + centre = origin.myClone(); + tempCentre = origin.myClone(); + this.bodyAngle = bodyAngle; + immediateDestinationAngle = bodyAngle; + progressStatus = 0; + attackStatus = isAttacking; + miningPositions = new int[8]; + + destinationAngle = bodyAngle; + this.teamNo = teamNo; + currentHP = maxHP; + type = 2; + if(bitmapVisionForEnemy == null){ + bitmapVisionForEnemy = createBitmapVision(6); + } + + + 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); + border = new Rect(0,0,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); + pointBlock = new Rect((int)(origin.x*64) - 6, (int)(origin.z*64) + 6, 12, 12); + + //create main axis in object space + iDirection = new vector(1f,0,0); + jDirection = new vector(0,1f,0); + kDirection = new vector(0,0,1f); + + //create polygons + makePolygons(); + + heuristicMap = new byte[128 * 128]; + } + + public void makePolygons(){ + + + int skinTextureIndex = 23; + + if(body == null){ + + body = new polygon3D[52]; + v = new vector[]{put(-0.071, 0.025, 0.11), put(-0.071, 0.025, -0.15), put(-0.071, 0.005, -0.15), put(-0.071, -0.025, -0.08), put(-0.071, -0.025, 0.07), put(-0.071, 0.005, 0.11)}; + body[0] = new polygon3D(v, put(-0.071, 0.027, 0.11), put(-0.071, 0.027, -0.15), put(-0.071, -0.025, 0.11), mainThread.textures[3], 1,1,1); + + v = new vector[]{put(0.071, 0.005, 0.11), put(0.071, -0.025, 0.07), put(0.071, -0.025, -0.08), put(0.071, 0.005, -0.15), put(0.071, 0.025, -0.15), put(0.071, 0.025, 0.11)}; + body[1] = new polygon3D(v, put(0.071, 0.027, -0.15),put(0.071, 0.027, 0.11), put(0.071, -0.025, -0.15), mainThread.textures[3], 1,1,1); + + v = new vector[]{put(-0.07, 0.04, -0.15), put(0.07, 0.04, -0.15), put(0.07, 0.015, -0.15), put(-0.07, 0.015, -0.15)}; + body[2] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 1,0.3f,1); + + v = new vector[]{put(-0.07, 0.005, -0.15), put(-0.04, 0.005, -0.15), put(-0.04, -0.025, -0.08), put(-0.07, -0.025, -0.08)}; + body[3] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[3], 1,1,1); + + v = new vector[]{put(-0.07, 0.015, -0.15), put(-0.04, 0.015, -0.15), put(-0.04, 0.005, -0.15), put(-0.07, 0.005, -0.15)}; + body[4] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[3], 1,1,1); + + v = new vector[]{put(0.04, 0.015, -0.15), put(0.07, 0.015, -0.15), put(0.07, 0.005, -0.15), put(0.04, 0.005, -0.15)}; + body[5] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[3], 1,1,1); + + v = new vector[]{put(0.04, 0.005, -0.15), put(0.07, 0.005, -0.15), put(0.07, -0.025, -0.08), put(0.04, -0.025, -0.08)}; + body[6] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[3], 1,1,1); + + v = new vector[]{put(0.07, 0.04, -0.15), put(0.07, 0.04, 0.11), put(0.07, 0.015, 0.11),put(0.07, 0.015, -0.15)}; + body[7] = new polygon3D(v, put(0.07, 0.04, -0.15), put(0.07, 0.04, 0.11), put(0.07, 0.015, -0.15), mainThread.textures[skinTextureIndex], 1,0.3f,1); + + v = new vector[]{put(-0.07, 0.04, 0.11), put(-0.07, 0.04, -0.15), put(-0.07, 0.015, -0.15), put(-0.07, 0.015, 0.11)}; + body[8] = new polygon3D(v, put(-0.07, 0.04, 0.11), put(-0.07, 0.04, -0.15), put(-0.07, 0.015, 0.11), mainThread.textures[skinTextureIndex], 1,0.3f,1); + + v = new vector[]{put(0.07, 0.04, 0.11), put(-0.07, 0.04, 0.11), put(-0.07, 0.01, 0.11), put(0.07, 0.01, 0.11)}; + body[9] = new polygon3D(v, v[2], v[3], v [1], mainThread.textures[skinTextureIndex], 1,0.3f,1); + + v = new vector[]{put(0.07, 0.04, 0.11), put(-0.07, 0.04, 0.11), put(-0.07, 0.01, 0.11), put(0.07, 0.01, 0.11)}; + body[10] = new polygon3D(v, v[2], v[3], v [1], mainThread.textures[skinTextureIndex], 1,0.3f,1); + + v = new vector[]{put(0.07, 0.04, 0.11), put(0.07, 0.04, -0.15), put(-0.07, 0.04, -0.15),put(-0.07, 0.04, 0.11)}; + body[11] = new polygon3D(v, v[1], v[2], v[0], mainThread.textures[skinTextureIndex], 1,2f,1); + body[11].shadowBias = 1000; + + v = new vector[]{put(-0.07, 0.12, 0.07), put(-0.07, 0.12, 0.02), put(-0.07, 0.04, 0.02), put(-0.07, 0.04, 0.11), put(-0.07, 0.07, 0.11)}; + body[12] = new polygon3D(v, put(-0.07, 0.12, 0.11), put(-0.07, 0.12, 0.02), put(-0.07, 0.04, 0.11), mainThread.textures[skinTextureIndex], 0.7f,0.7f,1); + + v = new vector[]{put(0, 0.07, 0.11), put(0, 0.04, 0.11), put(0, 0.04, 0.02), put(0, 0.12, 0.02), put(0, 0.12, 0.07)}; + body[13] = new polygon3D(v, put(0, 0.12, 0.02), put(0, 0.12, 0.11), put(0, 0.04, 0.02), mainThread.textures[skinTextureIndex], 0.7f,0.7f,1); + + v = new vector[]{put(-0.07, 0.12, 0.02), put(0.07, 0.12, 0.02), put(0.07, 0.04, 0.02), put(-0.07, 0.04, 0.02)}; + body[14] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1,0.7f,1); + + v = new vector[]{put(0, 0.07, 0.11 ), put(-0.07, 0.07, 0.11 ), put(-0.07, 0.04, 0.11 ), put(0, 0.04, 0.11 )}; + body[15] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 0.5f,0.5f,1); + + v = new vector[]{put(0, 0.12, 0.02), put(-0.07, 0.12, 0.02), put(-0.07, 0.12, 0.07), put(0, 0.12, 0.07)}; + body[16] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 0.5f,0.5f,1); + + v= new vector[]{put(0, 0.12, 0.07), put(-0.07, 0.12, 0.07), put(-0.07, 0.07, 0.11), put(0, 0.07, 0.11)}; + body[17] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[24], 1f,1f,1); + body[17].shadowBias = 40000; + + v = new vector[]{put(-0.07, 0.04, 0.02), put(0.07, 0.04, 0.02), put(0.07, 0.12, 0.02), put(-0.07, 0.12, 0.02)}; + body[18] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1,0.7f,1); + + v = new vector[]{put(0.07, 0.12, 0.02),put(0.07, 0.15, 0.04), put(0.07, 0.16, 0.10), put(0.07, 0.15, 0.10), put(0.07, 0.12, 0.07)}; + body[19] = new polygon3D(v, put(0.07, 0.12, 0.02), put(0.07, 0.12, 0.13), put(0.07, 0.02, 0.02), mainThread.textures[skinTextureIndex], 1, 1,1); + + v = new vector[]{put(0, 0.12, 0.07), put(0, 0.15, 0.10), put(0, 0.16, 0.10),put(0, 0.15, 0.04),put(0, 0.12, 0.02) }; + body[20] = new polygon3D(v, put(0, 0.12, 0.13),put(0, 0.12, 0.02), put(0, 0.02, 0.13), mainThread.textures[skinTextureIndex], 1, 1,1); + + v = new vector[]{put(0, 0.15, 0.04), put(0.07, 0.15, 0.04), put(0.07, 0.12, 0.02), put(0, 0.12, 0.02)}; + body[21] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 0.5f,0.25f,1); + + v = new vector[]{put(0, 0.16, 0.10), put(0.07, 0.16, 0.10), put(0.07, 0.15, 0.04), put(0, 0.15, 0.04) }; + body[22] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 0.5f,0.5f,1); + + v = new vector[]{put(0, 0.12, 0.02),put(0, 0.15, 0.04), put(0, 0.16, 0.10), put(0, 0.15, 0.10), put(0, 0.12, 0.07)}; + body[23] = new polygon3D(v, put(0, 0.12, 0.02), put(0, 0.12, 0.13), put(0, 0.02, 0.02), mainThread.textures[skinTextureIndex], 1, 1,1); + + v = new vector[]{put(0.07, 0.12, 0.07), put(0.07, 0.15, 0.10), put(0.07, 0.16, 0.10),put(0.07, 0.15, 0.04),put(0.07, 0.12, 0.02) }; + body[24] = new polygon3D(v, put(0.07, 0.12, 0.13),put(0.07, 0.12, 0.02), put(0.07, 0.02, 0.13), mainThread.textures[skinTextureIndex], 1, 1,1); + + v = new vector[]{put(0.07, 0.16, 0.10), put(0, 0.16, 0.10), put(0, 0.15, 0.10), put(0.07, 0.15, 0.10)}; + body[25] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 0.5f,0.1f,1); + + v = new vector[]{put(0.07, 0.12, 0.02), put(0.07, 0.12, 0.07), put(0.07, 0.04, 0.07), put(0.07, 0.04, 0.02) }; + body[26] = new polygon3D(v, put(0.07, 0.12, 0.02), put(0.07, 0.12, 0.13), put(0.07, 0.02, 0.02), mainThread.textures[skinTextureIndex], 1, 1,1); + + v = new vector[]{put(0.07, 0.04, 0.02), put(0.07, 0.04, 0.07), put(0.07, 0.12, 0.07) , put(0.07, 0.12, 0.02)}; + body[27] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 0.5f,0.1f,1); + + v = new vector[]{put(0.07, 0.12, 0.07), put(0.06, 0.12, 0.07), put(0.06, 0.04, 0.07), put(0.07, 0.04, 0.07)}; + body[28] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 0.1f,0.5f,1); + + v = new vector[]{put(0.01, 0.12, 0.07), put(0, 0.12, 0.07), put(0, 0.04, 0.07), put(0.01, 0.04, 0.07)}; + body[29] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 0.1f,0.5f,1); + + v = new vector[]{put(0.07, 0.08, 0.07), put(0, 0.08, 0.07), put(0, 0.04, 0.11), put(0.07, 0.04, 0.11)}; + body[30] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 0.5f,0.5f,1); + + v = new vector[]{put(0.07, 0.08, 0.07), put(0.07, 0.04, 0.11), put(0.07, 0.04, 0.07)}; + body[31] = new polygon3D(v, put(0.07, 0.12, 0.02), put(0.07, 0.12, 0.13), put(0.07, 0.02, 0.02), mainThread.textures[skinTextureIndex], 1, 1,1); + + + v = new vector[]{put(0.055, 0.21, 0), put(0.055, 0.21, 0.06), put(0.055, 0.18, 0.06),put(0.055, 0.18, 0)}; + body[32] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 4f,4f,1); + + v = new vector[]{put(0.015, 0.18, 0), put(0.015, 0.18, 0.06), put(0.015, 0.21, 0.06),put(0.015, 0.21, 0)}; + body[33] = new polygon3D(v, v[2].myClone(), v[3].myClone(), v[1].myClone(), mainThread.textures[25], 4f,4f,1); + + v = new vector[]{put(0.055, 0.21, 0), put(0.015, 0.21, 0), put(0.015, 0.21, 0.06), put(0.055, 0.21, 0.06)}; + body[34] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 4f,4f,1); + body[34].shadowBias = 30000; + + v = new vector[]{put(0.055, 0.21, 0.06), put(0.055, 0.21, 0.12), put(0.055, 0.18, 0.12),put(0.055, 0.18, 0)}; + body[35] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 4f,4f,1); + + v = new vector[]{put(0.015, 0.18, 0.06), put(0.015, 0.18, 0.12), put(0.015, 0.21, 0.12),put(0.015, 0.21, 0)}; + body[36] = new polygon3D(v, v[2].myClone(), v[3].myClone(), v[1].myClone(), mainThread.textures[25], 4f,4f,1); + + v = new vector[]{put(0.055, 0.21, 0.06), put(0.015, 0.21, 0.06), put(0.015, 0.21, 0.12), put(0.055, 0.21, 0.12)}; + body[37] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 4f,4f,1); + body[37].shadowBias = 50000; + + + double theta = Math.PI/12; + double r = 0.015; + + start.add(0,(float)(0.18 + r),0.12f); + for(int i = 0; i < 12; i++){ + v = new vector[]{put(0.055, r*Math.cos((i+1)*theta), r*Math.sin((i+1)*theta)), + put(0.055, r*Math.cos(i*theta), r*Math.sin(i*theta)), + put(0.015, r*Math.cos(i*theta), r*Math.sin(i*theta)), + put(0.015, r*Math.cos((i+1)*theta), r*Math.sin((i+1)*theta)) + + }; + body[38 + i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 4f,4f,1); + + } + + + v = new vector[13]; + for(int i = 0; i < 13; i ++){ + v[i] = put(0.055, r*Math.cos(i*theta), r*Math.sin(i*theta)); + } + body[50] = new polygon3D(v, put(0.055, 0.21, 0.06), put(0.055, 0.21, 0.12), put(0.055, 0.18, 0), mainThread.textures[25], 4f,4f,1); + + vector[] v2 = new vector[13]; + for(int i = 0; i < 13; i ++){ + v2[i] = v[12 -i].myClone(); + v2[i].x = 0.015f; + } + body[51] = new polygon3D(v2, put(0.015, 0.21, 0.12), put(0.015, 0.21, 0), put(0.015, 0.18, 0.12), mainThread.textures[25], 4f,4f,1); + + start.add(0,(float)(-0.18 - r),-0.12f); + + drill0 = new polygon3D[32]; + + makeTriangle(drill0, 0, 0, 0,0,0.01f); + makeTriangle(drill0, 4, 0, 0,0,0.03f); + makeTriangle(drill0, 8, 0, 0,0,0.05f); + makeTriangle(drill0, 12, 0, 0,0,0.07f); + makeTriangle(drill0, 16, 0, 0,0,0.09f); + makeTriangle(drill0, 20, 0, 0,0,0.11f); + makeTriangle(drill0, 24, 55, 0,0.085f,-0.045f); + makeTriangle(drill0, 28, 100, 0, 0.23f,-0.075f); + + + drill1 = new polygon3D[32]; + + makeTriangle(drill1, 0, 0, 0,0,0.0166f); + makeTriangle(drill1, 4, 0, 0,0,0.0366f); + makeTriangle(drill1, 8, 0, 0,0,0.0566f); + makeTriangle(drill1, 12, 0, 0,0,0.0766f); + makeTriangle(drill1, 16, 0, 0,0,0.0966f); + makeTriangle(drill1, 20, 15, 0,0.0065f,0.062f); + makeTriangle(drill1, 24, 70, 0,0.13f,-0.068f); + makeTriangle(drill1, 28, 0, 0,0, -0.0034f); + + + drill2 = new polygon3D[32]; + + makeTriangle(drill2, 0, 0, 0,0,0.0166f + 0.0066f); + makeTriangle(drill2, 4, 0, 0,0,0.0366f + 0.0066f); + makeTriangle(drill2, 8, 0, 0,0,0.0566f + 0.0066f); + makeTriangle(drill2, 12, 0, 0,0,0.0766f + 0.0066f); + makeTriangle(drill2, 16, 0, 0,0,0.0966f + 0.0066f); + makeTriangle(drill2, 20, 40, 0,0.05f,-0.012f); + makeTriangle(drill2, 24, 80, 0,0.16f,-0.075f); + makeTriangle(drill2, 28, 0, 0,0, -0.0034f + 0.0066f); + + + + int YZ_angle = 50; + tempVector.set(0,-0.01f, -0.08f); + for(int i = 32; i < body.length; i++){ + + body[i].origin.rotate_YZ(YZ_angle); + body[i].origin.add(tempVector); + + body[i].bottomEnd.rotate_YZ(YZ_angle); + body[i].bottomEnd.add(tempVector); + + body[i].rightEnd.rotate_YZ(YZ_angle); + body[i].rightEnd.add(tempVector); + + + + for(int j = 0; j < body[i].vertex3D.length; j++){ + + body[i].vertex3D[j].rotate_YZ(YZ_angle); + body[i].vertex3D[j].add(tempVector); + + + + } + body[i].normal.rotate_YZ(YZ_angle); + } + + for(int i = 0; i < body.length; i++){ + body[i].findDiffuse(); + body[i].parentObject = this; + + } + + + for(int i = 0; i < drill0.length; i++){ + + drill0[i].origin.rotate_YZ(YZ_angle); + drill0[i].origin.add(tempVector); + + drill0[i].bottomEnd.rotate_YZ(YZ_angle); + drill0[i].bottomEnd.add(tempVector); + + drill0[i].rightEnd.rotate_YZ(YZ_angle); + drill0[i].rightEnd.add(tempVector); + + drill1[i].origin.rotate_YZ(YZ_angle); + drill1[i].origin.add(tempVector); + + drill1[i].bottomEnd.rotate_YZ(YZ_angle); + drill1[i].bottomEnd.add(tempVector); + + drill1[i].rightEnd.rotate_YZ(YZ_angle); + drill1[i].rightEnd.add(tempVector); + + drill2[i].origin.rotate_YZ(YZ_angle); + drill2[i].origin.add(tempVector); + + drill2[i].bottomEnd.rotate_YZ(YZ_angle); + drill2[i].bottomEnd.add(tempVector); + + drill2[i].rightEnd.rotate_YZ(YZ_angle); + drill2[i].rightEnd.add(tempVector); + + + + for(int j = 0; j < drill0[i].vertex3D.length; j++){ + + drill0[i].vertex3D[j].rotate_YZ(YZ_angle); + drill0[i].vertex3D[j].add(tempVector); + + drill1[i].vertex3D[j].rotate_YZ(YZ_angle); + drill1[i].vertex3D[j].add(tempVector); + + drill2[i].vertex3D[j].rotate_YZ(YZ_angle); + drill2[i].vertex3D[j].add(tempVector); + + } + + drill0[i].normal.rotate_YZ(YZ_angle); + drill0[i].findDiffuse(); + drill0[i].parentObject = this; + + drill1[i].normal.rotate_YZ(YZ_angle); + drill1[i].findDiffuse(); + drill1[i].parentObject = this; + + drill2[i].normal.rotate_YZ(YZ_angle); + drill2[i].findDiffuse(); + drill2[i].parentObject = this; + + + } + + start.set(0,0,0); + cargoCenter = put(0, 0.04, -0.15); + cargo = new polygon3D[11]; + v = new vector[]{put(-0.06, 0, -0.02), put(0.06, 0, -0.02), put(0.06, 0, 0.16), put(-0.06, 0, 0.16)}; + cargo[0] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1f,1.5f,1); + + v = new vector[]{put(0.07, 0.01, -0.02), put(0.07, 0.01, 0.16), put(0.06, 0, 0.16), put(0.06, 0, -0.02)}; + cargo[1] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1.5f,0.1f,1); + + v = new vector[]{put(-0.06, 0, -0.02), put(-0.06, 0, 0.16), put(-0.07, 0.01, 0.16), put(-0.07, 0.01, -0.02)}; + cargo[2] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1.5f,0.1f,1); + + v = new vector[]{put(0.07, 0.06, -0.02),put(0.07, 0.06, 0.16), put(0.07, 0.01, 0.16), put(0.07, 0.01, -0.02)}; + cargo[3] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1.5f,0.5f,1); + + v = new vector[]{put(-0.07, 0.01, -0.02), put(-0.07, 0.01, 0.16),put(-0.07, 0.06, 0.16), put(-0.07, 0.06, -0.02)}; + cargo[4] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1.5f,0.5f,1); + + v = new vector[]{put(-0.07, 0.06, -0.02), put(-0.06, 0.07, -0.02), put(0.06, 0.07, -0.02), put(0.07, 0.06, -0.02), put(0.07, 0.01, -0.02), put(0.06, 0, -0.02), put(-0.06, 0, -0.02), put(-0.07, 0.01, -0.02)}; + cargo[5] = new polygon3D(v, put(-0.07, 0.07, -0.02), put(0.07, 0.07, -0.02),put(-0.07, 0.01, -0.02), mainThread.textures[skinTextureIndex], 1f,0.5f,1); + + v = new vector[]{put(-0.07, 0.01, 0.16), put(-0.06, 0, 0.16), put(0.06, 0, 0.16), put(0.07, 0.01, 0.16), put(0.07, 0.06, 0.16), put(0.06, 0.07, 0.16), put(-0.06, 0.07, 0.16), put(-0.07, 0.06, 0.16)}; + cargo[6] = new polygon3D(v, put(0.07, 0.07, 0.16), put(-0.07, 0.07, 0.16), put(0.07, 0.01, 0.16), mainThread.textures[skinTextureIndex], 1f,0.5f,1); + + v = new vector[]{put(-0.06, 0.07, 0.16), put(0.06, 0.07, 0.16), put(0.06, 0.07, -0.02), put(-0.06, 0.07, -0.02)}; + cargo[7] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 0.8f,1.3f,1); + + v = new vector[]{put(0.065, 0.06, 0.161), put(0.005, 0.06, 0.161), put(0.005, 0.02, 0.161), put(0.065, 0.02, 0.161)}; + cargo[8] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[27], 1f,1f,1); + + v = new vector[]{put(0.06, 0.07, -0.02), put(0.06, 0.07, 0.16), put(0.07, 0.06, 0.16), put(0.07, 0.06, -0.02)}; + cargo[9] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1.5f,0.1f,1); + + v = new vector[]{put(-0.07, 0.06, -0.02), put(-0.07, 0.06, 0.16), put(-0.06, 0.07, 0.16), put(-0.06, 0.07, -0.02)}; + cargo[10] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 1.5f,0.1f,1); + + + start.set(0,0,0); + pillarCenter = put(0, 0.035,0); + pillars = new polygon3D[98]; + + theta = Math.PI/12; + r = 0.008; + + for(int i = 0; i < 24; i++){ + v = new vector[]{put(r*Math.cos((i+1)*theta) - 0.03, r*Math.sin((i+1)*theta), 0), + put(r*Math.cos(i*theta) - 0.03, r*Math.sin(i*theta), 0), + put(r*Math.cos(i*theta) - 0.03, r*Math.sin(i*theta), -0.07 ), + put(r*Math.cos((i+1)*theta) - 0.03, r*Math.sin((i+1)*theta), -0.07), + + }; + pillars[i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[28], 4f,4f,1); + } + + v = new vector[24]; + for(int i = 0; i < 24; i ++){ + v[23 -i] = put(r*Math.cos(i*theta) - 0.03, r*Math.sin(i*theta), -0.07); + } + pillars[24] = new polygon3D(v, put(0.21 - 0.03, 0.06, -0.07), put(0.21 - 0.03, 0.12, -0.07), put(0.18 - 0.03, 0, -0.07), mainThread.textures[28], 4f,4f,1); + + for(int i = 0; i < 24; i++){ + v = new vector[]{put(r*Math.cos((i+1)*theta) + 0.03, r*Math.sin((i+1)*theta), 0), + put(r*Math.cos(i*theta) + 0.03, r*Math.sin(i*theta), 0), + put(r*Math.cos(i*theta) + 0.03, r*Math.sin(i*theta), -0.07 ), + put(r*Math.cos((i+1)*theta) + 0.03, r*Math.sin((i+1)*theta), -0.07), + + }; + pillars[25 + i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[28], 4f,4f,1); + } + + v = new vector[24]; + for(int i = 0; i < 24; i ++){ + v[23 -i] = put(r*Math.cos(i*theta) + 0.03, r*Math.sin(i*theta), -0.07); + } + pillars[49] = new polygon3D(v, put(0.21 + 0.03, 0.06, -0.07), put(0.21 + 0.03, 0.12, -0.07), put(0.18 + 0.03, 0, -0.07), mainThread.textures[28], 4f,4f,1); + + r = 0.004; + for(int i = 0; i < 24; i++){ + v = new vector[]{put(r*Math.cos((i+1)*theta) - 0.03, r*Math.sin((i+1)*theta), -0.07), + put(r*Math.cos(i*theta) - 0.03, r*Math.sin(i*theta), -0.07), + put(r*Math.cos(i*theta) - 0.03, r*Math.sin(i*theta), -0.15 ), + put(r*Math.cos((i+1)*theta) - 0.03, r*Math.sin((i+1)*theta), -0.15), + + }; + pillars[50 + i ] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[29], 4f,4f,1); + } + + for(int i = 0; i < 24; i++){ + v = new vector[]{put(r*Math.cos((i+1)*theta) + 0.03, r*Math.sin((i+1)*theta), -0.07), + put(r*Math.cos(i*theta) + 0.03, r*Math.sin(i*theta), -0.07), + put(r*Math.cos(i*theta) + 0.03, r*Math.sin(i*theta), -0.15 ), + put(r*Math.cos((i+1)*theta) + 0.03, r*Math.sin((i+1)*theta), -0.15), + + }; + pillars[74 + i ] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[29], 4f,4f,1); + } + + } + + bodyClone = clonePolygons(body,true); + drillClone0 = clonePolygons(drill0,true); + drillClone1 = clonePolygons(drill1,true); + drillClone2 = clonePolygons(drill2,true); + cargoClone = clonePolygons(cargo,true); + cargoCenterClone = new vector(0,0,0); + pillarsClone = clonePolygons(pillars,true); + pillarCenterClone = new vector(0,0,0); + + if(teamNo != 0){ + for(int i = 0; i < body.length; i++){ + if(body[i].myTexture.ID == 23) + bodyClone[i].myTexture = mainThread.textures[10]; + } + + for(int i = 0; i < cargo.length; i++){ + if(cargo[i].myTexture.ID == 23) + cargoClone[i].myTexture = mainThread.textures[10]; + } + } + } + + public void makeTriangle(polygon3D[] triangles, int startIndex, int angle, float x, float y, float z){ + float x_old = start.x; + float y_old = start.y; + float z_old = start.z; + start.set(x,y,z); + jDirection.rotate_YZ(angle); + kDirection.rotate_YZ(angle); + + v = new vector[]{put(0.02, 0.225, 0), put(0.05, 0.225, 0), put(0.05, 0.21, 0), put(0.02, 0.21, 0)}; + triangles[startIndex] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[26], 4f,4f,1); + + v = new vector[]{put(0.05, 0.225, 0), put(0.02, 0.225, 0), put(0.02, 0.21, 0.01f), put(0.05, 0.21, 0.01f)}; + triangles[startIndex + 1] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[26], 4f,4f,1); + + v = new vector[]{put(0.05, 0.225, 0), put(0.05, 0.21, 0.01f), put(0.05, 0.21, 0)}; + triangles[startIndex + 2] = new polygon3D(v, v[0].myClone(), put(0.05, 0.225, 0.01), v[2].myClone(), mainThread.textures[26], 4f,4f,1); + + v = new vector[]{put(0.02, 0.21, 0), put(0.02, 0.21, 0.01f), put(0.02, 0.225, 0)}; + triangles[startIndex + 3] = new polygon3D(v, put(0.02, 0.21, 0f), put(0.02, 0.21, 0.01), put(0.02, 0.225, 0f), mainThread.textures[26], 4f,4f,1); + + + start.set(x_old, y_old, z_old); + jDirection.rotate_YZ(360 - angle); + kDirection.rotate_YZ(360 -angle); + + } + + + + //update the model + public void update(){ + + + //handle unloading gold ore event + if(unloadingCount > 0){ + if(unloadingCount > 69 && cargoAngle > 300) + cargoAngle-=2; + + + if(unloadingCount < 31 && cargoAngle < 360) + cargoAngle+=2; + + unloadingCount--; + } + + //handle drilling event + if(drillingCount > 0){ + drillIndex--; + drillIndex = (drillIndex + 3)%3; + drillingCount --; + } + + if(waitingCount > 0) + waitingCount --; + + if(underAttackCountDown > 0) + underAttackCountDown--; + + + //check if harvester 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+=25; + if(insideRefinery){ + if(myRefinery!= null) + myRefinery.isBusy = false; + } + + return; + } + + //carry out commands given by the player or AI + if(!disableUnitLevelAI) + carryOutCommands(); + + + + if(tightSpaceManeuverCountDown > 0) + tightSpaceManeuverCountDown--; + + if(heuristicRecalculationCountDown > 0) + heuristicRecalculationCountDown--; + + //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(); + } + + + //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 - 650); + visionInsideScreen = camera.screen.intersects(visionBoundary); + + + //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; + } + } + } + + if(visionInsideScreen && teamNo == 0){ + + 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/16)*128]; + + if(teamNo == 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] = 0; + theAssetManager.unitsForMiniMapCount++; + } + + + + //test if the tank object is visible in camera point of view + if(visible_minimap){ + if(currentHP <= 130 && (mainThread.frameIndex + 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){ + updateGeometry(); + + + for(int i = 0; i < bodyClone.length; i++){ + bodyClone[i].update_lightspace(); + } + + polygon3D[] drillClone; + drillClone = null; + if(drillIndex == 0){ + drillClone = drillClone0; + } + if(drillIndex == 1){ + drillClone = drillClone1; + } + if(drillIndex == 2){ + drillClone = drillClone2; + } + + for(int i = 0; i < drillClone.length; i++){ + drillClone[i].update_lightspace(); + } + + for(int i = 0; i < cargoClone.length; i++){ + cargoClone[i].update_lightspace(); + } + + if(unloadingCount > 0){ + for(int i = 0; i < pillarsClone.length; i++){ + pillarsClone[i].update_lightspace(); + } + } + + theAssetManager.visibleUnit[theAssetManager.visibleUnitCount] = this; + theAssetManager.visibleUnitCount++; + + if(waitingCount > 0) + movement.reset(); + } + + } + + //carry out commands given by player or AI commander + public void carryOutCommands(){ + + + if(currentCommand == StandBy){ + resetLogicStatus(); + jobStatus = idle; + + }else if(currentCommand == move){ + float d = Math.abs(destinationX - centre.x) + Math.abs(destinationY - centre.z); + + if(waitingCount <= 1){ + if(d < 1.5f){ + if(jobStatus == headingToMine){ + //check if the mining spot is already occupied + tile = mainThread.gridMap.tiles[myMiningPosition]; + for(int i = 0; i < 5; i++){ + if(tile[i] != null && tile[i] != this){ + if(tile[i].getMovement().x ==0 && tile[i].getMovement().z == 0){ + boolean foundFreeSpot = false; + for(int j = 0; j < 7; j++){ + int p = miningPositions[(myMiningPosition + j)%8]; + tile = mainThread.gridMap.tiles[p]; + boolean freespot = true; + + for(int k = 0; k < 5; k++){ + if(tile[k] != null){ + freespot = false; + break; + } + } + + if(freespot){ + myMiningPosition = p; + int xPosition = myMiningPosition%128; + int yPosition = 127 - myMiningPosition/128; + this.destinationX = xPosition*0.25f +0.125f; + this.destinationY = yPosition*0.25f +0.125f; + foundFreeSpot = true; + break; + } + } + + if(!foundFreeSpot) + waitingCount = 15; + + break; + }else{ + waitingCount = 15; + } + } + } + + } + } + + if(d < 2){ + if(jobStatus == returningToRefinery){ + if(myRefinery == null || myRefinery.currentHP <=0 || myRefinery.isBusy || myRefinery.droppingAreaIsFull(this)){ + returnToRefinery(null); + movement.reset(); + } + } + } + } + + + + if(waitingCount == 0){ + if(jobStatus == leavingRefinery){ + if(centre.z != insideRefineryPositionY - 0.25f){ + if(centre.z - (insideRefineryPositionY - 0.25f) < speed) + movement.set(0,0, (insideRefineryPositionY - 0.25f) - centre.z); + else + movement.set(0,0,-speed); + + xPos_old = boundary2D.x1; + yPos_old = boundary2D.y1; + xPos = (int)((centre.x + movement.x)*64) - 8; + yPos = (int)((centre.z + movement.z)*64) + 8; + boundary2D.setOrigin(xPos, yPos); + + boolean canMove = true; + for(int i = 0; i < 4; i++){ + solidObject o = mainThread.gridMap.tiles[myRefinery.tileIndex[5]+128][i]; + if(o != null && o != this){ + if(o.boundary2D.intersect(boundary2D)){ + canMove = false; + if(o.teamNo != teamNo) //deactivate enemy unit's cloak ability on collision + o.cloakCooldownCount = 60; + break; + } + } + } + + if(!canMove){ + movement.reset(); + } + + boundary2D.x1 = xPos_old; + boundary2D.y1 = yPos_old; + + }else{ + jobStatus = headingToMine; + myRefinery.isBusy = false; + insideRefinery = false; + harvest(myGoldMine); + } + if(myRefinery.currentHP <= 0) + harvest(myGoldMine); + }else if(jobStatus == facingDownward){ + if(bodyAngle != 180){ + int bodyAngleDelta = 360 - (geometry.findAngleDelta(bodyAngle, 180, bodyTurnRate) + 360)%360; + bodyAngle= (bodyAngle - bodyAngleDelta + 360)%360; + }else{ + if(myRefinery.hasExit()) + jobStatus = leavingRefinery; + else + waitingCount = 15; + } + movement.reset(); + if(myRefinery.currentHP <= 0) + returnToRefinery(null); + }else if(jobStatus == unloadingCargo){ + if(unloadingCount == 0) + unloadingCount = 100; + if(unloadingCount == 50){ + if(teamNo == 0) + mainThread.pc.theBaseInfo.currentCredit +=cargoDeposite; + else + mainThread.ec.theBaseInfo.currentCredit +=cargoDeposite; + cargoDeposite = 0; + progressStatus = 100*cargoDeposite/700; + } + if(unloadingCount == 1){ + jobStatus = facingDownward; + } + movement.reset(); + if(myRefinery.currentHP <= 0) + returnToRefinery(null); + }else if(jobStatus == facingRight){ + if(bodyAngle != 90){ + int bodyAngleDelta = 360 - (geometry.findAngleDelta(bodyAngle, 90, bodyTurnRate) + 360)%360; + bodyAngle= (bodyAngle - bodyAngleDelta + 360)%360; + }else{ + + jobStatus = unloadingCargo; + + } + movement.reset(); + if(myRefinery.currentHP <= 0) + returnToRefinery(null); + }else if(jobStatus == enteringRefinery){ + if(centre.z != insideRefineryPositionY){ + if(insideRefineryPositionY - centre.z < speed) + movement.set(0,0,insideRefineryPositionY - centre.z); + else + movement.set(0,0,speed); + }else{ + jobStatus = facingRight; + movement.reset(); + } + if(myRefinery.currentHP <= 0) + returnToRefinery(null); + }else if(jobStatus == facingGoldMine){ + destinationAngle = geometry.findAngle(centre.x, centre.z, myGoldMine.centre.x, myGoldMine.centre.z); + immediateDestinationAngle = destinationAngle; + if(bodyAngle != immediateDestinationAngle){ + int bodyAngleDelta = 360 - (geometry.findAngleDelta(bodyAngle, immediateDestinationAngle, bodyTurnRate) + 360)%360; + bodyAngle= (bodyAngle - bodyAngleDelta + 360)%360; + }else{ + jobStatus = isDrilling; + drillingCount = 700; + } + movement.reset(); + }else if(jobStatus == facingRefinery){ + + if((bodyAngle%360) != 0){ + int bodyAngleDelta = 360 - (geometry.findAngleDelta(bodyAngle, 0, bodyTurnRate) + 360)%360; + bodyAngle= (bodyAngle - bodyAngleDelta + 360)%360; + }else{ + jobStatus = enteringRefinery; + myRefinery.isBusy = true; + insideRefinery = true; + myRefinery.unloadOreCountDown = 200; + } + movement.reset(); + if(myRefinery.currentHP <= 0) + returnToRefinery(null); + + }else if(jobStatus == isDrilling){ + if(myGoldMine.goldDeposite > 1){ + myGoldMine.goldDeposite-=1; + cargoDeposite+=1; + progressStatus = 100*cargoDeposite/700; + }else if(cargoDeposite >0) + returnToRefinery(null); + + if(drillingCount == 0 || cargoDeposite == 700 || myGoldMine.goldDeposite == 0){ + returnToRefinery(null); + } + movement.reset(); + }else{ + //check if the harvest is at a position that is suitable for mining + if(jobStatus == headingToMine ) { + int nodeX = (int)(centre.x * 64)/16; + int nodeY = 127 - (int)(centre.z * 64)/16; + int modX = (int)(centre.x * 64) % 16; + int modY = (int)(centre.z * 64) % 16; + + if(modX == 8 && modY == 8 && d < 1) { + for(int i =0; i < 8; i++) { + int miningNodeX = miningPositions[i] % 128; + int miningNodeY = miningPositions[i] / 128; + + if(miningNodeX == nodeX && miningNodeY == nodeY) { + int xPosition = miningPositions[i]%128; + int yPosition = 127 - miningPositions[i]/128; + destinationX = xPosition*0.25f +0.125f; + destinationY = yPosition*0.25f +0.125f; + break; + } + + } + } + } + + performPathFindingLogic(); + } + }else{ + movement.reset(); + } + + } + } + + //use a path finder to move to desination + public void performPathFindingLogic(){ + + + if(!pathIsFound && heuristicRecalculationCountDown == 0){ + + + + int destX = (int)(destinationX * 64)/16; + int destY = 127 - (int)(destinationY * 64)/16; + + pathIsFound = PathFinder.createHeuristicMap(heuristicMap,occupiedTile0, occupiedTile1, occupiedTile2, occupiedTile3, destX, destY); + heuristicRecalculationCountDown = 32; + + + + if(pathIsFound){ + + //find the first node in the path + int nextTile0 = findAdjacentTileWithSmallestHeuristic(occupiedTile0); + int nextTile1 = findAdjacentTileWithSmallestHeuristic(occupiedTile1); + int nextTile2 = findAdjacentTileWithSmallestHeuristic(occupiedTile2); + int nextTile3 = findAdjacentTileWithSmallestHeuristic(occupiedTile3); + + if(occupiedTile1 == -1) + nextTile1 = occupiedTile1; + if(occupiedTile2 == -1) + nextTile2 = occupiedTile2; + if(occupiedTile3 == -1) + nextTile3 = occupiedTile3; + + if(nextTile0 != occupiedTile0){ + nextNodeX = 0.125f + (nextTile0%128) * 0.25f; + nextNodeY = 0.125f + (127 - (nextTile0/128)) * 0.25f; + + + }else if(nextTile1 != occupiedTile1){ + nextNodeX = 0.125f + (nextTile1%128) * 0.25f; + nextNodeY = 0.125f + (127 - (nextTile1/128)) * 0.25f; + + }else if(nextTile2 != occupiedTile2){ + nextNodeX = 0.125f + (nextTile2%128) * 0.25f; + nextNodeY = 0.125f + (127 - (nextTile2/128)) * 0.25f; + + }else if(nextTile3 != occupiedTile3){ + nextNodeX = 0.125f + (nextTile3%128) * 0.25f; + nextNodeY = 0.125f + (127 - (nextTile3/128)) * 0.25f; + + } + } + } + + if(pathIsFound){ + + + + movement.reset(); + + //check if the harvester has reached next node in the path + if(centre.x == nextNodeX && centre.z == nextNodeY){ + //check if the harvester has reached the destination + int destX = (int)(destinationX * 64)/16; + int destY = 127 - (int)(destinationY * 64)/16; + int nodeX = (int)(centre.x * 64)/16; + int nodeY = 127 - (int)(centre.z * 64)/16; + if(destX == nodeX && destY == nodeY){ + + + pathIsFound = false; + resetLogicStatus(); + + if(jobStatus == idle) + currentCommand = StandBy; + else{ + if(jobStatus == headingToMine){ + jobStatus = facingGoldMine; + if(myGoldMine.goldDeposite ==0){ + currentCommand = StandBy; + } + } + + if(jobStatus == returningToRefinery){ + jobStatus = facingRefinery; + if(myRefinery.currentHP == 0){ + returnToRefinery(null); + } + } + + } + + return; + }else{ + //if destination hasn't reached, find the next node + int nextTile0 = findAdjacentTileWithSmallestHeuristic(occupiedTile0); + nextNodeX = 0.125f + (nextTile0%128) * 0.25f; + nextNodeY = 0.125f + (127 - (nextTile0/128)) * 0.25f; + + } + } + + + + float distanceToNextNode = (float)Math.sqrt((nextNodeX - centre.x) * (nextNodeX - centre.x) + (nextNodeY - centre.z) * (nextNodeY - centre.z)); + calculateMovement(); + destinationAngle = geometry.findAngle(centre.x, centre.z, nextNodeX, nextNodeY); + immediateDestinationAngle = destinationAngle; + + if(Math.abs(bodyAngle - immediateDestinationAngle) > 45 && Math.abs(bodyAngle - immediateDestinationAngle) < 315){ + + int bodyAngleDelta = 360 - (geometry.findAngleDelta(bodyAngle, immediateDestinationAngle, bodyTurnRate) + 360)%360; + bodyAngle= (bodyAngle - bodyAngleDelta + 360)%360; + movement.reset(); + + }else{ + if(bodyAngle != immediateDestinationAngle){ + int bodyAngleDelta = 360 - (geometry.findAngleDelta(bodyAngle, immediateDestinationAngle, bodyTurnRate) + 360)%360; + bodyAngle= (bodyAngle - bodyAngleDelta + 360)%360; + } + + movement.set(nextNodeX - centre.x, 0, nextNodeY - centre.z); + + if(speed < distanceToNextNode){ + movement.unit(); + movement.scale(speed); + } + + //check collision + xPos_old = boundary2D.x1; + yPos_old = boundary2D.y1; + xPos = (int)((centre.x + movement.x)*64) - 8; + yPos = (int)((centre.z + movement.z)*64) + 8; + boundary2D.setOrigin(xPos, yPos); + + Rect r = checkForCollision(boundary2D); + boundary2D.setOrigin(xPos_old, yPos_old); + + if(r != null){ + movement.reset(); + pathIsFound = false; + if(r.owner.teamNo != teamNo) //deactivate enemy unit's cloak ability on collision + r.owner.cloakCooldownCount = 60; + } + + + } + + return; + } + + + if(!pathIsFound){ + if((movement.x == 0 && movement.z == 0) || mainThread.gridMap.tiles[occupiedTile0][4] != null){ + if((Math.abs(destinationX - centre.x) + Math.abs(destinationY - centre.z) > 0.5) ||(jobStatus == idle)){ + heuristicRecalculationCountDown = 64; + } + } + performMovementLogic(); + avoidGettingStucked(); + + //harvester is always on the move + if(jobStatus != idle){ + currentCommand = move; + } + } + + } + + public int findAdjacentTileWithSmallestHeuristic(int currentTile){ + int smallestHeurstic = 127; + int nextTile = currentTile; + + boolean[] obstacleMap = mainThread.gridMap.previousObstacleMap; + + //check north west tile + int northWestTile = currentTile - 128 - 1; + int northTile = currentTile - 128; + int northEastTile = currentTile - 128 + 1; + int eastTile = currentTile + 1; + int southEastTile = currentTile + 1 + 128; + int southTile = currentTile + 128; + int southWestTile = currentTile + 128 - 1; + int westTile = currentTile - 1; + + if(northWestTile > 0 && northWestTile < 16384 && obstacleMap[northTile] && obstacleMap[westTile]){ + if(heuristicMap[northWestTile] < smallestHeurstic){ + smallestHeurstic = heuristicMap[northWestTile]; + nextTile = northWestTile; + } + } + + //check north tile + + if(northTile > 0 && northTile < 16384){ + if(heuristicMap[northTile] < smallestHeurstic){ + smallestHeurstic = heuristicMap[northTile]; + nextTile = northTile; + } + } + + //check north east tile + if(northEastTile > 0 && northEastTile < 16384 && obstacleMap[northTile] && obstacleMap[eastTile]){ + if(heuristicMap[northEastTile] < smallestHeurstic){ + smallestHeurstic = heuristicMap[northEastTile]; + nextTile = northEastTile; + } + } + + //check east tile + + if(eastTile > 0 && eastTile < 16384){ + if(heuristicMap[eastTile] < smallestHeurstic){ + smallestHeurstic = heuristicMap[eastTile]; + nextTile = eastTile; + } + } + + //check south east tile + + if(southEastTile > 0 && southEastTile < 16384 && obstacleMap[southTile] && obstacleMap[eastTile]){ + if(heuristicMap[southEastTile] < smallestHeurstic){ + smallestHeurstic = heuristicMap[southEastTile]; + nextTile = southEastTile; + } + } + + //check south tile + + if(southTile > 0 && southTile < 16384){ + if(heuristicMap[southTile] < smallestHeurstic){ + smallestHeurstic = heuristicMap[southTile]; + nextTile = southTile; + } + } + + //check south west tile + + if(southWestTile > 0 && southWestTile < 16384 && obstacleMap[southTile] && obstacleMap[westTile]){ + if(heuristicMap[southWestTile] < smallestHeurstic){ + smallestHeurstic = heuristicMap[southWestTile]; + nextTile = southWestTile; + } + } + + //check west tile + if(westTile > 0 && westTile < 16384){ + if(heuristicMap[westTile] < smallestHeurstic){ + smallestHeurstic = heuristicMap[westTile]; + nextTile = westTile; + } + } + + return nextTile; + } + + //move to a destination position, ignore any hostile units it encounters + public void performMovementLogic(){ + + //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; + } + + if(Math.abs(bodyAngle - immediateDestinationAngle) > 45 && Math.abs(bodyAngle - immediateDestinationAngle) < 315){ + + int bodyAngleDelta = 360 - (geometry.findAngleDelta(bodyAngle, immediateDestinationAngle, bodyTurnRate) + 360)%360; + bodyAngle= (bodyAngle - bodyAngleDelta + 360)%360; + movement.reset(); + + }else{ + if(bodyAngle != immediateDestinationAngle){ + int bodyAngleDelta = 360 - (geometry.findAngleDelta(bodyAngle, immediateDestinationAngle, bodyTurnRate) + 360)%360; + bodyAngle= (bodyAngle - bodyAngleDelta + 360)%360; + } + + 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 avoidGettingStucked(){ + //if the object can't move for some period then recalculate the path + if(movement.x == 0 && movement.z == 0){ + stuckCount++; + } + + + if(obstacle != null){ + if((unStableObstacle != null || !isStable(obstacle.owner)) && (ID + randomNumber + mainThread.frameIndex)%128 ==0){ + + newDestinationisGiven = true; + currentMovementStatus = freeToMove; + hugWallCoolDown = 0; + stuckCount = 0; + randomNumber = gameData.getRandom(); + } + } + + + + if(stuckCount > 128){ + newDestinationisGiven = true; + stuckCount = 0; + currentMovementStatus = freeToMove; + hugWallCoolDown = 0; + + } + } + + public void draw(){ + if(!visible) + return; + + for(int i = 0; i < bodyClone.length; i++){ + bodyClone[i].update(); + bodyClone[i].draw(); + } + + polygon3D[] drillClone; + drillClone = null; + if(drillIndex == 0){ + drillClone = drillClone0; + } + if(drillIndex == 1){ + drillClone = drillClone1; + } + if(drillIndex == 2){ + drillClone = drillClone2; + } + + for(int i = 0; i < drillClone.length; i++){ + drillClone[i].update(); + drillClone[i].draw(); + } + + for(int i = 0; i < cargoClone.length; i++){ + cargoClone[i].update(); + cargoClone[i].draw(); + } + + if(unloadingCount > 0){ + for(int i = 0; i < pillarsClone.length; i++){ + pillarsClone[i].update(); + pillarsClone[i].draw(); + } + } + + } + + public vector getMovement(){ + return movement; + } + + + public void updateGeometry(){ + centre.y-=0.18f; + + for(int i = 0; i < bodyClone.length; i++){ + bodyClone[i].origin.set(body[i].origin); + + bodyClone[i].origin.rotate_XZ(360 - bodyAngle); + bodyClone[i].origin.add(centre); + + + + bodyClone[i].bottomEnd.set(body[i].bottomEnd); + + bodyClone[i].bottomEnd.rotate_XZ(360 - bodyAngle); + bodyClone[i].bottomEnd.add(centre); + + + + bodyClone[i].rightEnd.set(body[i].rightEnd); + bodyClone[i].rightEnd.rotate_XZ( 360 - bodyAngle); + bodyClone[i].rightEnd.add(centre); + + + + + for(int j = 0; j < bodyClone[i].vertex3D.length; j++){ + bodyClone[i].vertex3D[j].set(body[i].vertex3D[j]); + bodyClone[i].vertex3D[j].rotate_XZ(360 -bodyAngle); + bodyClone[i].vertex3D[j].add(centre); + + + bodyClone[i].normal.set(body[i].normal); + bodyClone[i].normal.rotate_XZ(360 -bodyAngle); + bodyClone[i].findDiffuse(); + } + } + + polygon3D[] drill, drillClone; + drill = null; + drillClone = null; + if(drillIndex == 0){ + drill = drill0; + drillClone = drillClone0; + } + if(drillIndex == 1){ + drill = drill1; + drillClone = drillClone1; + } + if(drillIndex == 2){ + drill = drill2; + drillClone = drillClone2; + } + + for(int i = 0; i < drillClone.length; i++){ + drillClone[i].origin.set(drill[i].origin); + drillClone[i].origin.rotate_XZ(360 - bodyAngle); + drillClone[i].origin.add(centre); + + + + drillClone[i].bottomEnd.set(drill[i].bottomEnd); + + drillClone[i].bottomEnd.rotate_XZ(360 - bodyAngle); + drillClone[i].bottomEnd.add(centre); + + + + drillClone[i].rightEnd.set(drill[i].rightEnd); + drillClone[i].rightEnd.rotate_XZ( 360 - bodyAngle); + drillClone[i].rightEnd.add(centre); + + + + + for(int j = 0; j < drillClone[i].vertex3D.length; j++){ + drillClone[i].vertex3D[j].set(drill[i].vertex3D[j]); + drillClone[i].vertex3D[j].rotate_XZ(360 -bodyAngle); + drillClone[i].vertex3D[j].add(centre); + + drillClone[i].normal.set(drill[i].normal); + drillClone[i].normal.rotate_XZ(360 -bodyAngle); + drillClone[i].findDiffuse(); + } + } + + + //update cargo center + cargoCenterClone.set(cargoCenter); + cargoCenterClone.rotate_XZ(360 -bodyAngle); + cargoCenterClone.add(centre); + + + for(int i = 0; i < cargoClone.length; i++){ + cargoClone[i].origin.set(cargo[i].origin); + cargoClone[i].origin.rotate_YZ(cargoAngle); + cargoClone[i].origin.rotate_XZ(360 - bodyAngle); + cargoClone[i].origin.add(cargoCenterClone); + + cargoClone[i].bottomEnd.set(cargo[i].bottomEnd); + cargoClone[i].bottomEnd.rotate_YZ(cargoAngle); + cargoClone[i].bottomEnd.rotate_XZ(360 - bodyAngle); + cargoClone[i].bottomEnd.add(cargoCenterClone); + + + + cargoClone[i].rightEnd.set(cargo[i].rightEnd); + cargoClone[i].rightEnd.rotate_YZ(cargoAngle); + cargoClone[i].rightEnd.rotate_XZ( 360 - bodyAngle); + cargoClone[i].rightEnd.add(cargoCenterClone); + + + + + for(int j = 0; j < cargoClone[i].vertex3D.length; j++){ + cargoClone[i].vertex3D[j].set(cargo[i].vertex3D[j]); + cargoClone[i].vertex3D[j].rotate_YZ(cargoAngle); + cargoClone[i].vertex3D[j].rotate_XZ(360 -bodyAngle); + cargoClone[i].vertex3D[j].add(cargoCenterClone); + + + cargoClone[i].normal.set(cargo[i].normal); + cargoClone[i].normal.rotate_YZ(cargoAngle); + cargoClone[i].normal.rotate_XZ(360 -bodyAngle); + cargoClone[i].findDiffuse(); + } + } + + if(unloadingCount > 0){ + //update pillars + pillarCenterClone.set(pillarCenter); + pillarCenterClone.rotate_XZ(360 -bodyAngle); + pillarCenterClone.add(centre); + pillarAngle = (360- cargoAngle)/5*4; + + + for(int i = 0; i < pillarsClone.length; i++){ + pillarsClone[i].origin.set(pillars[i].origin); + pillarsClone[i].origin.rotate_YZ(pillarAngle); + pillarsClone[i].origin.rotate_XZ(360 - bodyAngle); + pillarsClone[i].origin.add(pillarCenterClone); + + + + pillarsClone[i].bottomEnd.set(pillars[i].bottomEnd); + pillarsClone[i].bottomEnd.rotate_YZ(pillarAngle); + pillarsClone[i].bottomEnd.rotate_XZ(360 - bodyAngle); + pillarsClone[i].bottomEnd.add(pillarCenterClone); + + + + pillarsClone[i].rightEnd.set(pillars[i].rightEnd); + pillarsClone[i].rightEnd.rotate_YZ(pillarAngle); + pillarsClone[i].rightEnd.rotate_XZ( 360 - bodyAngle); + pillarsClone[i].rightEnd.add(pillarCenterClone); + + + + + for(int j = 0; j < pillarsClone[i].vertex3D.length; j++){ + pillarsClone[i].vertex3D[j].set(pillars[i].vertex3D[j]); + pillarsClone[i].vertex3D[j].rotate_YZ(pillarAngle); + pillarsClone[i].vertex3D[j].rotate_XZ(360 -bodyAngle); + pillarsClone[i].vertex3D[j].add(pillarCenterClone); + + + pillarsClone[i].normal.set(pillars[i].normal); + pillarsClone[i].normal.rotate_YZ(pillarAngle); + pillarsClone[i].normal.rotate_XZ(360 -bodyAngle); + pillarsClone[i].findDiffuse(); + } + } + } + + centre.y+=0.18f; + } + + public void resetLogicStatus(){ + movement.reset(); + currentMovementStatus = freeToMove; + stuckCount = 0; + destinationX = centre.x; + destinationY = centre.z; + insideDeistinationRadiusCount = 0; + obstacle = null; + drillingCount = 0; + closeToDestination = false; + + } + + public void moveTo(float destinationX, float destinationY){ + if(myRefinery != null){ + if(myRefinery.currentHP >0){ + if(jobStatus >3 ) + return; + } + } + + + resetLogicStatus(); + pathIsFound = false; + this.destinationX = destinationX; + this.destinationY = destinationY; + newDestinationisGiven = true; + heuristicRecalculationCountDown = 0; + jobStatus = idle; + + } + + + public void harvest(solidObject o){ + + + if(drillingCount > 0 && o == myGoldMine) + return; + + if(cargoDeposite == 700){ + return; + } + + if(jobStatus > 3){ + return; + } + + myGoldMine = (goldMine)o; + + if(myGoldMine.goldDeposite == 0){ + myGoldMine = null; + return; + } + + resetLogicStatus(); + pathIsFound = false; + newDestinationisGiven = true; + heuristicRecalculationCountDown = 0; + currentCommand = move; + jobStatus = headingToMine; + + + //set destination to one of the 8 adjacent tiles around the gold mine + int goldMineTile = myGoldMine.tileIndex[0]; + miningPositions[0] = goldMineTile - 128; + miningPositions[1] = goldMineTile - 127; + miningPositions[2] = goldMineTile + 2; + miningPositions[3] = goldMineTile + 130; + miningPositions[4] = goldMineTile + 257; + miningPositions[5] = goldMineTile + 256; + miningPositions[6] = goldMineTile + 127; + miningPositions[7] = goldMineTile -1; + + myMiningPosition = miningPositions[(int)((Math.random()*8))]; + int xPosition = myMiningPosition%128; + int yPosition = 127 - myMiningPosition/128; + this.destinationX = xPosition*0.25f +0.125f; + this.destinationY = yPosition*0.25f +0.125f; + } + + + public void returnToRefinery(solidObject o){ + if(jobStatus == enteringRefinery || jobStatus == leavingRefinery || jobStatus == unloadingCargo || jobStatus == facingRight || jobStatus == facingDownward) + return; + + if(cargoDeposite == 0){ + if(myGoldMine != null){ + harvest(myGoldMine); + } + return; + } + + if(o == null){ + //find a nearest refinary + myRefinery = findNearestRefinery(); + + }else{ + myRefinery = (refinery)o; + if(myRefinery.currentHP <=0){ + //find a nearest refinary + myRefinery = findNearestRefinery(); + } + } + + if(myRefinery != null){ + resetLogicStatus(); + pathIsFound = false; + newDestinationisGiven = true; + heuristicRecalculationCountDown = 0; + currentCommand = move; + jobStatus = returningToRefinery; + + myDropPosition = myRefinery.tileIndex[5] + 128; + int xPosition = myDropPosition%128; + int yPosition = 127 - myDropPosition/128; + this.destinationX = xPosition*0.25f +0.125f; + this.destinationY = yPosition*0.25f +0.125f; + + int insdieRefinery = myRefinery.tileIndex[5]; + xPosition = insdieRefinery%128; + yPosition = 127 - insdieRefinery/128; + + insideRefineryPositionX = xPosition*0.25f +0.125f;; + insideRefineryPositionY = yPosition*0.25f +0.125f; + + }else{ + currentCommand = StandBy; + } + } + + public refinery findNearestRefinery(){ + refinery[] refineries = (refinery[])mainThread.theAssetManager.refineries; + + for(int i = 1; i < refineries.length; i++){ + for(int j = 0; j d2){ + refinery temp = refineries[j+1]; + refineries[j+1] = refineries[j]; + refineries[j] = temp; + } + } + } + } + + refinery nearestBusyRefinery = null; + for(int i = 0; i < refineries.length; i++){ + if(refineries[i] != null){ + if(!refineries[i].isBusy && !refineries[i].droppingAreaIsFull(this) && refineries[i].currentHP >0 && (refineries[i].teamNo == teamNo)){ + if(checkDistance(refineries[i]) > 4){ + if(nearestBusyRefinery == null) + return refineries[i]; + }else{ + return refineries[i]; + } + } + if(nearestBusyRefinery == null && (refineries[i].isBusy || refineries[i].droppingAreaIsFull(this)) && refineries[i].currentHP >0 && (refineries[i].teamNo == teamNo)){ + nearestBusyRefinery = refineries[i]; + } + } + + } + + if(nearestBusyRefinery != null){ + waitingCount = 15; + return nearestBusyRefinery; + } + + return null; + } + + public void goToTheNearestGoldMine(){ + int goldMineIndex = -1; + double distance = 10; + for(int i = 0; i < mainThread.theAssetManager.goldMines.length; i++){ + if(mainThread.theAssetManager.goldMines[i] == null) + continue; + + double newDistance = getDistance(mainThread.theAssetManager.goldMines[i]); + if(newDistance < distance && mainThread.theAssetManager.goldMines[i].goldDeposite > 1){ + distance = newDistance; + goldMineIndex = i; + } + } + + if(goldMineIndex != -1){ + myGoldMine = mainThread.theAssetManager.goldMines[goldMineIndex]; + //waitingCount = 15; + returnToRefinery(null); + } + } + + public float checkDistance(solidObject o){ + return Math.abs(o.centre.x - centre.x) + Math.abs(o.centre.z - centre.z); + } + + public void hold(){ + if(jobStatus < 4) + currentCommand = StandBy; + } + + public int getMaxHp(){return maxHP;} + +} diff --git a/entity/heavyTank.java b/entity/heavyTank.java new file mode 100644 index 0000000..3256d49 --- /dev/null +++ b/entity/heavyTank.java @@ -0,0 +1,1138 @@ +package entity; + +import java.awt.Rectangle; + +import core.*; +import enemyAI.enemyCommander; + +//light tank 3D model + +public class heavyTank extends solidObject{ + + + public vector bodyCenter, turretCenter; + + public polygon3D[] body, turret; + + public static int maxHP = 320; + + //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,908, 597); + + //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,688, 432); + + //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, 800); + + //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 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 = 4; + public int turretTurnRate = 6; + public int myAttackCooldown= 45; + + //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 boolean canSelfRepair; + + + public heavyTank(vector origin, int bodyAngle, int teamNo){ + speed = 0.0085f; + attackRange = 1.7f; + groupAttackRange = 1.1f; + 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 = 7; + myDamage = 15; + if(bitmapVisionForEnemy == null){ + bitmapVisionForEnemy = createBitmapVision(6); + bitmapVisionGainFromAttackingUnit = createBitmapVision(2); + } + + + 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 polygons + makePolygons(); + + movement_offscreen = new vector(0,0,0); + + if(tileCheckList == null){ + tileCheckList = generateTileCheckList(6f); + } + + } + + public void makePolygons(){ + + bodyCenter.y-=0.18f; + start.set(bodyCenter); + + int skinTextureIndex = 71; + if(teamNo != 0) + skinTextureIndex = 10; + + + iDirection = new vector(0.85f,0,0); + jDirection = new vector(0,0.85f,0); + kDirection = new vector(0,0,0.92f); + iDirection.rotate_XZ(360-bodyAngle); + kDirection.rotate_XZ(360-bodyAngle); + + + body = new polygon3D[19]; + v = new vector[]{put(0.1, 0, 0.15), put(0.06, 0, 0.15), put(0.06, -0.04, 0.14), put(0.1, -0.04, 0.14)}; + body[0] = new polygon3D(v,v[0], v[1], v[3], mainThread.textures[3], 1,0.5f,1); + + v = new vector[]{put(-0.1, -0.04, 0.14), put(-0.06, -0.04, 0.14), put(-0.06, 0, 0.15), put(-0.1, 0, 0.15)}; + body[1] = new polygon3D(v,v[0], v[1], v[3], mainThread.textures[3], 1,0.5f,1); + + v = new vector[]{put(0.06, 0, -0.14), put(0.1, 0, -0.14), put(0.1, -0.04, -0.12), put(0.06, -0.04, -0.12)}; + body[2] = new polygon3D(v,v[0], v[1], v[3], mainThread.textures[3], 1,0.5f,1); + + v = new vector[]{ put(-0.06, -0.04, -0.12), put(-0.1, -0.04, -0.12), put(-0.1, 0, -0.14),put(-0.06, 0, -0.14)}; + body[3] = new polygon3D(v,v[0], v[1], v[3], mainThread.textures[3], 1,0.5f,1); + + int i = 4; + + v = new vector[]{put(0.06, 0.06, 0.13), put(0.06, 0.06, 0.08), put(0.06, -0.01, 0.08), put(0.06, -0.01, 0.15)}; + body[0+i] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 0.8f,1.1f,1); + + v = new vector[]{put(-0.06, -0.01, 0.15), put(-0.06, -0.01, 0.08), put(-0.06, 0.06, 0.08), put(-0.06, 0.06, 0.13)}; + body[1+i] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 0.8f,1.1f,1); + + v = new vector[]{put(-0.06, 0.06, 0.09), put(0.06, 0.06, 0.09), put(0.06, 0.06, -0.13), put(-0.06, 0.06, -0.13)}; + body[2+i] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 0.8f,1.1f,1); + + v = new vector[]{put(0.06, 0.06, 0.09), put(-0.06, 0.06, 0.09), put(-0.06, 0, 0.15), put(0.06, 0, 0.15)}; + body[3+i] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 0.8f,0.4f,1); + + v = new vector[]{put(-0.1, 0.06, -0.13), put(0.1, 0.06, -0.13), put(0.1, 0, -0.14), put(-0.1, 0, -0.14)}; + body[4+i] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 0.8f,0.3f,1); + + v = new vector[]{put(0.06, 0.06, 0.13), put(0.1, 0.06, 0.13), put(0.1, 0.06, -0.13), put(0.06, 0.06, -0.13)}; + body[5+i] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 0.3f,0.8f,1); + + v = new vector[]{put(-0.06, 0.06, -0.13), put(-0.1, 0.06, -0.13), put(-0.1, 0.06, 0.13), put(-0.06, 0.06, 0.13)}; + body[6+i] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 0.3f,0.8f,1); + + v = new vector[]{put(0.1, 0.06, 0.13), put(0.06, 0.06, 0.13), put(0.06, 0., 0.15), put(0.1, 0., 0.15)}; + body[7+i] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 0.8f,1.1f,1); + + v = new vector[]{put(-0.1, 0., 0.15), put(-0.06, 0., 0.15), put(-0.06, 0.06, 0.13),put(-0.1, 0.06, 0.13)}; + body[8+i] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 0.8f,1.1f,1); + + v = new vector[]{put(0.1, 0.06, -0.13), put(0.1, 0.06, 0.13), put(0.1, 0, 0.15), put(0.1, 0, -0.14)}; + body[9+i] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 0.8f,0.2f,1); + + v = new vector[]{put(-0.1, 0, -0.14), put(-0.1, 0, 0.15), put(-0.1, 0.06, 0.13), put(-0.1, 0.06, -0.13)}; + body[10+i] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 0.8f,0.2f,1); + + v = new vector[]{put(0.1, 0, 0.01), put(0.1, 0, 0.15), put(0.1, -0.04, 0.14), put(0.1, -0.04, 0.03)}; + body[11+i] = new polygon3D(v, put(0.1, 0.1, 0.03), put(0.1, 0.1, 0.13), put(0.1, -0.04, 0.03), mainThread.textures[3], 1,0.5f,1); + + v = new vector[]{put(0.1, 0, -0.14), put(0.1, 0, -0.01), put(0.1, -0.04, -0.03), put(0.1, -0.04, -0.12)}; + body[12+i] = new polygon3D(v, put(0.1, 0.1, -0.15), put(0.1, 0.1, -0.01), put(0.1, -0.04, -0.15), mainThread.textures[3], 1,0.5f,1); + + v = new vector[]{put(-0.1, -0.04, 0.03), put(-0.1, -0.04, 0.14), put(-0.1, 0, 0.15), put(-0.1, 0, 0.01)}; + body[13+i] = new polygon3D(v, put(-0.1, 0.1, 0.03), put(-0.1, 0.1, 0.13), put(-0.1, -0.04, 0.03), mainThread.textures[3], 1,0.5f,1); + + v = new vector[]{put(-0.1, -0.04, -0.12), put(-0.1, -0.04, -0.03), put(-0.1, 0, -0.01), put(-0.1, 0, -0.14)}; + body[14+i] = new polygon3D(v, put(-0.1, 0.1, -0.15), put(-0.1, 0.1, -0.01), put(-0.1, -0.04, -0.15), mainThread.textures[3], 1,0.5f,1); + + + + for(i = 0; i < body.length; i++){ + + body[i].parentObject = this; + + } + + + turretCenter = put(0, 0.065, -0.0); + start.set(turretCenter); + + iDirection = new vector(1.1f,0,0); + jDirection = new vector(0,1.1f,0); + kDirection = new vector(0,0,1.05f); + + iDirection.rotate_XZ(360-turretAngle); + kDirection.rotate_XZ(360-turretAngle); + + + + turret = new polygon3D[41 + 18 + 18]; + + iDirection.scale(0.9f); + kDirection.scale(0.9f); + + float f = 0.01f; + vector [] v1 = new vector[]{ + put(-0.04, 0.036, 0.06 -f), put(0.04, 0.036, 0.06 -f), put(0.05, 0.036, 0.04-f), put(0.05, 0.036, -0.03-f), put(0.03, 0.036, -0.07-f), put(-0.03, 0.036, -0.07-f),put(-0.05, 0.036, -0.03-f), put(-0.05, 0.036, 0.04-f) + }; + + + v = new vector[]{ + v1[0].myClone(), + v1[1].myClone(), + v1[2].myClone(), + v1[3].myClone(), + v1[4].myClone(), + v1[5].myClone(), + v1[6].myClone(), + v1[7].myClone() + }; + + turret[0] = new polygon3D(v, put(-0.04, 0.04, 0.19-f), put(0.04, 0.04, 0.19-f), put(-0.04, 0.04, 0.09-f), mainThread.textures[skinTextureIndex], 0.6f,0.6f,1); + + + iDirection.scale(1f/0.75f); + kDirection.scale(1f/0.8f); + + vector [] v2 = new vector[]{ + put(-0.04, 0, 0.06-f), put(0.04, 0, 0.06-f), put(0.05, 0, 0.04-f), put(0.05, 0, -0.03-f), put(0.03, 0, -0.07-f), put(-0.03, 0, -0.07-f),put(-0.05, 0, -0.03-f), put(-0.05, 0, 0.04-f) + }; + + for(i = 0; i < 8; i++){ + + v = new vector[]{v1[i].myClone(),v1[(i+7)%8].myClone(), v2[(i+7)%8].myClone(), v2[i].myClone()}; + turret[1 + i] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[skinTextureIndex], 0.3f,0.3f,1); + } + + + + double r1 = 0.0055; + double r2 = 0.0075; + double theta = Math.PI/8; + + start.y-=0.08f; + + for(i = 0; i < 16; i++){ + v = new vector[]{put(r2*Math.cos(i*theta) - 0.018f, r2*Math.sin(i*theta)+0.093, 0.03), + put(r2*Math.cos((i+1)*theta) - 0.018f, r2*Math.sin((i+1)*theta)+0.093, 0.03), + put(r1*Math.cos((i+1)*theta)- 0.018f, r1*Math.sin((i+1)*theta)+0.093, 0.15), + put(r1*Math.cos(i*theta) - 0.018f, r1*Math.sin(i*theta)+0.093, 0.15) + }; + turret[9 +i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[72], 10,10,1); + turret[9 +i].Ambient_I -=15; + turret[9 +i].reflectance -=30; + turret[9 +i].findDiffuse(); + } + + + + for(i = 0; i < 16; i++){ + v = new vector[]{put(r2*Math.cos(i*theta) + 0.018f, r2*Math.sin(i*theta)+0.093, 0.03), + put(r2*Math.cos((i+1)*theta) + 0.018f, r2*Math.sin((i+1)*theta)+0.093, 0.03), + put(r1*Math.cos((i+1)*theta)+ 0.018f, r1*Math.sin((i+1)*theta)+0.093, 0.15), + put(r1*Math.cos(i*theta) + 0.018f, r1*Math.sin(i*theta)+0.093, 0.15) + }; + turret[25 +i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[72], 10,10,1); + turret[25 +i].Ambient_I -=15; + turret[25 +i].reflectance -=30; + turret[25 +i].findDiffuse(); + } + + + + + double r3 = 0.009; + for(i = 0; i < 16; i++){ + v = new vector[]{put(r3*Math.cos(i*theta) + 0.018f, r3*Math.sin(i*theta)+0.093, 0.08), + put(r3*Math.cos((i+1)*theta) + 0.018f, r3*Math.sin((i+1)*theta)+0.093, 0.08), + put(r3*Math.cos((i+1)*theta)+ 0.018f, r3*Math.sin((i+1)*theta)+0.093, 0.1), + put(r3*Math.cos(i*theta) + 0.018f, r3*Math.sin(i*theta)+0.093, 0.1) + }; + turret[41 +i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10,10,1); + turret[41 +i].Ambient_I -=15; + turret[41 +i].reflectance -=30; + turret[41 +i].findDiffuse(); + + } + + v = new vector[16]; + for(i = 0; i < 16; i ++){ + v[i] = put(r3*Math.cos((i+1)*theta)+ 0.018f, r3*Math.sin((i+1)*theta)+0.093, 0.1); + } + turret[57] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10,10,1); + + v = new vector[16]; + for(i = 0; i < 16; i ++){ + v[15 - i] = put(r3*Math.cos((i+1)*theta) + 0.018f, r3*Math.sin((i+1)*theta)+0.093, 0.08); + } + turret[58] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10,10,1); + + + for(i = 0; i < 16; i++){ + v = new vector[]{put(r3*Math.cos(i*theta) - 0.018f, r3*Math.sin(i*theta)+0.093, 0.08), + put(r3*Math.cos((i+1)*theta) - 0.018f, r3*Math.sin((i+1)*theta)+0.093, 0.08), + put(r3*Math.cos((i+1)*theta)- 0.018f, r3*Math.sin((i+1)*theta)+0.093, 0.1), + put(r3*Math.cos(i*theta) - 0.018f, r3*Math.sin(i*theta)+0.093, 0.1) + }; + turret[59 +i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10,10,1); + turret[59 +i].Ambient_I -=15; + turret[59 +i].reflectance -=30; + turret[59 +i].findDiffuse(); + + } + + v = new vector[16]; + for(i = 0; i < 16; i ++){ + v[i] = put(r3*Math.cos((i+1)*theta)- 0.018f, r3*Math.sin((i+1)*theta)+0.093, 0.1); + } + turret[75] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10,10,1); + + v = new vector[16]; + for(i = 0; i < 16; i ++){ + v[15 - i] = put(r3*Math.cos((i+1)*theta) - 0.018f, r3*Math.sin((i+1)*theta)+0.093, 0.08); + } + turret[76] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10,10,1); + + + for(i = 0; i < turret.length; i++){ + + turret[i].parentObject = this; + } + + + } + + + //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+=50; + return; + } + + if(experience >= 80){ + myDamage = 25; + level = 1; + if(experience >= 160){ + level = 2; + myDamage = 40; + if(currentHP < maxHP && mainThread.frameIndex%8==0) + currentHP++; + } + } + + if(canSelfRepair && currentHP < maxHP && mainThread.frameIndex%6==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, 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 - 650); + 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 <= 160 && (mainThread.frameIndex + 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); + + //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(); + performStandByLogic(); + + }else if(currentCommand == move){ + performMovementLogic(); + avoidGettingStucked(); + + }else if(currentCommand == attackInNumbers || currentCommand == attackCautiously){ + performAttackLogic(); + avoidGettingStucked(); + + }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 + if((ID + mainThread.frameIndex)%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; + } + } + } + } + } + } + } + + + //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) + fireBullet(attackAngle); + }else{ + fireBullet(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){ + if((tile[j].centre.x - centre.x)*(tile[j].centre.x - centre.x) + (tile[j].centre.z - centre.z)*(tile[j].centre.z - centre.z) <= attackRange*attackRange){ + 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(); + } + + + //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(); + + } + } + } + } + + + public void fireBullet(int attackAngle){ + + int theDamage = myDamage; + + if(attackCoolDown == 0 && targetObject.currentHP >0 && hasLineOfSightToTarget){ + //if there is nothing between the tank and its target + + + + if(targetObject.type == 6) + theDamage = 20; + + firingPosition.set(0.022f, -0.4f, 0.2f); + firingPosition.rotate_XZ(360 - attackAngle); + firingPosition.add(centre.x, 0, centre.z); + theAssetManager.spawnBullet(attackAngle, theDamage, targetObject, firingPosition, this); + attackCoolDown = myAttackCooldown; + + //spawn a mini explosion + float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount]; + tempFloat[0] = firingPosition.x; + tempFloat[1] = firingPosition.y; + tempFloat[2] = firingPosition.z; + tempFloat[3] = 0.4f; + tempFloat[4] = 3; + tempFloat[5] = 0; + tempFloat[6] = 6 + (gameData.getRandom()%4); + tempFloat[7] = centre.y; + theAssetManager.explosionCount++; + } + + if(attackCoolDown == myAttackCooldown - 8 && targetObject.currentHP >0 && hasLineOfSightToTarget){ + + if(targetObject.type == 6) + theDamage = 20; + + firingPosition.set(-0.022f, -0.4f, 0.2f); + firingPosition.rotate_XZ(360 - attackAngle); + firingPosition.add(centre.x, 0, centre.z); + theAssetManager.spawnBullet(attackAngle, theDamage, targetObject, firingPosition, this); + + //spawn a mini explosion + float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount]; + tempFloat[0] = firingPosition.x; + tempFloat[1] = firingPosition.y; + tempFloat[2] = firingPosition.z; + tempFloat[3] = 0.4f; + tempFloat[4] = 3; + 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;} + +} diff --git a/entity/lightPole.java b/entity/lightPole.java new file mode 100644 index 0000000..b50fa64 --- /dev/null +++ b/entity/lightPole.java @@ -0,0 +1,307 @@ +package entity; + +import java.awt.Rectangle; + +import core.*; + +//palmTree model +public class lightPole extends solidObject{ + //the polygons of the model + public polygon3D[] polygons; + + public int angle; + + public int tileIndex; + + public vector shadowvertex0, tempshadowvertex0,shadowvertex1, tempshadowvertex1,shadowvertex2, tempshadowvertex2,shadowvertex3, tempshadowvertex3; + + //a screen space boundary which is used to test if the object is visible from camera point of view + public final static Rectangle visibleBoundary = new Rectangle(-50,-50,868, 612); + + //a screen space boundary which is used to test if the entire object is within the screen + public final static Rectangle screenBoundary = new Rectangle(40,40,688, 432); + + //screen space boundary which is used to test if the shadow of the object is within the screen + public final static Rectangle shadowBoundary1 = new Rectangle(0,0,768, 512); + + //lightPole never moves + public final static vector movenment = new vector(0,0,0); + + public boolean vanished; + + + + public lightPole(float x, float y, float z, int angle){ + //uncontrollable unit, but act as a small sized static collidable agent + ID = -1; + type = 100; + + this.angle = angle; + + boundary2D = new Rect((int)(x*64), (int)(z*64), 1, 1); + + tileIndex = boundary2D.x1/16 + (127 - (boundary2D.y1)/16)*128; + if(tileIndex >= 0 && tileIndex < 128*128) + mainThread.gridMap.tiles[tileIndex][4] = this; + else + tileIndex = 0; + + start = new vector(x,y,z); + centre = start.myClone(); + tempCentre = start.myClone(); + + shadowvertex0 =start.myClone(); + shadowvertex0.add(-0.35f,-0.2f, -0.35f); + tempshadowvertex0 = new vector(0,0,0); + + shadowvertex1 =start.myClone(); + shadowvertex1.add(-0.35f,-0.2f, 0); + tempshadowvertex1 = new vector(0,0,0); + + shadowvertex2 =start.myClone(); + shadowvertex2.add(0,-0.2f, -0.35f); + tempshadowvertex2 = new vector(0,0,0); + + shadowvertex3 =start.myClone(); + shadowvertex3.add(0,-0.2f, 0f); + tempshadowvertex3 = new vector(0,0,0); + + //create main axis in object space + iDirection = new vector(1f,0,0); + jDirection = new vector(0,1f,0); + kDirection = new vector(0,0,1f); + + boundary2D.owner = this; + currentCommand = StandBy; + + makePolygons(); + } + + + + //Construct polygons for this model. + //The polygon data is hard-coded here + private void makePolygons(){ + + polygons = new polygon3D[57]; + vector[] v; + + //power tower A + float r = 0.008f; + float r1 = 0.006f; + float delta = (float)Math.PI/8; + + for(int i = 0; i < 16; i++){ + v = new vector[]{put(r1*Math.cos(i*delta), 0.4, r1*Math.sin(i*delta)), + put(r1*Math.cos((i+1)*delta), 0.4, r1*Math.sin((i+1)*delta)), + put(r*Math.cos((i+1)*delta), 0, r*Math.sin((i+1)*delta)), + put(r*Math.cos(i*delta), 0, r*Math.sin(i*delta)) + }; + polygons[i] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 10f,10f,1); + } + + iDirection.rotate_YZ(30); + jDirection.rotate_YZ(30); + kDirection.rotate_YZ(30); + + start.z-=0.221f; + for(int i = 0; i < 16; i++){ + v = new vector[]{put(r1*Math.cos(i*delta), 0.502, r1*Math.sin(i*delta)), + put(r1*Math.cos((i+1)*delta), 0.502, r1*Math.sin((i+1)*delta)), + put(r1*Math.cos((i+1)*delta), 0.449, r1*Math.sin((i+1)*delta)), + put(r1*Math.cos(i*delta), 0.449, r1*Math.sin(i*delta)) + }; + polygons[i+16] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 10f,10f,1); + } + + + iDirection.rotate_YZ(30); + jDirection.rotate_YZ(30); + kDirection.rotate_YZ(30); + + start.z-=0.14f; + start.y+=0.2f; + float r2 = 0.004f; + for(int i = 0; i < 16; i++){ + v = new vector[]{put(r2*Math.cos(i*delta), 0.55, r2*Math.sin(i*delta)), + put(r2*Math.cos((i+1)*delta), 0.55, r2*Math.sin((i+1)*delta)), + put(r1*Math.cos((i+1)*delta), 0.45, r1*Math.sin((i+1)*delta)), + put(r1*Math.cos(i*delta), 0.45, r1*Math.sin(i*delta)) + }; + polygons[i+32] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 10f,10f,1); + } + + + start.set(centre); + start.z+=0.1f; + start.y -=0.02f; + iDirection.set(1f,0,0); + jDirection.set(0,1f,0); + kDirection.set(0,0,1f); + + float h = 0.5f; + + float w1 = -0.01f*0.9f; + float w2 = -0.005f*0.9f; + float w3 = 0.005f*0.9f; + float w4 = 0.01f*0.9f; + + float h1 = 0.04f*1f; + float h2 = 0.035f*1f; + float h3 = 0.015f*1f; + float h4 = 0.01f*1f; + + float thickness = 0.01f; + + v = new vector[]{put(w2,h, h1), put(w3,h,h1), put(w4,h, h2), put(w4,h, h3), put(w3,h, h4), put(w2,h, h4), put(w1,h, h3), put(w1,h, h2)}; + polygons[48] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 10f,10f,1); + + + v = new vector[]{put(w2, h, h4), put(w3, h, h4), put(w3, h-thickness, h4), put(w2, h-thickness, h4)}; + polygons[49] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 10f,10f,1); + + v = new vector[]{put(w2, h-thickness, h1), put(w3, h-thickness, h1), put(w3, h, h1), put(w2, h, h1)}; + polygons[50] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 10f,10f,1); + + + v = new vector[]{put(w3, h, h4), put(w4, h, h3), put(w4, h-thickness, h3), put(w3, h-thickness, h4) }; + polygons[51] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 10f,10f,1); + + v = new vector[]{put(w1, h, h3), put(w2, h, h4), put(w2, h-thickness, h4), put(w1, h-thickness, h3) }; + polygons[52] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 10f,10f,1); + + v = new vector[]{put(w4, h, h3), put(w4, h , h2), put(w4, h-thickness , h2), put(w4, h-thickness, h3)}; + polygons[53] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 10f,10f,1); + + v = new vector[]{put(w1, h-thickness, h3), put(w1, h-thickness , h2), put(w1, h , h2), put(w1, h, h3)}; + polygons[54] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 10f,10f,1); + + v = new vector[]{put(w4,h,h2), put(w3, h, h1),put(w3, h-thickness, h1), put(w4,h-thickness,h2)}; + polygons[55] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 10f,10f,1); + + v = new vector[]{put(w2, h, h1), put(w1,h,h2), put(w1,h-thickness,h2), put(w2, h-thickness, h1)}; + polygons[56] = new polygon3D(v, v[0], v[1], v[3], mainThread.textures[25], 10f,10f,1); + + for(int i = 0; i < polygons.length; i++){ + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + polygons[i].vertex3D[j].subtract(centre); + polygons[i].vertex3D[j].rotate_XZ(angle); + polygons[i].vertex3D[j].add(centre); + } + polygons[i].normal.rotate_XZ(angle); + polygons[i].findDiffuse(); + + + polygons[i].parentObject = this; + } + + + + } + + //update the model + public void update(){ + if(vanished) + return; + + mainThread.gridMap.currentObstacleMap[tileIndex] = false; + + //update center in camera coordinate + tempCentre.set(centre); + tempCentre.subtract(camera.position); + tempCentre.rotate_XZ(camera.XZ_angle); + tempCentre.rotate_YZ(camera.YZ_angle); + tempCentre.updateLocation(); + + if(tempCentre.screenX > 918 || tempCentre.screenX < - 150 || tempCentre.screenY < - 150 || tempCentre.screenY > 662){ + visible = false; + return; + } + + //test if the light pole is visible in camera point of view + if(visibleBoundary.contains(tempCentre.screenX, tempCentre.screenY)){ + visible = true; + + if(screenBoundary.contains(tempCentre.screenX, tempCentre.screenY)) + withinViewScreen = true; + else + withinViewScreen = false; + + + }else{ + visible = false; + } + + + + + tempshadowvertex0.set(shadowvertex0); + tempshadowvertex0.subtract(camera.position); + tempshadowvertex0.rotate_XZ(camera.XZ_angle); + tempshadowvertex0.rotate_YZ(camera.YZ_angle); + tempshadowvertex0.updateLocation(); + + tempshadowvertex1.set(shadowvertex1); + tempshadowvertex1.subtract(camera.position); + tempshadowvertex1.rotate_XZ(camera.XZ_angle); + tempshadowvertex1.rotate_YZ(camera.YZ_angle); + tempshadowvertex1.updateLocation(); + + tempshadowvertex2.set(shadowvertex2); + tempshadowvertex2.subtract(camera.position); + tempshadowvertex2.rotate_XZ(camera.XZ_angle); + tempshadowvertex2.rotate_YZ(camera.YZ_angle); + tempshadowvertex2.updateLocation(); + + tempshadowvertex3.set(shadowvertex3); + tempshadowvertex3.subtract(camera.position); + tempshadowvertex3.rotate_XZ(camera.XZ_angle); + tempshadowvertex3.rotate_YZ(camera.YZ_angle); + tempshadowvertex3.updateLocation(); + + + + //if the object is visible then draw it on the shadow buffer from light point of view + if(shadowBoundary1.contains(tempshadowvertex0.screenX, tempshadowvertex0.screenY) || + shadowBoundary1.contains(tempshadowvertex1.screenX, tempshadowvertex1.screenY) || + shadowBoundary1.contains(tempshadowvertex2.screenX, tempshadowvertex2.screenY) || + shadowBoundary1.contains(tempshadowvertex3.screenX, tempshadowvertex3.screenY) + + + ){ + for(int i = 0; i < polygons.length; i++){ + polygons[i].update_lightspace(); + + + } + + } + + } + + public void vanish(){ + mainThread.gridMap.tiles[tileIndex][4] = null; + mainThread.gridMap.currentObstacleMap[tileIndex] = true; + vanished = true; + } + + + public vector getMovement(){ + return movenment; + } + + //draw model + public void draw(){ + + if(!visible || vanished) + return; + for(int i = 0; i < polygons.length; i++){ + polygons[i].update(); + } + + for(int i = 0; i < polygons.length; i++){ + polygons[i].draw(); + } + } + +} diff --git a/entity/lightTank.java b/entity/lightTank.java new file mode 100644 index 0000000..8a7252b --- /dev/null +++ b/entity/lightTank.java @@ -0,0 +1,1025 @@ +package entity; + +import java.awt.Rectangle; + +import core.*; +import enemyAI.enemyCommander; + +//light tank 3D model + +public class lightTank extends solidObject{ + + public vector iDirectionBody, jDirectionBody, kDirectionBody, iDirectionTurret, jDirectionTurret, kDirectionTurret; + + public vector bodyCenter, turretCenter; + + public polygon3D[] body, turret; + + public static int maxHP = 120; + + //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,908, 597); + + //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,688, 432); + + //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, 800); + + //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 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 = 8; + public int turretTurnRate = 10; + public int myAttackCooldown= 28; + + //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, tileCheckList_player, tileCheckList_enemy; + + + public lightTank(vector origin, int bodyAngle, int teamNo){ + speed = 0.012f; + attackRange = 1.60f; + groupAttackRange = 1.2f; + 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 = 0; + myDamage = 10; + if(bitmapVisionForEnemy == null){ + bitmapVisionForEnemy = createBitmapVision(6); + bitmapVisionGainFromAttackingUnit = createBitmapVision(2); + } + + + 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(0.95f*0.97f,0,0); + jDirection = new vector(0,0.63f*0.97f,0); + kDirection = new vector(0,0,0.95f*0.97f); + + iDirection.rotate_XZ(360-bodyAngle); + kDirection.rotate_XZ(360-bodyAngle); + + //create axis for body and turret + iDirectionBody = iDirection.myClone(); + jDirectionBody = new vector(0,0.8f,0); + kDirectionBody = kDirection.myClone(); + + iDirectionTurret = iDirection.myClone(); + jDirectionTurret = jDirection.myClone(); + kDirectionTurret = kDirection.myClone(); + jDirectionTurret.scale(1.1f); + kDirectionTurret.scale(0.9f); + + + //create polygons + makePolygons(); + + + movement_offscreen = new vector(0,0,0); + + if(tileCheckList_player == null){ + tileCheckList_player = generateTileCheckList(5f); + tileCheckList_enemy = generateTileCheckList(5f); + } + + } + + public void makePolygons(){ + + bodyCenter.y-=0.18f; + start.set(bodyCenter); + + int skinTextureIndex = 2; + if(teamNo != 0) + skinTextureIndex = 10; + + body = new polygon3D[15]; + v = new vector[]{put(-0.071, 0.025, 0.11), put(-0.071, 0.025, -0.11), put(-0.071, 0.005, -0.11), put(-0.071, -0.025, -0.08), put(-0.071, -0.025, 0.07), put(-0.071, 0.005, 0.11)}; + body[0] = new polygon3D(v, put(-0.071, 0.027, 0.11), put(-0.071, 0.027, -0.11), put(-0.071, -0.025, 0.11), mainThread.textures[3], 1,1,1); + + v = new vector[]{put(0.071, 0.005, 0.11), put(0.071, -0.025, 0.07), put(0.071, -0.025, -0.08), put(0.071, 0.005, -0.11), put(0.071, 0.025, -0.11), put(0.071, 0.025, 0.11)}; + body[1] = new polygon3D(v, put(0.071, 0.027, -0.11),put(0.071, 0.027, 0.11), put(0.071, -0.025, -0.11), mainThread.textures[3], 1,1,1); + + v = new vector[]{put(-0.06, 0.055, 0.05), put(0.06, 0.055, 0.05), put(0.06, 0.055, -0.1), put(-0.06, 0.055, -0.1)}; + body[2] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 1,0.9f, 1); + + v = new vector[]{put(-0.07, 0.04, 0.11), put(0.07, 0.04, 0.11), put(0.06, 0.055, 0.05), put(-0.06, 0.055, 0.05)}; + body[3] = new polygon3D(v, v[2], v[3], v [1], mainThread.textures[skinTextureIndex], 1,0.3f,1); + + v = new vector[]{put(-0.06, 0.055, 0.05),put(-0.06, 0.055, -0.1), put(-0.07, 0.04, -0.11), put(-0.07, 0.04, 0.11)}; + body[4] = new polygon3D(v, v[2], v[3], v [1], mainThread.textures[skinTextureIndex], 1,0.3f,1); + + v = new vector[]{put(0.07, 0.04, 0.11), put(0.07, 0.04, -0.11), put(0.06, 0.055, -0.1),put(0.06, 0.055, 0.05)}; + body[5] = new polygon3D(v, v[2], v[3], v [1], mainThread.textures[skinTextureIndex], 1,0.3f,1); + + v = new vector[]{put(-0.06, 0.055, -0.1), put(0.06, 0.055, -0.1), put(0.07, 0.04, -0.11), put(-0.07, 0.04, -0.11)}; + body[6] = new polygon3D(v, v[2], v[3], v [1], mainThread.textures[skinTextureIndex], 1,0.3f,1); + + v = new vector[]{put(0.07, 0.04, 0.11), put(-0.07, 0.04, 0.11), put(-0.07, 0.01, 0.11), put(0.07, 0.01, 0.11)}; + body[7] = new polygon3D(v, v[2], v[3], v [1], mainThread.textures[skinTextureIndex], 1,0.3f,1); + + v = new vector[]{put(-0.07, 0.04, 0.11), put(-0.07, 0.04, -0.11), put(-0.07, 0.015, -0.11), put(-0.07, 0.005, -0.09), put(-0.07, 0.005, 0.09),put(-0.07, 0.015, 0.11)}; + body[8] = new polygon3D(v, put(-0.07, 0.04, 0.11), put(-0.07, 0.04, -0.11), put(-0.07, 0.025, 0.11), mainThread.textures[skinTextureIndex], 1,0.3f,1); + + v = new vector[]{put(0.07, 0.015, 0.11), put(0.07, 0.005, 0.09), put(0.07, 0.005, -0.09), put(0.07, 0.015, -0.11), put(0.07, 0.04, -0.11),put(0.07, 0.04, 0.11)}; + body[9] = new polygon3D(v, put(0.07, 0.04, 0.11), put(0.07, 0.04, -0.11), put(0.07, 0.025, 0.11), mainThread.textures[skinTextureIndex], 1,0.3f,1); + + v = new vector[]{put(-0.07, 0.04, -0.11), put(0.07, 0.04, -0.11), put(0.07, 0.015, -0.11), put(-0.07, 0.015, -0.11)}; + body[10] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 1,0.3f,1); + + v = new vector[]{put(-0.07, 0.005, -0.11), put(-0.04, 0.005, -0.11), put(-0.04, -0.025, -0.08), put(-0.07, -0.025, -0.08)}; + body[11] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[3], 1,1,1); + + v = new vector[]{put(-0.07, 0.015, -0.11), put(-0.04, 0.015, -0.11), put(-0.04, 0.005, -0.11), put(-0.07, 0.005, -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.015, -0.11), put(0.07, 0.015, -0.11), put(0.07, 0.005, -0.11), put(0.04, 0.005, -0.11)}; + body[13] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[3], 1,1,1); + + v = new vector[]{put(0.04, 0.005, -0.11), put(0.07, 0.005, -0.11), put(0.07, -0.025, -0.08), put(0.04, -0.025, -0.08)}; + body[14] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[3], 1,1,1); + + + + for(int i = 0; i < body.length; i++){ + body[i].Ambient_I+=6; + body[i].findDiffuse(); + body[i].parentObject = this; + + } + + + turretCenter = put(0, 0.065, -0.0); + start.set(turretCenter); + + turret = new polygon3D[11]; + kDirection.set(kDirectionTurret); + + v = new vector[]{put(0.04, 0.035, 0.06), put(-0.04, 0.035, 0.06), put(-0.04, 0, 0.06), put(0.04, 0, 0.06)}; + turret[0] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.6f,0.3f,1); + + v = new vector[]{put(0, 0.04, 0.18), put(0.006, 0.03, 0.18), put(0.008, 0.025, 0.06), put(0, 0.035, 0.06)}; + turret[1] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.1f,1,1); + + v = new vector[]{ put(0, 0.035, 0.06), put(-0.008, 0.025, 0.06), put(-0.006, 0.03, 0.18),put(0, 0.04, 0.18)}; + turret[2] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.1f,1,1); + + v = new vector[]{put(-0.04, 0.035, 0.06), put(0.04, 0.035, 0.06), put(0.05, 0.035, 0.04), put(0.05, 0.035, -0.03), put(0.03, 0.035, -0.07), put(-0.03, 0.035, -0.07),put(-0.05, 0.035, -0.03), put(-0.05, 0.035, 0.04)}; + turret[3] = new polygon3D(v, put(-0.04, 0.035, 0.19), put(0.04, 0.035, 0.19), put(-0.04, 0.035, 0.09), mainThread.textures[skinTextureIndex], 0.6f,0.6f,1); + + v = new vector[]{put(0.03, 0, -0.07), put(-0.03, 0, -0.07), put(-0.03, 0.035, -0.07), put(0.03, 0.035, -0.07)}; + turret[4] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.4f,0.2f,1); + + v = new vector[]{put(0.03, 0.035, -0.07), put(0.05, 0.035, -0.03), put(0.05, 0, -0.03), put(0.03, 0, -0.07)}; + turret[5] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.4f,0.2f,1); + + v = new vector[]{put(-0.03, 0, -0.07), put(-0.05, 0, -0.03), put(-0.05, 0.035, -0.03), put(-0.03, 0.035, -0.07)}; + turret[6] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.4f,0.2f,1); + + v = new vector[]{put(0.05, 0.035, -0.03), put(0.05, 0.035, 0.04), put(0.05, 0, 0.04), put(0.05, 0, -0.03)}; + turret[7] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.5f,0.3f,1); + + v = new vector[]{put(-0.05, 0, -0.03), put(-0.05, 0, 0.04), put(-0.05, 0.035, 0.04), put(-0.05, 0.035, -0.03)}; + turret[8] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.5f,0.3f,1); + + v = new vector[]{put(0.05, 0.035, 0.04), put(0.04, 0.035, 0.06), put(0.04, 0, 0.06), put(0.05, 0, 0.04)}; + turret[9] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.3f,0.3f,1); + + v = new vector[]{put(-0.05, 0, 0.04), put(-0.04, 0, 0.06), put(-0.04, 0.035, 0.06), put(-0.05, 0.035, 0.04)}; + turret[10] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[skinTextureIndex], 0.3f,0.3f,1); + + for(int i = 0; i < turret.length; i++){ + turret[i].Ambient_I+=6; + turret[i].findDiffuse(); + turret[i].parentObject = this; + } + + + } + + + //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+=10; + return; + } + + if(experience >= 40){ + myDamage = 18; + level = 1; + if(experience >= 80){ + level = 2; + myDamage = 30 ; + if(currentHP < maxHP && mainThread.frameIndex%12==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, 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 - 650); + 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 <= 60 && (mainThread.frameIndex + 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); + + //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(); + performStandByLogic(); + + }else if(currentCommand == move){ + performMovementLogic(); + avoidGettingStucked(); + + }else if(currentCommand == attackInNumbers || currentCommand == attackCautiously){ + performAttackLogic(); + avoidGettingStucked(); + + }else if(currentCommand == attackMove){ + performAttackMoveLogic(); + avoidGettingStucked(); + } + } + + //the tank will attack with any hostile unit that moved into its firing range + public void performStandByLogic(){ + if(teamNo == 0) + tileCheckList = tileCheckList_player; + else + tileCheckList = tileCheckList_enemy; + + //scan for hostile unit + if((ID + mainThread.frameIndex)%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; + } + } + } + } + } + } + } + + + //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) + fireBullet(attackAngle); + }else{ + fireBullet(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; + if(teamNo == 0) + tileCheckList = tileCheckList_player; + else + tileCheckList = tileCheckList_enemy; + + 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){ + 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(); + } + + + //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(); + + } + } + } + } + + + public void fireBullet(int attackAngle){ + if(attackCoolDown == 0 && targetObject.currentHP >0 && hasLineOfSightToTarget){ + //if there is nothing between the tank and its target + firingPosition.set(0, -0.4f, 0.18f); + firingPosition.rotate_XZ(360 - attackAngle); + firingPosition.add(centre.x, 0, centre.z); + //deal bonus damage against heavy tank + int theDamage = myDamage; + if(targetObject.type == 7) + theDamage*=1.5; + if(targetObject.type == 0) + theDamage*=1.2; + if(targetObject.type >= 100) + theDamage*=0.8; + + theAssetManager.spawnBullet(attackAngle, theDamage, targetObject, firingPosition, this); + attackCoolDown = myAttackCooldown; + + //spawn a mini explosion + float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount]; + tempFloat[0] = firingPosition.x; + tempFloat[1] = firingPosition.y; + tempFloat[2] = firingPosition.z; + tempFloat[3] = 0.4f; + tempFloat[4] = 3; + 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;} + +} diff --git a/entity/missileTurret.java b/entity/missileTurret.java new file mode 100644 index 0000000..f83a1ee --- /dev/null +++ b/entity/missileTurret.java @@ -0,0 +1,951 @@ +package entity; + +import java.awt.Rectangle; + +import core.*; +import enemyAI.enemyCommander; + + +//the power plant model +public class missileTurret extends solidObject{ + + public static int maxHP = 250; + + public int countDownToDeath = 16; + + public vector tempVector = new vector(0,0,0); + public vector tempVector0 = new vector(0,0,0); + public vector tempVector1 = new vector(0,0,0); + public vector tempVector2 = new vector(0,0,0); + public vector tempVector3 = new vector(0,0,0); + + public int [] tileIndex = new int[1]; + public int[] tempInt; + + public float[] tempFloat; + + public vector shadowvertex0, tempshadowvertex0,shadowvertex1, tempshadowvertex1,shadowvertex2, tempshadowvertex2,shadowvertex3, tempshadowvertex3; + + //a screen space boundary which is used to test if the object is visible from camera point of view + public final static Rectangle visibleBoundary = new Rectangle(-85,-85,920, 762); + + //a screen space boundary which is used to test if the entire object is within the screen + public final static Rectangle screenBoundary = new Rectangle(60,60,648, 402); + + //screen space boundary which is used to test if the shadow of the object is within the screen + public final static Rectangle shadowBoundary1 = new Rectangle(0,0,768, 512); + + //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,1600, 2000); + + //a bitmap representation of the vision of the power plant for enemy commander + public static boolean[] bitmapVisionForEnemy; + public static boolean[] bitmapVisionGainFromAttackingUnit; + + //missile never moves + public final static vector movenment = new vector(0,0,0); + + //the oreintation of the turret + public int turretAngle; + + //attack range + public float attackRange = 2.4f; + + //the angle that the turret have rotated between current frame and previous frame + public int turretAngleDelta, accumulatedDelta; + + public int turretTurnRate = 8; + public int myAttackCooldown= 23; + public int attackCoolDown; + public vector firingPosition; + + + //index of the tiles to check when the turret is in standby mode + public static int[] tileCheckList; + + //once the turret starts attacking, it exposed itself to the enemy + public int exposedCountDown; + + public baseInfo theBaseInfo; + + public boolean overCharge; + + public int noOverChargeRed = 4; + public int noOverChargeGreen = 21; + public int noOverChargeBlue = 31; + + public int noOverChargeRedBase = 6; + public int noOverChargeGreenBase = 12; + public int noOverChargeBlueBase = 16; + + public int OverChargeRed = 30; + public int OverChargeGreen = 19; + public int OverChargeBlue = 4; + + public int OverChargeRedBase = 16; + public int OverChargeGreenBase = 12; + public int OverChargeBlueBase = 6; + + public int attackAngle; + + public int randomInt; + + public boolean attackLock; + + public missileTurret(float x, float y, float z, int teamNo){ + //uncontrollable unit, but act as a big sized static collidable agent + type = 199; + + ID = globalUniqID++; + randomInt = gameData.getRandom(); + + if(teamNo == 0){ + isRevealed = true; + theBaseInfo = mainThread.pc.theBaseInfo; + }else{ + theBaseInfo = mainThread.ec.theBaseInfo; + } + + theBaseInfo.numberOfMissileTurret++; + + + currentHP = maxHP; + myDamage = 30; + + this.teamNo = teamNo; + + currentCommand = StandBy; + + if(teamNo == 0){ + isRevealed = true; + } + + if(tileCheckList == null){ + tileCheckList = generateTileCheckList(10f); + } + + if(bitmapVisionForEnemy == null){ + bitmapVisionForEnemy = createBitmapVision(8); + bitmapVisionGainFromAttackingUnit = createBitmapVision(2); + } + + //create 2D boundary + boundary2D = new Rect((int)(x*64) - 8, (int)(z*64) + 8, 16, 16); + boundary2D.owner = this; + int centerX = (int)(x*64); + int centerY = (int)(z*64); + + tileIndex[0] = centerX/16 + (127 - centerY/16)*128; + + + mainThread.gridMap.tiles[tileIndex[0]][0] = this; + mainThread.gridMap.tiles[tileIndex[0]][1] = this; + mainThread.gridMap.tiles[tileIndex[0]][2] = this; + mainThread.gridMap.tiles[tileIndex[0]][3] = this; + mainThread.gridMap.tiles[tileIndex[0]][4] = this; + + + + //init model + start = new vector(x,y,z); + iDirection = new vector(1f,0,0); + jDirection = new vector(0,1f,0); + kDirection = new vector(0,0,1f); + + firingPosition = new vector(0,0,0); + + + //define centre of the model in world coordinate + start = new vector(x,y,z); + centre = start.myClone(); + tempCentre = start.myClone(); + + shadowvertex0 =start.myClone(); + shadowvertex0.add(-0.45f,-0.2f, -0.15f); + tempshadowvertex0 = new vector(0,0,0); + + shadowvertex1 =start.myClone(); + shadowvertex1.add(-0.45f,-0.2f, 0.2f); + tempshadowvertex1 = new vector(0,0,0); + + shadowvertex2 =start.myClone(); + shadowvertex2.add(0.2f,-0.2f, -0.15f); + tempshadowvertex2 = new vector(0,0,0); + + shadowvertex3 =start.myClone(); + shadowvertex3.add(0.2f,-0.2f, 0.2f); + tempshadowvertex3 = new vector(0,0,0); + + + + makePolygons(); + + } + + //create polygons + public void makePolygons(){ + polygons = new polygon3D[94]; + vector[] v; + + //turret base + + float l =0.07f; + float h = 0.07f; + + iDirection.scale(0.65f); + kDirection.scale(0.65f); + + h = 0.3f; + + vector a1 = put(-0.06, h, 0.08); + vector a2 = put(0.06, h, 0.08); + vector a3 = put(0.08, h, 0.06); + vector a4 = put(0.08, h, -0.06); + vector a5 = put(0.06, h, -0.08); + vector a6 = put(-0.06, h, -0.08); + vector a7 = put(-0.08, h, -0.06); + vector a8 = put(-0.08, h, 0.06); + + int textureIndex = 66; + if(teamNo != 0) + textureIndex = 67; + + v = new vector[]{a1, a2, a3, a4,a5, a6, a7, a8}; + polygons[0] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[5].myClone(), mainThread.textures[12], 0.7f, 1f, 1); + + iDirection.scale(1.4f); + kDirection.scale(1.4f); + + vector b1 = put(-0.06, 0, 0.08); + vector b2 = put(0.06, 0, 0.08); + vector b3 = put(0.08, 0, 0.06); + vector b4 = put(0.08, 0, -0.06); + vector b5 = put(0.06, 0, -0.08); + vector b6 = put(-0.06, 0, -0.08); + vector b7 = put(-0.08, 0, -0.06); + vector b8 = put(-0.08, 0, 0.06); + + + v = new vector[]{a2.myClone(), a1.myClone(), b1.myClone(), b2.myClone()}; + polygons[1] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[12], 0.5f, 1f, 1); + polygons[1].shadowBias = 20000; + + + v = new vector[]{a1.myClone(), a8.myClone(), b8.myClone(), b1.myClone()}; + polygons[2] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[2].myClone(), mainThread.textures[12], 0.5f, 1f, 1); + + v = new vector[]{a3.myClone(), a2.myClone(), b2.myClone(), b3.myClone()}; + polygons[3] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[12], 0.5f, 1f, 1); + + v = new vector[]{a4.myClone(), a3.myClone(), b3.myClone(), b4.myClone()}; + polygons[4] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[12], 0.5f, 1f, 1); + + v = new vector[]{a5.myClone(), a4.myClone(), b4.myClone(), b5.myClone()}; + polygons[5] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[12], 0.5f, 1f, 1); + + v = new vector[]{a6.myClone(), a5.myClone(), b5.myClone(), b6.myClone()}; + polygons[6] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[12], 0.5f, 1f, 1); + + v = new vector[]{a7.myClone(), a6.myClone(), b6.myClone(), b7.myClone()}; + polygons[7] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[12], 0.5f, 1f, 1); + + v = new vector[]{a8.myClone(), a7.myClone(), b7.myClone(), b8.myClone()}; + polygons[8] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[12], 0.5f, 1f, 1); + + float r = 0.052f; + float r2 = 0.046f; + + + double theta = Math.PI/16; + + for(int i = 0; i < 32; i++){ + v = new vector[]{ + put(r2*Math.cos(i*theta), 0.3101, r2*Math.sin(i*theta)), + put(r2*Math.cos((i+1)*theta), 0.3101, r2*Math.sin((i+1)*theta)), + put(r*Math.cos((i+1)*theta), 0.3101, r*Math.sin((i+1)*theta)), + put(r*Math.cos(i*theta), 0.3101, r*Math.sin(i*theta)) + + + + }; + polygons[9 +i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[26], 10,10,0); + polygons[9 +i].color = 8 << 10 | 16 << 5 | 21; + } + + for(int i = 0; i < 32; i++){ + v = new vector[]{put(r*Math.cos(i*theta), 0.31, r*Math.sin(i*theta)), + put(r*Math.cos((i+1)*theta), 0.31, r*Math.sin((i+1)*theta)), + put(r*Math.cos((i+1)*theta), 0.3, r*Math.sin((i+1)*theta)), + put(r*Math.cos(i*theta), 0.3, r*Math.sin(i*theta)) + }; + polygons[41 +i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[26], 10,10,0); + polygons[41 +i].color = 8 << 10 | 16 << 5 | 21; + } + + + + + v = new vector[32]; + for(int i = 0; i < 32; i++){ + v[31-i] = put(r*Math.cos(i*theta), 0.31, r*Math.sin(i*theta)); + } + polygons[73] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[26], 10,10,1); + polygons[73].shadowBias = 5000; + + + //turret tower + iDirection.rotate_XZ(360-turretAngle); + jDirection.rotate_XZ(360-turretAngle); + kDirection.rotate_XZ(360-turretAngle); + + + v = new vector[]{put(-0.02f, 0.4f, 0.0f), put(-0.02f, 0.4f, -0.04f), put(-0.02f, 0.31f, -0.02f), put(-0.02f, 0.31f, 0.02f)}; + polygons[74] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 0.5f,0.5f,1); + + + v = new vector[]{put(0.02f, 0.31f, 0.02f), put(0.02f, 0.31f, -0.02f), put(0.02f, 0.4f, -0.04f), put(0.02f, 0.4f, 0.0f)}; + polygons[75] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 0.5f,0.5f,1); + + v = new vector[]{put(0.02f, 0.4f, 0.0f), put(-0.02f, 0.4f, 0.0f), put(-0.02f, 0.31f, 0.02f), put(0.02f, 0.31f, 0.02f)}; + polygons[76] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 0.5f,0.5f,1); + + v = new vector[]{put(0.02f, 0.31f, -0.02f), put(-0.02f, 0.31f, -0.02f), put(-0.02f, 0.4f, -0.04f), put(0.02f, 0.4f, -0.04f)}; + polygons[77] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 0.5f,0.5f,1); + + v = new vector[]{put(-0.02f, 0.4f, 0.0f), put(0.02f, 0.4f, 0.0f), put(0.02f, 0.4f, -0.04f), put(-0.02f, 0.4f, -0.04f)}; + polygons[78] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 0.5f,0.5f,1); + + + v = new vector[]{put(-0.07f, 0.41f, 0.09f), put(-0.04f, 0.41f, 0.09f), put(-0.04f, 0.41f, -0.07f), put(-0.07f, 0.41f, -0.07f)}; + polygons[79] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[33], 0.5f,0.5f,1); + + v = new vector[]{put(-0.07f, 0.41f, 0.09f), put(-0.07f, 0.41f, -0.07f), put(-0.075f, 0.405f, -0.07f), put(-0.075f, 0.405f, 0.09f)}; + polygons[80] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[33], 0.5f,0.5f,1); + + v = new vector[]{ put(-0.035f, 0.405f, 0.09f), put(-0.035f, 0.405f, -0.07f), put(-0.04f, 0.41f, -0.07f),put(-0.04f, 0.41f, 0.09f)}; + polygons[81] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[33], 0.5f,0.5f,1); + + v = new vector[]{put(-0.075f, 0.405f, 0.09f), put(-0.075f, 0.405f, -0.07f), put(-0.075f, 0.37f, -0.07f), put(-0.075f, 0.37f, 0.09f)}; + polygons[82] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[33], 0.5f,0.5f,1); + + v = new vector[]{put(-0.035f, 0.37f, 0.09f), put(-0.035f, 0.37f, -0.07f), put(-0.035f, 0.405f, -0.07f), put(-0.035f, 0.405f, 0.09f)}; + polygons[83] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[33], 0.5f,0.5f,1); + + v = new vector[]{put(-0.04f, 0.41f, 0.09f), put(-0.07f, 0.41f, 0.09f), put(-0.075f, 0.405f, 0.09f), put(-0.075f, 0.37f, 0.09f), put(-0.07f, 0.365f, 0.09f), put(-0.04f, 0.365f, 0.09f), put(-0.035f, 0.37f, 0.09f), put(-0.035f, 0.405f, 0.09f) }; + polygons[84] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[33], 0.5f,0.5f,1); + + v = new vector[]{put(-0.042f, 0.401f, 0.091f), put(-0.067f, 0.401f, 0.091f), put(-0.067f, 0.375f, 0.091f), put(-0.042f, 0.375f, 0.091f) }; + polygons[85] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[68], 0.5f,0.5f,1); + polygons[85].Ambient_I+=20; + + v = new vector[]{put(-0.035f, 0.405f, -0.07f), put(-0.035f, 0.37f, -0.07f), put(-0.04f, 0.365f, -0.07f), put(-0.07f, 0.365f, -0.07f), put(-0.075f, 0.37f, -0.07f), put(-0.075f, 0.405f, -0.07f), put(-0.07f, 0.41f, -0.07f), put(-0.04f, 0.41f, -0.07f)}; + polygons[86] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[33], 0.5f,0.5f,1); + + + + jDirection.scale(1.5f); + iDirection.scale(1.6f); + kDirection.scale(0.3f); + + start.y-=0.19; + start.x+=0.032; + start.z-=0.02; + + + v = new vector[]{put(-0.07f, 0.41f, 0.09f), put(-0.04f, 0.41f, 0.09f), put(-0.04f, 0.41f, -0.07f), put(-0.07f, 0.41f, -0.07f)}; + polygons[87] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 0.5f,0.5f,1); + + v = new vector[]{put(-0.07f, 0.41f, 0.09f), put(-0.07f, 0.41f, -0.07f), put(-0.075f, 0.405f, -0.07f), put(-0.075f, 0.405f, 0.09f)}; + polygons[88] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 0.5f,0.5f,1); + + v = new vector[]{ put(-0.035f, 0.405f, 0.09f), put(-0.035f, 0.405f, -0.07f), put(-0.04f, 0.41f, -0.07f),put(-0.04f, 0.41f, 0.09f)}; + polygons[89] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 0.5f,0.5f,1); + + v = new vector[]{put(-0.075f, 0.405f, 0.09f), put(-0.075f, 0.405f, -0.07f), put(-0.075f, 0.37f, -0.07f), put(-0.075f, 0.37f, 0.09f)}; + polygons[90] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 0.5f,0.5f,1); + + v = new vector[]{put(-0.035f, 0.37f, 0.09f), put(-0.035f, 0.37f, -0.07f), put(-0.035f, 0.405f, -0.07f), put(-0.035f, 0.405f, 0.09f)}; + polygons[91] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 0.5f,0.5f,1); + + v = new vector[]{put(-0.04f, 0.41f, 0.09f), put(-0.07f, 0.41f, 0.09f), put(-0.075f, 0.405f, 0.09f), put(-0.075f, 0.37f, 0.09f), put(-0.07f, 0.365f, 0.09f), put(-0.04f, 0.365f, 0.09f), put(-0.035f, 0.37f, 0.09f), put(-0.035f, 0.405f, 0.09f) }; + polygons[92] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 0.5f,0.5f,1); + + v = new vector[]{put(-0.035f, 0.405f, -0.07f), put(-0.035f, 0.37f, -0.07f), put(-0.04f, 0.365f, -0.07f), put(-0.07f, 0.365f, -0.07f), put(-0.075f, 0.37f, -0.07f), put(-0.075f, 0.405f, -0.07f), put(-0.07f, 0.41f, -0.07f), put(-0.04f, 0.41f, -0.07f)}; + polygons[93] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 0.5f,0.5f,1); + + + jDirection.scale(1f/1.5f); + iDirection.scale(1f/1.6f); + kDirection.scale(1f/0.3f); + + start.y+=0.19; + start.x-=0.032; + start.z+=0.02; + + + + + + } + + + + //update the model + public void update(){ + theAssetManager = mainThread.theAssetManager; + + //process emerging from ground animation + if(centre.y < -0.5f){ + centre.y+=0.01f; + + if(centre.y > -0.5){ + for(int i = 0; i < polygons.length; i++){ + polygons[i].origin.y+=0.0000005; + polygons[i].rightEnd.y+=0.0000005; + polygons[i].bottomEnd.y+=0.0000005; + + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + polygons[i].vertex3D[j].y+=0.0000005; + } + + } + shadowvertex0.y+=0.0000005; + shadowvertex1.y+=0.0000005; + shadowvertex2.y+=0.0000005; + shadowvertex3.y+=0.0000005; + + centre.y = -0.5f; + }else{ + for(int i = 0; i < polygons.length; i++){ + polygons[i].origin.y+=0.01; + polygons[i].rightEnd.y+=0.01; + polygons[i].bottomEnd.y+=0.01; + + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + polygons[i].vertex3D[j].y+=0.01; + } + + + } + shadowvertex0.y+=0.01; + shadowvertex1.y+=0.01; + shadowvertex2.y+=0.01; + shadowvertex3.y+=0.01; + } + + //the building is invulnerable during emerging stage + currentHP = maxHP; + } + + if(underAttackCountDown > 0) + underAttackCountDown--; + + //check if power plant has been destroyed + if(currentHP <= 0){ + countDownToDeath--; + + if(countDownToDeath == 0){ + //spawn an explosion when the tank is destroyed + float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount]; + tempFloat[0] = centre.x; + tempFloat[1] = centre.y + 0.15f; + 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); + + + theBaseInfo.numberOfMissileTurret--; + + if(overCharge) + theBaseInfo.numberOfOverChargedMissileTurret--; + + //removeFromGridMap(); + mainThread.gridMap.tiles[tileIndex[0]][0] = null; + mainThread.gridMap.tiles[tileIndex[0]][1] = null; + mainThread.gridMap.tiles[tileIndex[0]][2] = null; + mainThread.gridMap.tiles[tileIndex[0]][3] = null; + mainThread.gridMap.tiles[tileIndex[0]][4] = null; + + if(attacker.teamNo != teamNo) + attacker.experience+=35; + + return; + }else{ + + if(mainThread.frameIndex%2==0){ + float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount]; + tempFloat[0] = centre.x + (float)Math.random()/4f - 0.125f; + tempFloat[1] = centre.y + 0.15f; + tempFloat[2] = centre.z + (float)Math.random()/4f - 0.125f; + tempFloat[3] = 1.5f; + tempFloat[4] = 1; + tempFloat[5] = 0; + tempFloat[6] = 6 + (gameData.getRandom()%4); + tempFloat[7] = this.height; + theAssetManager.explosionCount++; + } + return; + } + } + + if(isRepairing && currentHP >0){ + if(mainThread.frameIndex%5==0 && theBaseInfo.currentCredit > 0 && currentHP 0) + attackCoolDown--; + + if(exposedCountDown > 0) + exposedCountDown --; + + if(overCharge) + myAttackCooldown = 10; + + //mark itself on obstacle map + mainThread.gridMap.currentObstacleMap[tileIndex[0]] = false; + + + //update center in camera coordinate + tempCentre.set(centre); + tempCentre.y+=0.4f; + tempCentre.subtract(camera.position); + tempCentre.rotate_XZ(camera.XZ_angle); + tempCentre.rotate_YZ(camera.YZ_angle); + tempCentre.updateLocation(); + screenX_gui = (int)tempCentre.screenX; + screenY_gui = (int)tempCentre.screenY; + + tempCentre.set(centre); + tempCentre.y+=0.1f; + tempCentre.subtract(camera.position); + tempCentre.rotate_XZ(camera.XZ_angle); + tempCentre.rotate_YZ(camera.YZ_angle); + tempCentre.updateLocation(); + + + + //test if the gun turret is visible in camera point of view + if(visibleBoundary.contains(tempCentre.screenX, tempCentre.screenY) && isRevealed){ + visible = true; + + if(screenBoundary.contains(tempCentre.screenX, tempCentre.screenY)) + withinViewScreen = true; + else + withinViewScreen = false; + + tempshadowvertex0.set(shadowvertex0); + tempshadowvertex0.subtract(camera.position); + tempshadowvertex0.rotate_XZ(camera.XZ_angle); + tempshadowvertex0.rotate_YZ(camera.YZ_angle); + tempshadowvertex0.updateLocation(); + + tempshadowvertex1.set(shadowvertex1); + tempshadowvertex1.subtract(camera.position); + tempshadowvertex1.rotate_XZ(camera.XZ_angle); + tempshadowvertex1.rotate_YZ(camera.YZ_angle); + tempshadowvertex1.updateLocation(); + + tempshadowvertex2.set(shadowvertex2); + tempshadowvertex2.subtract(camera.position); + tempshadowvertex2.rotate_XZ(camera.XZ_angle); + tempshadowvertex2.rotate_YZ(camera.YZ_angle); + tempshadowvertex2.updateLocation(); + + tempshadowvertex3.set(shadowvertex3); + tempshadowvertex3.subtract(camera.position); + tempshadowvertex3.rotate_XZ(camera.XZ_angle); + tempshadowvertex3.rotate_YZ(camera.YZ_angle); + tempshadowvertex3.updateLocation(); + + + + //if the object is visible then draw it on the shadow buffer from light point of view + if(shadowBoundary1.contains(tempshadowvertex0.screenX, tempshadowvertex0.screenY) || + shadowBoundary1.contains(tempshadowvertex1.screenX, tempshadowvertex1.screenY) || + shadowBoundary1.contains(tempshadowvertex2.screenX, tempshadowvertex2.screenY) || + shadowBoundary1.contains(tempshadowvertex3.screenX, tempshadowvertex3.screenY) + ){ + for(int i = 0; i < polygons.length; i++){ + polygons[i].update_lightspace(); + + + } + + } + + //add this object to visible unit list + theAssetManager.visibleUnit[theAssetManager.visibleUnitCount] = this; + theAssetManager.visibleUnitCount++; + + + }else{ + visible = false; + } + + + //create vision for enemy commander + if(teamNo == 1){ + int xPos = boundary2D.x1/16 - 6 + 10; + int 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; + } + } + } + + + visionBoundary.x = (int)(tempCentre.screenX - 800); + visionBoundary.y = (int)(tempCentre.screenY - 1000); + visionInsideScreen = camera.screen.intersects(visionBoundary); + + + if(visionInsideScreen){ + if(teamNo != 0){ + if(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++; + } + } + + + if(theAssetManager.minimapBitmap[tileIndex[0]]){ + isRevealed = true; + } + visible_minimap = isRevealed; + + + 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] = 2; + if(teamNo == 0 && underAttackCountDown > 0) + tempInt[4] = 10001; + else{ + if(exposedCountDown > 0) + tempInt[4] = exposedCountDown; + else + tempInt[4] = 10000; + } + theAssetManager.unitsForMiniMapCount++; + + } + + + + + accumulatedDelta+=turretAngleDelta; + accumulatedDelta= accumulatedDelta%360; + if(visible){ + if(!overCharge){ + float ratio = ((float)Math.sin((float)(mainThread.frameIndex + ID)/10) + 1)/2; + + if(theBaseInfo.lowPower) + ratio = 0; + + int color = (int)(noOverChargeRedBase + ratio * (noOverChargeRed - noOverChargeRedBase)) << 10 | (int)(noOverChargeGreenBase + ratio * (noOverChargeGreen - noOverChargeGreenBase)) << 5 | (int)(noOverChargeBlueBase + ratio * (noOverChargeBlue - noOverChargeBlueBase)); + + for(int i = 9; i < 73; i++){ + polygons[i].color = color; + polygons[i].diffuse_I = 100; + } + }else{ + float ratio = ((float)Math.sin((float)(mainThread.frameIndex + ID)/10) + 1)/2; + + if(theBaseInfo.lowPower) + ratio = 0; + + int color = (int)(OverChargeRedBase + ratio * (OverChargeRed - OverChargeRedBase)) << 10 | (int)(OverChargeGreenBase + ratio * (OverChargeGreen - OverChargeGreenBase)) << 5 | (int)(OverChargeBlueBase + ratio * (OverChargeBlue - OverChargeBlueBase)); + + for(int i = 9; i < 73; i++){ + polygons[i].color = color; + polygons[i].diffuse_I = 100; + } + + + } + + //update turret polygons + for(int i = 74; i < polygons.length; i++){ + + polygons[i].origin.subtract(centre); + polygons[i].origin.rotate_XZ(accumulatedDelta); + polygons[i].origin.add(centre); + + + polygons[i].bottomEnd.subtract(centre); + polygons[i].bottomEnd.rotate_XZ(accumulatedDelta); + polygons[i].bottomEnd.add(centre); + + + polygons[i].rightEnd.subtract(centre); + polygons[i].rightEnd.rotate_XZ(accumulatedDelta); + polygons[i].rightEnd.add(centre); + + + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + + polygons[i].vertex3D[j].subtract(centre); + polygons[i].vertex3D[j].rotate_XZ(accumulatedDelta); + polygons[i].vertex3D[j].add(centre); + } + + + polygons[i].normal.rotate_XZ(accumulatedDelta); + polygons[i].findDiffuse(); + } + accumulatedDelta = 0; + + } + + } + + //process turret AI + public void carryOutCommands(){ + if(theBaseInfo.lowPower){ + targetObject = null; + turretAngleDelta = 0; + return; + } + + if(targetObject != null){ + + //target enemy military unit first + if((targetObject.type > 100 ||targetObject.type <199) && !attackLock && (randomInt + mainThread.frameIndex)%4 == 2){ + 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) + 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){ + destinationX = tile[j].getRealCentre().x; + destinationY = tile[j].getRealCentre().z; + distanceToDesination = (float)Math.sqrt((destinationX - centre.x) * (destinationX - centre.x) + (destinationY - centre.z) * (destinationY - centre.z)); + + if(distanceToDesination <= attackRange){ + if(tile[j].type < 100 || tile[j].type >= 199){ + targetObject = tile[j]; + break; + } + } + } + } + } + if(targetObject.type < 100 || targetObject.type >= 199) + break; + } + } + } + + destinationX = targetObject.getRealCentre().x; + destinationY = targetObject.getRealCentre().z; + + distanceToDesination = (float)Math.sqrt((destinationX - centre.x) * (destinationX - centre.x) + (destinationY - centre.z) * (destinationY - centre.z)); + + + + if(targetObject.currentHP <=0 || (targetObject.isCloaked && teamNo != targetObject.teamNo) || distanceToDesination > attackRange){ + targetObject = null; + turretAngleDelta = 0; + attackLock = false; + return; + } + + 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 there is no target, perform standby logic + //scan for hostile unit + + boolean[] bitmapVision; + if(teamNo == 0) + bitmapVision = mainThread.theAssetManager.minimapBitmap; + else + bitmapVision = enemyCommander.visionMap; + + attackLock = false; + + if((randomInt + mainThread.frameIndex)%240 == 0){ + attackAngle = (int)(Math.random()*360); + } + if(turretAngle != attackAngle){ + + turretAngleDelta = 360 - (geometry.findAngleDelta(turretAngle, attackAngle, 2) + 360)%360; + turretAngle= (turretAngle - turretAngleDelta + 360)%360; + + }else{ + + turretAngleDelta = 0; + } + + + if((ID + mainThread.frameIndex)%4 == 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) + continue; + tile = mainThread.gridMap.tiles[index]; + + if(!bitmapVision[index]){ + boolean isRevealedBuilding = false; + if(tile[4] != null) + if(tile[4].type > 100) + if(tile[4].isRevealed == true) + 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){ + destinationX = tile[j].getRealCentre().x; + destinationY = tile[j].getRealCentre().z; + distanceToDesination = (float)Math.sqrt((destinationX - centre.x) * (destinationX - centre.x) + (destinationY - centre.z) * (destinationY - centre.z)); + + if(distanceToDesination <= attackRange){ + targetObject = tile[j]; + if(targetObject.type < 100 || targetObject.type >= 199) + return; + } + } + } + } + } + } + } + + + } + } + + + //draw the model + public void draw(){ + + if(!visible) + return; + for(int i = 0; i < polygons.length; i++){ + polygons[i].update(); + polygons[i].draw(); + } + } + + public void attack(solidObject o){ + if(targetObject != o){ + + distanceToDesination = (float)Math.sqrt((o.centre.x - centre.x) * (o.centre.x - centre.x) + (o.centre.z - centre.z) * (o.centre.z - centre.z)); + + //check if target is within range + if(distanceToDesination <= attackRange){ + targetObject = o; + attackLock = true; + } + + } + } + + public void fireRocket(int attackAngle){ + if(targetObject != null && targetObject.teamNo != teamNo){ + exposedCountDown = 64; + isRevealed = true; + } + + tempVector.set(centre); + + + if(attackCoolDown == 0 ){ + firingPosition.set(-0.05f, -0.1f, 0.14f); + firingPosition.rotate_XZ(360 - attackAngle); + firingPosition.add(tempVector.x, 0, tempVector.z); + theAssetManager.spawnRocket(attackAngle, myDamage, targetObject, firingPosition, this); + attackCoolDown = myAttackCooldown; + + //spawn a mini explosion + firingPosition.set(-0.05f, -0.1f, 0.13f); + 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 hold(){ + targetObject = null; + turretAngleDelta = 0; + } + + public vector getMovement(){ + return movenment; + } +} diff --git a/entity/palmTree.java b/entity/palmTree.java new file mode 100644 index 0000000..e62cf47 --- /dev/null +++ b/entity/palmTree.java @@ -0,0 +1,347 @@ +package entity; + +import java.awt.Rectangle; + +import core.*; + +//palmTree model +public class palmTree extends solidObject{ + //the polygons of the model + public polygon3D[] polygons; + + public int angle; + + public int tileIndex; + + public vector shadowvertex0, tempshadowvertex0,shadowvertex1, tempshadowvertex1,shadowvertex2, tempshadowvertex2,shadowvertex3, tempshadowvertex3; + + //a screen space boundary which is used to test if the object is visible from camera point of view + public final static Rectangle visibleBoundary = new Rectangle(-50,-50,868, 612); + + //a screen space boundary which is used to test if the entire object is within the screen + public final static Rectangle screenBoundary = new Rectangle(40,40,688, 432); + + //screen space boundary which is used to test if the shadow of the object is within the screen + public final static Rectangle shadowBoundary1 = new Rectangle(-20, -20,808, 552); + + //palmTrees never moves + public final static vector movenment = new vector(0,0,0); + + + //angles between leave branch + public static int[] angles = new int[5]; + + public palmTree(float x, float y, float z){ + //uncontrollable unit, but act as a small sized static collidable agent + ID = -1; + + type = 100; + + + boundary2D = new Rect((int)(x*64), (int)(z*64), 1, 1); + + tileIndex = boundary2D.x1/16 + (127 - (boundary2D.y1)/16)*128; + + if(tileIndex >= 0 && tileIndex < 128*128) + mainThread.gridMap.tiles[tileIndex][4] = this; + else + tileIndex = 0; + + + this.angle = (int)(360*Math.random()); + + x = x+0.05f - (float)(Math.random()/10); + y = y+0.05f - (float)(Math.random()/10); + z = z+0.05f - (float)(Math.random()/10); + + start = new vector(x,y,z); + centre = start.myClone(); + tempCentre = start.myClone(); + + shadowvertex0 =start.myClone(); + shadowvertex0.add(-0.35f,-0.2f, -0.35f); + tempshadowvertex0 = new vector(0,0,0); + + shadowvertex1 =start.myClone(); + shadowvertex1.add(-0.35f,-0.2f, 0); + tempshadowvertex1 = new vector(0,0,0); + + shadowvertex2 =start.myClone(); + shadowvertex2.add(0,-0.2f, -0.35f); + tempshadowvertex2 = new vector(0,0,0); + + shadowvertex3 =start.myClone(); + shadowvertex3.add(0,-0.2f, 0f); + tempshadowvertex3 = new vector(0,0,0); + + float scale_i = (float)(Math.random() * 0.3) - 0.15f; + float scale_j = (float)(Math.random() * 0.3) - 0.15f; + float scale_k = (float)(Math.random() * 0.3) - 0.15f; + + float scale_j_x = (float)(Math.random() * 0.3) - 0.15f; + float scale_j_y = (float)(Math.random() * 0.3) - 0.15f; + + iDirection = new vector(0.7f+0.3f*1.1f + scale_i,0,0); + jDirection = new vector(scale_j_x,(1.1f+0.3f) + scale_j ,scale_j_y); + kDirection = new vector(0,0,0.7f+0.3f*1.1f + scale_k); + + //adjust orientation of the model + iDirection.rotate_XZ(angle); + kDirection.rotate_XZ(angle); + + int color = 110 << 16 | 205 << 8 | 10; + + postProcessingThread.theMiniMap.background[tileIndex] = color; + postProcessingThread.theMiniMap.background[tileIndex + 1] = color; + postProcessingThread.theMiniMap.background[tileIndex + 128] = color; + postProcessingThread.theMiniMap.background[tileIndex + 129] = color; + + boundary2D.owner = this; + currentCommand = StandBy; + angles[0] = 0; + makePolygons(); + } + + public palmTree(float x, float y, float z, float scale_i, float scale_j, float scale_k, float scale_j_x, float scale_j_y, int angle, int angle1, int angle2, int angle3, int angle4, int angle5){ + //uncontrollable unit, but act as a small sized static collidable agent + type = 100; + boundary2D = new Rect((int)(x*64), (int)(z*64), 1, 1); + + tileIndex = boundary2D.x1/16 + (127 - (boundary2D.y1)/16)*128; + mainThread.gridMap.tiles[tileIndex][4] = this; + + start = new vector(x,y,z); + centre = start.myClone(); + tempCentre = start.myClone(); + + shadowvertex0 =start.myClone(); + shadowvertex0.add(-0.75f,-0.2f, -0.95f); + tempshadowvertex0 = new vector(0,0,0); + + shadowvertex1 =start.myClone(); + shadowvertex1.add(-0.75f,-0.2f, 0); + tempshadowvertex1 = new vector(0,0,0); + + shadowvertex2 =start.myClone(); + shadowvertex2.add(0,-0.2f, -0.95f); + tempshadowvertex2 = new vector(0,0,0); + + shadowvertex3 =start.myClone(); + shadowvertex3.add(0,-0.2f, 0f); + tempshadowvertex3 = new vector(0,0,0); + + iDirection = new vector(0.7f+0.3f*1.1f + scale_i,0,0); + jDirection = new vector(scale_j_x,(1.1f+0.3f) + scale_j ,scale_j_y); + kDirection = new vector(0,0,0.7f+0.3f*1.1f + scale_k); + + iDirection.rotate_XZ(angle); + kDirection.rotate_XZ(angle); + + int color = 110 << 16 | 205 << 8 | 10; + + postProcessingThread.theMiniMap.background[tileIndex] = color; + postProcessingThread.theMiniMap.background[tileIndex + 1] = color; + postProcessingThread.theMiniMap.background[tileIndex + 128] = color; + postProcessingThread.theMiniMap.background[tileIndex + 129] = color; + + boundary2D.owner = this; + currentCommand = StandBy; + angles[0] = angle1; + angles[1] = angle2; + angles[2] = angle3; + angles[3] = angle4; + angles[4] = angle5; + + makePolygons(); + + } + + //Construct polygons for this model. + //The polygon data is hard-coded here + private void makePolygons(){ + + + vector[] v; + + start.add(0,-0.25f,0); + + polygons = new polygon3D[8 + 5*6]; + + if(angles[0] ==0){ + for(int i = 0; i < 5; i++){ + angles[i] = 72*(i+1) + 15 - (int)(30*Math.random()); + + } + } + + + //body + v = new vector[]{put(-0.001, 0.1, -0.01), put(0.016, 0.1, -0.01), put(0.01, 0, -0.01), put(-0.014, 0, -0.01)}; + polygons[0] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[4], 0.1f,0.5f,1); + + v = new vector[]{put(-0.001, 0.1, 0.01), put(-0.001, 0.1, -0.01), put(-0.014, 0, -0.01), put(-0.014, 0, 0.014)}; + polygons[1] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[4], 0.1f,0.5f,1); + + v = new vector[]{put(0.016, 0.1, 0.01), put(-0.001, 0.1, 0.01), put(-0.014, 0, 0.014), put(0.01, 0, 0.014)}; + polygons[2] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[4], 0.1f,0.5f,1); + + v = new vector[]{put(0.016, 0.1, -0.01), put(0.016, 0.1, 0.01), put(0.01, 0, 0.014), put(0.01, 0, -0.01)}; + polygons[3] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[4], 0.1f,0.5f,1); + + v = new vector[]{put(0.002, 0.3, -0.008), put(0.013, 0.3, -0.008), put(0.016, 0.1, -0.01), put(-0.001, 0.1, -0.01)}; + polygons[4] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[4], 0.1f,0.5f,1); + + v = new vector[]{put(0.002, 0.3, 0.006), put(0.002, 0.3, -0.008), put(-0.001, 0.1, -0.01),put(-0.001, 0.1, 0.01)}; + polygons[5] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[4], 0.1f,0.5f,1); + + v = new vector[]{put(0.013, 0.3, 0.006), put(0.002, 0.3, 0.006), put(-0.001, 0.1, 0.01),put(0.016, 0.1, 0.01)}; + polygons[6] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[4], 0.1f,0.5f,1); + + v = new vector[]{put(0.013, 0.3, -0.008), put(0.013, 0.3, 0.006), put(0.016, 0.1, 0.01), put(0.016, 0.1, -0.01)}; + polygons[7] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[4], 0.1f,0.5f,1); + + //leaves + start.add(0.005f, 0,0); + int index = 8; + int currentAngle = 0; + for(int i = 0; i < 5; i++){ + + v = new vector[]{put(0.015, 0.3, 0.01), put(0, 0.3, 0), put(0, 0.34, 0.05), put(0.015, 0.32, 0.05)}; + polygons[index] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[5], 1,1,1); + + v = new vector[]{put(0, 0.3, 0), put(-0.015, 0.3, 0.01), put(-0.015, 0.32, 0.05), put(0, 0.34, 0.05)}; + polygons[index+1] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[5], 1,1,1); + + v = new vector[]{put(0, 0.34, 0.05), put(0, 0.33, 0.09), put(0.015, 0.31, 0.09), put(0.015, 0.32, 0.05)}; + polygons[index + 2] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[5], 1,1,1); + + v = new vector[]{put(0, 0.34, 0.05), put(-0.015, 0.32, 0.05), put(-0.015, 0.31, 0.09), put(0, 0.33, 0.09)}; + polygons[index + 3] = new polygon3D(v, v[0], v[1], v [3], mainThread.textures[5], 1,1,1); + + v = new vector[]{put(0, 0.33, 0.09), put(-0.015, 0.31, 0.09), put(0, 0.29, 0.12)}; + polygons[index + 4] = new polygon3D(v, v[0], v[1], v [2], mainThread.textures[5], 1,1,1); + + v = new vector[]{put(0.015, 0.31, 0.09), put(0, 0.33, 0.09), put(0, 0.29, 0.12)}; + polygons[index + 5] = new polygon3D(v, v[0], v[1], v [2], mainThread.textures[5], 1,1,1); + + iDirection.rotate_XZ(angles[i]-currentAngle); + kDirection.rotate_XZ(angles[i]-currentAngle); + + currentAngle = angles[i]; + + index+=6; + } + + + + + + for(int i = 0; i < polygons.length; i++){ + polygons[i].Ambient_I+=10; + polygons[i].findDiffuse(); + polygons[i].parentObject = this; + } + + } + + //update the model + public void update(){ + mainThread.gridMap.currentObstacleMap[tileIndex] = false; + + //update center in camera coordinate + tempCentre.set(centre); + tempCentre.subtract(camera.position); + tempCentre.rotate_XZ(camera.XZ_angle); + tempCentre.rotate_YZ(camera.YZ_angle); + tempCentre.updateLocation(); + + if(tempCentre.screenX > 918 || tempCentre.screenX < - 150 || tempCentre.screenY < - 150 || tempCentre.screenY > 662){ + visible = false; + return; + } + + //test if the palm tree is visible in camera point of view + if(visibleBoundary.contains(tempCentre.screenX, tempCentre.screenY)){ + visible = true; + + if(screenBoundary.contains(tempCentre.screenX, tempCentre.screenY)) + withinViewScreen = true; + else + withinViewScreen = false; + + + }else{ + visible = false; + } + + + + + tempshadowvertex0.set(shadowvertex0); + tempshadowvertex0.subtract(camera.position); + tempshadowvertex0.rotate_XZ(camera.XZ_angle); + tempshadowvertex0.rotate_YZ(camera.YZ_angle); + tempshadowvertex0.updateLocation(); + + tempshadowvertex1.set(shadowvertex1); + tempshadowvertex1.subtract(camera.position); + tempshadowvertex1.rotate_XZ(camera.XZ_angle); + tempshadowvertex1.rotate_YZ(camera.YZ_angle); + tempshadowvertex1.updateLocation(); + + tempshadowvertex2.set(shadowvertex2); + tempshadowvertex2.subtract(camera.position); + tempshadowvertex2.rotate_XZ(camera.XZ_angle); + tempshadowvertex2.rotate_YZ(camera.YZ_angle); + tempshadowvertex2.updateLocation(); + + tempshadowvertex3.set(shadowvertex3); + tempshadowvertex3.subtract(camera.position); + tempshadowvertex3.rotate_XZ(camera.XZ_angle); + tempshadowvertex3.rotate_YZ(camera.YZ_angle); + tempshadowvertex3.updateLocation(); + + + + //if the object is visible then draw it on the shadow buffer from light point of view + if(shadowBoundary1.contains(tempshadowvertex0.screenX, tempshadowvertex0.screenY) || + shadowBoundary1.contains(tempshadowvertex1.screenX, tempshadowvertex1.screenY) || + shadowBoundary1.contains(tempshadowvertex2.screenX, tempshadowvertex2.screenY) || + shadowBoundary1.contains(tempshadowvertex3.screenX, tempshadowvertex3.screenY) + + + ){ + for(int i = 0; i < polygons.length; i++){ + polygons[i].update_lightspace(); + + + } + + } + + } + + + + + public vector getMovement(){ + return movenment; + } + + //draw model + public void draw(){ + + if(!visible) + return; + for(int i = 0; i < polygons.length; i++){ + polygons[i].update(); + } + + for(int i = 0; i < polygons.length; i++){ + + + polygons[i].draw(); + } + } + +} diff --git a/entity/powerPlant.java b/entity/powerPlant.java new file mode 100644 index 0000000..9de0e7a --- /dev/null +++ b/entity/powerPlant.java @@ -0,0 +1,838 @@ +package entity; + +import java.awt.Rectangle; + +import core.*; +import enemyAI.enemyCommander; + +//the power plant model +public class powerPlant extends solidObject{ + + //the polygons of the model + private polygon3D[] polygons; + + public static int maxHP = 400; + + public int countDownToDeath = 16; + + public vector tempVector = new vector(0,0,0); + public vector tempVector0 = new vector(0,0,0); + public vector tempVector1 = new vector(0,0,0); + public vector tempVector2 = new vector(0,0,0); + public vector tempVector3 = new vector(0,0,0); + + public int [] tileIndex = new int[9]; + public int[] tempInt; + + public float[] tempFloat; + + public vector shadowvertex0, tempshadowvertex0,shadowvertex1, tempshadowvertex1,shadowvertex2, tempshadowvertex2,shadowvertex3, tempshadowvertex3; + + //a screen space boundary which is used to test if the object is visible from camera point of view + public final static Rectangle visibleBoundary = new Rectangle(-85,-85,920, 762); + + //a screen space boundary which is used to test if the entire object is within the screen + public final static Rectangle screenBoundary = new Rectangle(60,60,648, 402); + + //screen space boundary which is used to test if the shadow of the object is within the screen + public final static Rectangle shadowBoundary1 = new Rectangle(0,0,768, 512); + + //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,1600, 2000); + + //a bitmap representation of the vision of the power plant for enemy commander + public static boolean[] bitmapVisionForEnemy; + + //power plant never moves + public final static vector movenment = new vector(0,0,0); + + public baseInfo theBaseInfo; + + public static int intendedDeployLocation = -1; + + public powerPlant(float x, float y, float z, int teamNo){ + //uncontrollable unit, but act as a big sized static collidable agent + type = 101; + + if(teamNo == 0){ + isRevealed = true; + theBaseInfo = mainThread.pc.theBaseInfo; + }else{ + theBaseInfo = mainThread.ec.theBaseInfo; + } + + theBaseInfo.numberOfPowerPlant++; + + ID = globalUniqID++; + + currentHP = 400; + + this.teamNo = teamNo; + + currentCommand = this.StandBy; + + if(teamNo == 0){ + isRevealed = true; + } + + if(bitmapVisionForEnemy == null){ + bitmapVisionForEnemy = createBitmapVision(8); + } + + //create 2D boundary + boundary2D = new Rect((int)(x*64) - 16, (int)(z*64) + 16, 32, 32); + boundary2D.owner = this; + int centerX = (int)(x*64); + int centerY = (int)(z*64); + + tileIndex[0] = (centerX - 8)/16 + (127 - (centerY + 8)/16)*128; + tileIndex[1] = (centerX + 8)/16 + (127 - (centerY + 8)/16)*128; + tileIndex[2] = (centerX + 8)/16 + (127 - (centerY - 8)/16)*128; + tileIndex[3] = (centerX - 8)/16 + (127 - (centerY - 8)/16)*128; + + mainThread.gridMap.tiles[tileIndex[0]][0] = this; + mainThread.gridMap.tiles[tileIndex[1]][0] = this; + mainThread.gridMap.tiles[tileIndex[2]][0] = this; + mainThread.gridMap.tiles[tileIndex[3]][0] = this; + + mainThread.gridMap.tiles[tileIndex[0]][1] = this; + mainThread.gridMap.tiles[tileIndex[1]][1] = this; + mainThread.gridMap.tiles[tileIndex[2]][1] = this; + mainThread.gridMap.tiles[tileIndex[3]][1] = this; + + mainThread.gridMap.tiles[tileIndex[0]][2] = this; + mainThread.gridMap.tiles[tileIndex[1]][2] = this; + mainThread.gridMap.tiles[tileIndex[2]][2] = this; + mainThread.gridMap.tiles[tileIndex[3]][2] = this; + + mainThread.gridMap.tiles[tileIndex[0]][3] = this; + mainThread.gridMap.tiles[tileIndex[1]][3] = this; + mainThread.gridMap.tiles[tileIndex[2]][3] = this; + mainThread.gridMap.tiles[tileIndex[3]][3] = this; + + mainThread.gridMap.tiles[tileIndex[0]][4] = this; + mainThread.gridMap.tiles[tileIndex[1]][4] = this; + mainThread.gridMap.tiles[tileIndex[2]][4] = this; + mainThread.gridMap.tiles[tileIndex[3]][4] = this; + + //the size of the building is larger for AI, to prevent it from building everything close together + if(teamNo != 0){ + tileIndex[4] = tileIndex[1] - 128; + tileIndex[5] = tileIndex[1] - 130; + tileIndex[6] = tileIndex[1] + 256; + tileIndex[7] = tileIndex[1] + 254; + tileIndex[8] = tileIndex[1] + 126; + + mainThread.gridMap.tiles[tileIndex[4]][4] = this; + mainThread.gridMap.tiles[tileIndex[5]][4] = this; + mainThread.gridMap.tiles[tileIndex[6]][4] = this; + mainThread.gridMap.tiles[tileIndex[7]][4] = this; + mainThread.gridMap.tiles[tileIndex[8]][4] = this; + } + + + + //init model + x-=0.03f; + start = new vector(x,y,z); + iDirection = new vector(1.2f,0,0); + jDirection = new vector(0,1.2f,0); + kDirection = new vector(0,0,1.2f); + + //adjust orientation of the model + iDirection.rotate_XZ(255); + kDirection.rotate_XZ(255); + + //define centre of the model in world coordinate + start = new vector(x,y,z); + centre = start.myClone(); + tempCentre = start.myClone(); + + shadowvertex0 =start.myClone(); + shadowvertex0.add(-0.45f,-0.2f, -0.15f); + tempshadowvertex0 = new vector(0,0,0); + + shadowvertex1 =start.myClone(); + shadowvertex1.add(-0.45f,-0.2f, 0.2f); + tempshadowvertex1 = new vector(0,0,0); + + shadowvertex2 =start.myClone(); + shadowvertex2.add(0.2f,-0.2f, -0.15f); + tempshadowvertex2 = new vector(0,0,0); + + shadowvertex3 =start.myClone(); + shadowvertex3.add(0.2f,-0.2f, 0.2f); + tempshadowvertex3 = new vector(0,0,0); + + + makePolygons(); + + } + + //create polygons + public void makePolygons(){ + polygons = new polygon3D[36+36+2+32+32 + 32 + 1]; + vector[] v; + + int index = 0; + + double theta = Math.PI/16; + + double r = 0.12; + + for(int i = 0; i < 18; i++){ + v = new vector[]{put(r*Math.cos((i+1)*theta), 0.18, r*Math.sin((i+1)*theta)), + put(r*Math.cos(i*theta), 0.18, r*Math.sin(i*theta)), + put(r*Math.cos(i*theta), 0, r*Math.sin(i*theta)), + put(r*Math.cos((i+1)*theta), 0, r*Math.sin((i+1)*theta)) + + }; + + tempVector.set(v[1]); + tempVector.subtract(v[0]); + + tempVector0.set(v[0]); + tempVector1.set(v[1]); + + tempVector3.set(v[3]); + tempVector1.add(tempVector); + int p = i % 2; + for(int j = 0; j < p; j++){ + tempVector0.subtract(tempVector); + tempVector1.subtract(tempVector); + tempVector3.subtract(tempVector); + } + + polygons[i + index] = new polygon3D(v, tempVector0.myClone(),tempVector1.myClone(), tempVector3.myClone(), mainThread.textures[13], 0.5f,1, 1); + } + + index+=18; + + v = new vector[]{put(0.12*Math.cos(0*theta), 0.18, 0.12*Math.sin(0*theta)), + put(0.17*Math.cos(0*theta), 0.16, 0.17*Math.sin(0*theta)), + put(0.2*Math.cos(0*theta), 0.13, 0.2*Math.sin(0*theta)), + put(0.2*Math.cos(0*theta), 0, 0.2*Math.sin(0*theta)), + put(0.12*Math.cos(0*theta), 0, 0.12*Math.sin(0*theta)), + }; + polygons[index] = new polygon3D(v, v[0].myClone(), put(0.2*Math.cos(0*theta), 0.18, 0.2*Math.sin(0*theta)), v[4].myClone(), mainThread.textures[13], 0.5f, 1, 1); + + index+=1; + + v = new vector[]{ put(0.12*Math.cos(18*theta), 0, 0.12*Math.sin(18*theta)), + put(0.2*Math.cos(18*theta), 0, 0.2*Math.sin(18*theta)), + put(0.2*Math.cos(18*theta), 0.13, 0.2*Math.sin(18*theta)), + put(0.17*Math.cos(18*theta), 0.16, 0.17*Math.sin(18*theta)), + put(0.12*Math.cos(18*theta), 0.18, 0.12*Math.sin(18*theta)) + }; + polygons[index] = new polygon3D(v, put(0.2*Math.cos(18*theta), 0.18, 0.2*Math.sin(18*theta)), v[4].myClone(), v[1].myClone(), mainThread.textures[13], 0.5f, 1, 1); + index+=1; + + + + double delta = Math.PI/8; + start.add(-0.05f,0,0); + r = 0.085; + double r2 = 0.06; + for(int i = 0; i < 16; i++){ + v = new vector[]{put(r2*Math.cos(i*delta), 0.18, r2*Math.sin(i*delta)), + put(r2*Math.cos((i+1)*delta), 0.18, r2*Math.sin((i+1)*delta)), + put(r*Math.cos((i+1)*delta), 0, r*Math.sin((i+1)*delta)), + put(r*Math.cos(i*delta), 0, r*Math.sin(i*delta)) + }; + + tempVector.set(v[1]); + tempVector.subtract(v[0]); + tempVector0.set(v[0]); + tempVector1.set(v[1]); + tempVector3.set(v[3]); + tempVector1.add(tempVector); + + int p = i % 2; + for(int j = 0; j < p; j++){ + tempVector0.subtract(tempVector); + tempVector1.subtract(tempVector); + tempVector3.subtract(tempVector); + } + + change(0,0.18f,0, tempVector); + polygons[i + index] = new polygon3D(v, tempVector0.myClone(),tempVector1.myClone(), tempVector3.myClone(), mainThread.textures[12], 1f,0.25f,1); + polygons[i + index].textureScaledWidth = (int)(polygons[i + index].myTexture.width*0.5); + polygons[i + index].createShadeSpan(tempVector, v[0], v[1]); + } + start.add(0.05f,0,-0); + index+=16; + + + + r = 0.2; + + for(int i = 0; i < 18; i++){ + v = new vector[]{put(r*Math.cos(i*theta), 0.13, r*Math.sin(i*theta)), + put(r*Math.cos((i+1)*theta), 0.13, r*Math.sin((i+1)*theta)), + put(r*Math.cos((i+1)*theta), 0, r*Math.sin((i+1)*theta)), + put(r*Math.cos(i*theta), 0, r*Math.sin(i*theta)) + }; + + + tempVector.set(v[1]); + tempVector.subtract(v[0]); + tempVector0.set(v[0]); + tempVector1.set(v[1]); + tempVector3.set(v[3]); + tempVector1.add(tempVector); + + int p = i % 2; + for(int j = 0; j < p; j++){ + tempVector0.subtract(tempVector); + tempVector1.subtract(tempVector); + tempVector3.subtract(tempVector); + } + + polygons[i + index] = new polygon3D(v, tempVector0.myClone(),tempVector1.myClone(), tempVector3.myClone(), mainThread.textures[13], 0.5f,1,1); + } + + index += 18; + + r2 = 0.17; + + for(int i = 0; i < 18; i++){ + v = new vector[]{put(r2*Math.cos(i*theta), 0.16, r2*Math.sin(i*theta)), + put(r2*Math.cos((i+1)*theta), 0.16, r2*Math.sin((i+1)*theta)), + put(r*Math.cos((i+1)*theta), 0.13, r*Math.sin((i+1)*theta)), + put(r*Math.cos(i*theta), 0.13, r*Math.sin(i*theta)) + }; + + tempVector.set(v[1]); + tempVector.subtract(v[0]); + tempVector0.set(v[0]); + tempVector1.set(v[1]); + tempVector3.set(v[3]); + tempVector1.add(tempVector); + + int p = i % 2; + for(int j = 0; j < p; j++){ + tempVector0.subtract(tempVector); + tempVector1.subtract(tempVector); + tempVector3.subtract(tempVector); + } + + if(teamNo == 0) + polygons[i + index] = new polygon3D(v, tempVector0.myClone(),tempVector1.myClone(), tempVector3.myClone(), mainThread.textures[15], 0.5f,1,1); + else + polygons[i + index] = new polygon3D(v, tempVector0.myClone(),tempVector1.myClone(), tempVector3.myClone(), mainThread.textures[16], 0.5f,1,1); + } + + index += 18; + + r = 0.12; + + for(int i = 0; i < 18; i++){ + v = new vector[]{put(r*Math.cos(i*theta), 0.18, r*Math.sin(i*theta)), + put(r*Math.cos((i+1)*theta), 0.18, r*Math.sin((i+1)*theta)), + put(r2*Math.cos((i+1)*theta), 0.16, r2*Math.sin((i+1)*theta)), + put(r2*Math.cos(i*theta), 0.16, r2*Math.sin(i*theta)) + }; + + tempVector.set(v[1]); + tempVector.subtract(v[0]); + tempVector0.set(v[0]); + tempVector1.set(v[1]); + tempVector3.set(v[3]); + tempVector1.add(tempVector); + + int p = i % 2; + for(int j = 0; j < p; j++){ + tempVector0.subtract(tempVector); + tempVector1.subtract(tempVector); + tempVector3.subtract(tempVector); + } + + polygons[i + index] = new polygon3D(v, tempVector0.myClone(),tempVector1.myClone(), tempVector3.myClone(), mainThread.textures[14], 0.5f,0.4f,1); + } + + index +=18; + + start.add(-0.05f,0,0); + r = 0.05; + r2 = 0.05; + for(int i = 0; i < 16; i++){ + v = new vector[]{ + put(r*Math.cos(i*delta), 0.18, r*Math.sin(i*delta)), + put(r*Math.cos((i+1)*delta), 0.18, r*Math.sin((i+1)*delta)), + put(r2*Math.cos((i+1)*delta), 0.38, r2*Math.sin((i+1)*delta)), + put(r2*Math.cos(i*delta), 0.38, r2*Math.sin(i*delta)) + + + + }; + + tempVector.set(v[1]); + tempVector.subtract(v[0]); + tempVector0.set(v[0]); + tempVector1.set(v[1]); + tempVector3.set(v[3]); + tempVector1.add(tempVector); + + int p = i % 2; + for(int j = 0; j < p; j++){ + tempVector0.subtract(tempVector); + tempVector1.subtract(tempVector); + tempVector3.subtract(tempVector); + } + + polygons[i + index] = new polygon3D(v, tempVector0.myClone(),tempVector1.myClone(), tempVector3.myClone(), mainThread.textures[12], 0.5f,1,1); + } + + index+=16; + double h = 0.31; + double r3 = 0.056; + v = new vector[16]; + for(int i = 0; i <16; i++){ + v[15 - i] = put(r3*Math.cos(i*delta), h, r3*Math.sin(i*delta)); + } + polygons[index] = new polygon3D(v, put(-r3, h, r3), put(r3, h, r3), put(-r3, h, -r3), mainThread.textures[17], 1f,1,1); + polygons[index].shadowBias = 15000; + index++; + + start.add(0.05f,0,-0); + + start.add(-0.05f,0,0); + r = 0.06; + r2 = 0.058; + for(int i = 0; i < 16; i++){ + v = new vector[]{put(r2*Math.cos(i*delta), 0.26, r2*Math.sin(i*delta)), + put(r2*Math.cos((i+1)*delta), 0.26, r2*Math.sin((i+1)*delta)), + put(r*Math.cos((i+1)*delta), 0.18, r*Math.sin((i+1)*delta)), + put(r*Math.cos(i*delta), 0.18, r*Math.sin(i*delta)) + }; + + tempVector.set(v[1]); + tempVector.subtract(v[0]); + tempVector0.set(v[0]); + tempVector1.set(v[1]); + tempVector3.set(v[3]); + tempVector1.add(tempVector); + + int p = i % 2; + for(int j = 0; j < p; j++){ + tempVector0.subtract(tempVector); + tempVector1.subtract(tempVector); + tempVector3.subtract(tempVector); + } + + change(0,0.26f,0, tempVector); + polygons[i + index] = new polygon3D(v, tempVector0.myClone(),tempVector1.myClone(), tempVector3.myClone(), mainThread.textures[12], 1f,0.25f,1); + polygons[i + index].textureScaledWidth = (int)(polygons[i + index].myTexture.width*0.5); + polygons[i + index].createShadeSpan(tempVector, v[0], v[1]); + } + start.add(0.05f,0,-0); + index+=16; + + + + + + + start.add(-0.05f,0,0); + r = 0.058; + r2 = 0.059; + for(int i = 0; i < 16; i++){ + v = new vector[]{put(r2*Math.cos(i*delta), 0.32, r2*Math.sin(i*delta)), + put(r2*Math.cos((i+1)*delta), 0.32, r2*Math.sin((i+1)*delta)), + put(r*Math.cos((i+1)*delta), 0.26, r*Math.sin((i+1)*delta)), + put(r*Math.cos(i*delta), 0.26, r*Math.sin(i*delta)) + }; + + tempVector.set(v[1]); + tempVector.subtract(v[0]); + tempVector0.set(v[0]); + tempVector1.set(v[1]); + tempVector3.set(v[3]); + tempVector1.add(tempVector); + + int p = i % 2; + for(int j = 0; j < p; j++){ + tempVector0.subtract(tempVector); + tempVector1.subtract(tempVector); + tempVector3.subtract(tempVector); + } + + change(0,0.32f,0, tempVector); + polygons[i + index] = new polygon3D(v, tempVector0.myClone(),tempVector1.myClone(), tempVector3.myClone(), mainThread.textures[12], 1f,0.25f,1); + polygons[i + index].textureScaledWidth = (int)(polygons[i + index].myTexture.width*0.5); + polygons[i + index].createShadeSpan(tempVector, v[0], v[1]); + } + start.add(0.05f,0,-0); + index+=16; + + + + + start.add(-0.05f,0,0); + r = 0.059; + r2 = 0.06; + for(int i = 0; i < 16; i++){ + v = new vector[]{put(r2*Math.cos(i*delta), 0.38, r2*Math.sin(i*delta)), + put(r2*Math.cos((i+1)*delta), 0.38, r2*Math.sin((i+1)*delta)), + put(r*Math.cos((i+1)*delta), 0.32, r*Math.sin((i+1)*delta)), + put(r*Math.cos(i*delta), 0.32, r*Math.sin(i*delta)) + }; + + tempVector.set(v[1]); + tempVector.subtract(v[0]); + tempVector0.set(v[0]); + tempVector1.set(v[1]); + tempVector3.set(v[3]); + tempVector1.add(tempVector); + + int p = i % 2; + for(int j = 0; j < p; j++){ + tempVector0.subtract(tempVector); + tempVector1.subtract(tempVector); + tempVector3.subtract(tempVector); + } + + change(0,0.38f,0, tempVector); + polygons[i + index] = new polygon3D(v, tempVector0.myClone(),tempVector1.myClone(), tempVector3.myClone(), mainThread.textures[12], 1f,0.25f,1); + polygons[i + index].textureScaledWidth = (int)(polygons[i + index].myTexture.width*0.5); + polygons[i + index].createShadeSpan(tempVector, v[0], v[1]); + + } + start.add(0.05f,0,-0); + index+=16; + + start.add(-0.05f,0,0); + r = 0.05; + r2 = 0.06; + for(int i = 0; i < 16; i++){ + v = new vector[]{ + put(r*Math.cos(i*delta), 0.38, r*Math.sin(i*delta)), + put(r*Math.cos((i+1)*delta), 0.38, r*Math.sin((i+1)*delta)), + put(r2*Math.cos((i+1)*delta), 0.38, r2*Math.sin((i+1)*delta)), + put(r2*Math.cos(i*delta), 0.38, r2*Math.sin(i*delta)) + }; + + tempVector.set(v[1]); + tempVector.subtract(v[0]); + tempVector0.set(v[0]); + tempVector1.set(v[1]); + tempVector3.set(v[3]); + tempVector1.add(tempVector); + + int p = i % 2; + for(int j = 0; j < p; j++){ + tempVector0.subtract(tempVector); + tempVector1.subtract(tempVector); + tempVector3.subtract(tempVector); + } + + polygons[i + index] = new polygon3D(v, tempVector0.myClone(),tempVector1.myClone(), tempVector3.myClone(), mainThread.textures[12], 0.5f,0.25f,1); + } + start.add(0.05f,0,-0); + index+=16; + + + + for(int i = 0; i < polygons.length; i++){ + polygons[i].findDiffuse(); + polygons[i].parentObject = this; + + } + } + + + //update the model + public void update(){ + + //process emerging from ground animation + if(centre.y < -0.5f){ + centre.y+=0.02f; + + if(centre.y > -0.5){ + for(int i = 0; i < polygons.length; i++){ + polygons[i].origin.y+=0.0000005; + polygons[i].rightEnd.y+=0.0000005; + polygons[i].bottomEnd.y+=0.0000005; + + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + polygons[i].vertex3D[j].y+=0.0000005; + } + + + + } + shadowvertex0.y+=0.0000005; + shadowvertex1.y+=0.0000005; + shadowvertex2.y+=0.0000005; + shadowvertex3.y+=0.0000005; + + centre.y = -0.5f; + }else{ + for(int i = 0; i < polygons.length; i++){ + polygons[i].origin.y+=0.02; + polygons[i].rightEnd.y+=0.02; + polygons[i].bottomEnd.y+=0.02; + + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + polygons[i].vertex3D[j].y+=0.02; + } + + + } + shadowvertex0.y+=0.02; + shadowvertex1.y+=0.02; + shadowvertex2.y+=0.02; + shadowvertex3.y+=0.02; + } + + //the building is invulnerable during emerging stage + currentHP = maxHP; + } + + if(underAttackCountDown > 0) + underAttackCountDown--; + + //check if power plant has been destroyed + if(currentHP <= 0){ + countDownToDeath--; + + if(countDownToDeath == 0){ + //spawn an explosion when the tank is destroyed + float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount]; + tempFloat[0] = centre.x; + tempFloat[1] = centre.y + 0.15f; + tempFloat[2] = centre.z; + tempFloat[3] = 3.5f; + tempFloat[4] = 1; + tempFloat[5] = 0; + tempFloat[6] = 7; + tempFloat[7] = this.height; + theAssetManager.explosionCount++; + theAssetManager.removeObject(this); + + + theBaseInfo.numberOfPowerPlant--; + + + + //removeFromGridMap(); + mainThread.gridMap.tiles[tileIndex[0]][0] = null; + mainThread.gridMap.tiles[tileIndex[1]][0] = null; + mainThread.gridMap.tiles[tileIndex[2]][0] = null; + mainThread.gridMap.tiles[tileIndex[3]][0] = null; + + mainThread.gridMap.tiles[tileIndex[0]][1] = null; + mainThread.gridMap.tiles[tileIndex[1]][1] = null; + mainThread.gridMap.tiles[tileIndex[2]][1] = null; + mainThread.gridMap.tiles[tileIndex[3]][1] = null; + + mainThread.gridMap.tiles[tileIndex[0]][2] = null; + mainThread.gridMap.tiles[tileIndex[1]][2] = null; + mainThread.gridMap.tiles[tileIndex[2]][2] = null; + mainThread.gridMap.tiles[tileIndex[3]][2] = null; + + mainThread.gridMap.tiles[tileIndex[0]][3] = null; + mainThread.gridMap.tiles[tileIndex[1]][3] = null; + mainThread.gridMap.tiles[tileIndex[2]][3] = null; + mainThread.gridMap.tiles[tileIndex[3]][3] = null; + + mainThread.gridMap.tiles[tileIndex[0]][4] = null; + mainThread.gridMap.tiles[tileIndex[1]][4] = null; + mainThread.gridMap.tiles[tileIndex[2]][4] = null; + mainThread.gridMap.tiles[tileIndex[3]][4] = null; + + if(teamNo != 0){ + mainThread.gridMap.tiles[tileIndex[4]][4] = null; + mainThread.gridMap.tiles[tileIndex[5]][4] = null; + mainThread.gridMap.tiles[tileIndex[6]][4] = null; + mainThread.gridMap.tiles[tileIndex[7]][4] = null; + mainThread.gridMap.tiles[tileIndex[8]][4] = null; + } + + if(attacker.teamNo != teamNo) + attacker.experience+=25; + return; + }else{ + + float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount]; + tempFloat[0] = centre.x + (float)Math.random()/2.5f - 0.2f; + tempFloat[1] = centre.y + 0.15f; + tempFloat[2] = centre.z + (float)Math.random()/2.5f - 0.2f; + tempFloat[3] = 1.5f; + tempFloat[4] = 1; + tempFloat[5] = 0; + tempFloat[6] = 6 + (gameData.getRandom()%4); + tempFloat[7] = this.height; + theAssetManager.explosionCount++; + + + } + } + + //processing repair event + if(isRepairing && currentHP >0){ + if(mainThread.frameIndex%8==0 && theBaseInfo.currentCredit > 0 && currentHP maxHP) + currentHP = maxHP; + } + } + + //mark itself on obstacle map + mainThread.gridMap.currentObstacleMap[tileIndex[0]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[1]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[2]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[3]] = false; + + + //update center in camera coordinate + tempCentre.set(centre); + tempCentre.subtract(camera.position); + tempCentre.rotate_XZ(camera.XZ_angle); + tempCentre.rotate_YZ(camera.YZ_angle); + tempCentre.updateLocation(); + + theAssetManager = mainThread.theAssetManager; + + //test if the palm tree is visible in camera point of view + if(visibleBoundary.contains(tempCentre.screenX, tempCentre.screenY) && isRevealed){ + visible = true; + + if(screenBoundary.contains(tempCentre.screenX, tempCentre.screenY)) + withinViewScreen = true; + else + withinViewScreen = false; + + tempshadowvertex0.set(shadowvertex0); + tempshadowvertex0.subtract(camera.position); + tempshadowvertex0.rotate_XZ(camera.XZ_angle); + tempshadowvertex0.rotate_YZ(camera.YZ_angle); + tempshadowvertex0.updateLocation(); + + tempshadowvertex1.set(shadowvertex1); + tempshadowvertex1.subtract(camera.position); + tempshadowvertex1.rotate_XZ(camera.XZ_angle); + tempshadowvertex1.rotate_YZ(camera.YZ_angle); + tempshadowvertex1.updateLocation(); + + tempshadowvertex2.set(shadowvertex2); + tempshadowvertex2.subtract(camera.position); + tempshadowvertex2.rotate_XZ(camera.XZ_angle); + tempshadowvertex2.rotate_YZ(camera.YZ_angle); + tempshadowvertex2.updateLocation(); + + tempshadowvertex3.set(shadowvertex3); + tempshadowvertex3.subtract(camera.position); + tempshadowvertex3.rotate_XZ(camera.XZ_angle); + tempshadowvertex3.rotate_YZ(camera.YZ_angle); + tempshadowvertex3.updateLocation(); + + + + //if the object is visible then draw it on the shadow buffer from light point of view + if(shadowBoundary1.contains(tempshadowvertex0.screenX, tempshadowvertex0.screenY) || + shadowBoundary1.contains(tempshadowvertex1.screenX, tempshadowvertex1.screenY) || + shadowBoundary1.contains(tempshadowvertex2.screenX, tempshadowvertex2.screenY) || + shadowBoundary1.contains(tempshadowvertex3.screenX, tempshadowvertex3.screenY) + ){ + for(int i = 0; i < polygons.length; i++){ + polygons[i].update_lightspace(); + + + } + + } + + //add this object to visible unit list + theAssetManager.visibleUnit[theAssetManager.visibleUnitCount] = this; + theAssetManager.visibleUnitCount++; + + + }else{ + visible = false; + } + + + //create vision for enemy commander + if(teamNo == 1){ + int xPos = boundary2D.x1/16 - 8 + 10; + int yPos = 127 - boundary2D.y1/16 - 8 + 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; + } + } + } + + visionBoundary.x = (int)(tempCentre.screenX - 800); + visionBoundary.y = (int)(tempCentre.screenY - 1000); + visionInsideScreen = camera.screen.intersects(visionBoundary); + + + if(visionInsideScreen){ + if(teamNo == 0){ + 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++; + } + } + + if(theAssetManager.minimapBitmap[tileIndex[0]] || + theAssetManager.minimapBitmap[tileIndex[1]] || + theAssetManager.minimapBitmap[tileIndex[2]] || + theAssetManager.minimapBitmap[tileIndex[3]] ) + isRevealed = true; + visible_minimap = isRevealed; + + if(visible_minimap){ + tempInt = theAssetManager.unitsForMiniMap[theAssetManager.unitsForMiniMapCount]; + tempInt[0] = teamNo; + 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] = 10000; + theAssetManager.unitsForMiniMapCount++; + + + //spawn smoke particle + if((mainThread.frameIndex + ID) % 5 ==0 && centre.y >= -0.5f){ + float[] tempFloat = theAssetManager.smokeEmmiterList[theAssetManager.smokeEmmiterCount]; + tempFloat[0] = centre.x - 0.053f + (float)(Math.random()/20) - 0.025f; + tempFloat[1] = centre.y + 0.45f; + tempFloat[2] = centre.z + (float)(Math.random()/20) - 0.025f; + tempFloat[3] = 1.5f; + tempFloat[4] = 1; + tempFloat[5] = 11; + tempFloat[6] = this.height; + theAssetManager.smokeEmmiterCount++; + } + + } + + } + + + //draw the model + public void draw(){ + if(!visible) + return; + for(int i = 0; i < polygons.length; i++){ + polygons[i].update(); + polygons[i].draw(); + } + } + + public vector getMovement(){ + return movenment; + } +} diff --git a/entity/refinery.java b/entity/refinery.java new file mode 100644 index 0000000..f5cf1c6 --- /dev/null +++ b/entity/refinery.java @@ -0,0 +1,1117 @@ +package entity; + +import java.awt.Rectangle; + +import core.*; +import enemyAI.enemyCommander; + +//the refinery plant model +public class refinery extends solidObject{ + + //the polygons of the model + private polygon3D[] polygons; + + public polygon3D storageCoverLeft; + public polygon3D storageCoverRight; + public int unloadOreCountDown; + public final int unloadOreTime = 190; + + public polygon3D[][] cargos; + + public float cargoX_left; + public float cargoY_left; + + public float cargoX_MaxRight; + + public static int maxHP = 750; + + public int countDownToDeath = 16; + + public boolean isBusy; + + public vector tempVector = new vector(0,0,0); + public vector tempVector0 = new vector(0,0,0); + public vector tempVector1 = new vector(0,0,0); + public vector tempVector2 = new vector(0,0,0); + public vector tempVector3 = new vector(0,0,0); + + + //refinery occupies 6 tiles + public int [] tileIndex = new int[6]; + + public int[] tempInt; + + public float[] tempFloat; + + public vector shadowvertex0, tempshadowvertex0,shadowvertex1, tempshadowvertex1,shadowvertex2, tempshadowvertex2,shadowvertex3, tempshadowvertex3; + + //a screen space boundary which is used to test if the object is visible from camera point of view + public final static Rectangle visibleBoundary = new Rectangle(-85,-85,920, 762); + + //a screen space boundary which is used to test if the entire object is within the screen + public final static Rectangle screenBoundary = new Rectangle(60,60,648, 402); + + //screen space boundary which is used to test if the shadow of the object is within the screen + public final static Rectangle shadowBoundary1 = new Rectangle(30,70,748, 482); + + //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,1600, 2000); + + //a bitmap representation of the vision of the refinery for enemy commander + public static boolean[] bitmapVisionForEnemy; + + //refinery never moves + public final static vector movenment = new vector(0,0,0); + + public baseInfo theBaseInfo; + + public static int intendedDeployLocation = -1; + + public goldMine nearestGoldMine; + + public refinery(float x, float y, float z, int teamNo){ + //uncontrollable unit, but act as a big sized static collidable agent + type = 102; + + currentHP = 750; + + if(teamNo == 0){ + isRevealed = true; + theBaseInfo = mainThread.pc.theBaseInfo; + }else{ + theBaseInfo = mainThread.ec.theBaseInfo; + } + + ID = globalUniqID++; + + theBaseInfo.numberOfRefinery++; + + this.teamNo = teamNo; + + currentCommand = this.StandBy; + + if(teamNo == 0){ + isRevealed = true; + } + + if(bitmapVisionForEnemy == null){ + bitmapVisionForEnemy = createBitmapVision(8); + } + + //create 2D boundary + boundary2D = new Rect((int)(x*64) - 24, (int)(z*64) + 16, 48, 32); + boundary2D.owner = this; + int centerX = (int)(x*64); + int centerY = (int)(z*64); + + tileIndex[0] = (centerX - 16)/16 + (127 - (centerY + 8)/16)*128; + tileIndex[1] = (centerX + 16)/16 + (127 - (centerY + 8)/16)*128; + tileIndex[2] = (centerX + 16)/16 + (127 - (centerY - 8)/16)*128; + tileIndex[3] = (centerX - 16)/16 + (127 - (centerY - 8)/16)*128; + tileIndex[4] = (centerX)/16 + (127 - (centerY + 8)/16)*128; + tileIndex[5] = (centerX)/16 + (127 - (centerY - 8)/16)*128; + + + mainThread.gridMap.tiles[tileIndex[0]][0] = this; + mainThread.gridMap.tiles[tileIndex[1]][0] = this; + mainThread.gridMap.tiles[tileIndex[2]][0] = this; + mainThread.gridMap.tiles[tileIndex[3]][0] = this; + mainThread.gridMap.tiles[tileIndex[4]][0] = this; + mainThread.gridMap.tiles[tileIndex[5]][0] = this; + + + mainThread.gridMap.tiles[tileIndex[0]][1] = this; + mainThread.gridMap.tiles[tileIndex[1]][1] = this; + mainThread.gridMap.tiles[tileIndex[2]][1] = this; + mainThread.gridMap.tiles[tileIndex[3]][1] = this; + mainThread.gridMap.tiles[tileIndex[4]][1] = this; + mainThread.gridMap.tiles[tileIndex[5]][1] = this; + + mainThread.gridMap.tiles[tileIndex[0]][2] = this; + mainThread.gridMap.tiles[tileIndex[1]][2] = this; + mainThread.gridMap.tiles[tileIndex[2]][2] = this; + mainThread.gridMap.tiles[tileIndex[3]][2] = this; + mainThread.gridMap.tiles[tileIndex[4]][2] = this; + mainThread.gridMap.tiles[tileIndex[5]][2] = this; + + mainThread.gridMap.tiles[tileIndex[0]][3] = this; + mainThread.gridMap.tiles[tileIndex[1]][3] = this; + mainThread.gridMap.tiles[tileIndex[2]][3] = this; + mainThread.gridMap.tiles[tileIndex[3]][3] = this; + mainThread.gridMap.tiles[tileIndex[4]][3] = this; + mainThread.gridMap.tiles[tileIndex[5]][3] = this; + + + mainThread.gridMap.tiles[tileIndex[0]][4] = this; + mainThread.gridMap.tiles[tileIndex[1]][4] = this; + mainThread.gridMap.tiles[tileIndex[2]][4] = this; + mainThread.gridMap.tiles[tileIndex[3]][4] = this; + mainThread.gridMap.tiles[tileIndex[4]][4] = this; + mainThread.gridMap.tiles[tileIndex[5]][4] = this; + + int tileIndex6 = tileIndex[5] + 128; + int tileIndex7 = tileIndex[5] + 128 - 1; + int tileIndex8 = tileIndex[5] + 128 + 1; + mainThread.gridMap.tiles[tileIndex6][4] = this; + mainThread.gridMap.tiles[tileIndex7][4] = this; + mainThread.gridMap.tiles[tileIndex8][4] = this; + + + //init model + start = new vector(x,y,z); + iDirection = new vector(1f,0,0); + jDirection = new vector(0,1f,0); + kDirection = new vector(0,0,1f); + + //define centre of the model in world coordinate + start = new vector(x,y,z); + centre = start.myClone(); + tempCentre = start.myClone(); + + shadowvertex0 =start.myClone(); + shadowvertex0.add(-0.45f,-0.2f, -0.4f); + tempshadowvertex0 = new vector(0,0,0); + + shadowvertex1 =start.myClone(); + shadowvertex1.add(-0.45f,-0.2f, 0.2f); + tempshadowvertex1 = new vector(0,0,0); + + shadowvertex2 =start.myClone(); + shadowvertex2.add(0.2f,-0.2f, -0.4f); + tempshadowvertex2 = new vector(0,0,0); + + shadowvertex3 =start.myClone(); + shadowvertex3.add(0.2f,-0.2f, 0.2f); + tempshadowvertex3 = new vector(0,0,0); + + + makePolygons(); + + } + + //create polygons + public void makePolygons(){ + polygons = new polygon3D[157 + 4 * 13]; + + int polyIndex; + + cargos = new polygon3D[5][13]; + float referenceX = -0.28f - 0.02f; + float referenceY = 0.34f - 0.012f; + + + + for(int i = 0; i < cargos.length; i++){ + + v = new vector[]{put(referenceX, referenceY, 0.1), put(referenceX+0.07, referenceY, 0.1), put(referenceX+0.06, referenceY-0.05, 0.1), put(referenceX+0.01, referenceY-0.05, 0.1)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 1,1f,1)); + cargos[i][0] = polygons[polyIndex]; + + if(i == 0){ + cargoX_left = v[0].x; + cargoY_left = v[0].y; + + cargoX_MaxRight = cargoX_left + 0.5f; + } + + v = new vector[]{put(referenceX, referenceY, 0.175), put(referenceX+0.07, referenceY, 0.175), put(referenceX+0.06, referenceY-0.05, 0.175), put(referenceX+0.01, referenceY-0.05, 0.175)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 1,1f,1)); + cargos[i][1] = polygons[polyIndex]; + + v = new vector[]{put(referenceX+0.01, referenceY-0.05, 0.18), put(referenceX+0.06, referenceY-0.05, 0.18), put(referenceX+0.07, referenceY, 0.18), put(referenceX, referenceY, 0.18)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 1,1f,1)); + cargos[i][2] = polygons[polyIndex]; + + v = new vector[]{put(referenceX+0.01, referenceY-0.05, 0.105), put(referenceX+0.06, referenceY-0.05, 0.105), put(referenceX+0.07, referenceY, 0.105), put(referenceX, referenceY, 0.105)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 1,1f,1)); + cargos[i][3] = polygons[polyIndex]; + + v = new vector[]{put(referenceX+0.07, referenceY, 0.1), put(referenceX+0.07, referenceY, 0.18), put(referenceX+0.06, referenceY-0.05, 0.18), put(referenceX+0.06, referenceY -0.05, 0.1)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 1,1f,1)); + cargos[i][4] = polygons[polyIndex]; + + v = new vector[]{put(referenceX+0.055, referenceY-0.05, 0.1), put(referenceX+0.055, referenceY-0.05, 0.18), put(referenceX+0.065, referenceY, 0.18), put(referenceX+0.065, referenceY, 0.1)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 1,1f,1)); + cargos[i][5] = polygons[polyIndex]; + + v = new vector[]{put(referenceX, referenceY, 0.18), put(referenceX, referenceY, 0.1), put(referenceX+0.01, referenceY-0.05, 0.1), put(referenceX+0.01, referenceY-0.05, 0.18)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 1,1f,1)); + cargos[i][6] = polygons[polyIndex]; + + v = new vector[]{put(referenceX+0.015, referenceY- 0.05, 0.18), put(referenceX+0.015, referenceY-0.05, 0.1), put(referenceX+0.005, referenceY, 0.1), put(referenceX+0.005, referenceY, 0.18)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 1,1f,1)); + cargos[i][7] = polygons[polyIndex]; + + v = new vector[]{put(referenceX, referenceY, 0.105), put(referenceX+0.07, referenceY, 0.105), put(referenceX+0.07, referenceY, 0.1), put(referenceX, referenceY, 0.1)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 1,0.2f,1)); + cargos[i][8] = polygons[polyIndex]; + + v = new vector[]{put(referenceX, referenceY, 0.18), put(referenceX+0.07, referenceY, 0.18), put(referenceX+0.07, referenceY, 0.175), put(referenceX, referenceY, 0.175)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 1,0.2f,1)); + cargos[i][9] = polygons[polyIndex]; + + v = new vector[]{put(referenceX, referenceY, 0.18), put(referenceX+0.005, referenceY, 0.18), put(referenceX+0.005, referenceY, 0.1), put(referenceX, referenceY, 0.1)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.2f,1f,1)); + cargos[i][10] = polygons[polyIndex]; + + v = new vector[]{put(referenceX+0.065, referenceY, 0.18), put(referenceX+0.07, referenceY, 0.18), put(referenceX+0.07, referenceY, 0.1), put(referenceX+0.065, referenceY, 0.1)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.2f,1f,1)); + cargos[i][11] = polygons[polyIndex]; + + v = new vector[]{put(referenceX+0.01, referenceY-0.01, 0.18), put(referenceX + 0.07, referenceY-0.01, 0.18), put(referenceX + 0.07, referenceY-0.01, 0.1), put(referenceX+0.01, referenceY-0.01, 0.1)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[34], 0.8f,1f,1)); + cargos[i][12] = polygons[polyIndex]; + + referenceX +=0.1f; + referenceY +=0.06f; + } + + v = new vector[]{put(-0.38, 0.3, -0.2), put(0.38, 0.3, -0.2), put(0.38, 0.3, -0.225), put(0.345, 0.3, -0.26), put(-0.345, 0.3, -0.26), put(-0.38, 0.3, -0.225)}; + polyIndex = addPolygon(polygons, new polygon3D(v, put(-0.38, 0.3, 0.26), put(0.38, 0.3, 0.26), put(-0.38, 0.3, -0.26), mainThread.textures[30], 1,1,1)); + polygons[polyIndex].shadowBias = 5000; + + v = new vector[]{put(-0.38, 0.3, 0.225), put(-0.345, 0.3, 0.26), put(0.345, 0.3, 0.26), put(0.38, 0.3, 0.225), put(0.38, 0.3, 0.2), put(-0.38, 0.3, 0.2)}; + polyIndex = addPolygon(polygons, new polygon3D(v, put(-0.38, 0.3, 0.26), put(0.38, 0.3, 0.26), put(-0.38, 0.3, -0.26), mainThread.textures[30], 1,1,1)); + polygons[polyIndex].shadowBias = 5000; + + v = new vector[]{put(-0.14, 0.3, 0.225), put(0.38, 0.3, 0.225), put(0.38, 0.3, -0.225), put(-0.14, 0.3, -0.225) }; + polyIndex = addPolygon(polygons, new polygon3D(v, put(-0.38, 0.3, 0.26), put(0.38, 0.3, 0.26), put(-0.38, 0.3, -0.26), mainThread.textures[30], 1,1,1)); + polygons[polyIndex].shadowBias = 5000; + + v = new vector[]{put(-0.38, 0.3, 0.225), put(-0.33, 0.3, 0.225), put(-0.33, 0.3, -0.225), put(-0.38, 0.3, -0.225) }; + polyIndex = addPolygon(polygons, new polygon3D(v, put(-0.38, 0.3, 0.26), put(0.38, 0.3, 0.26), put(-0.38, 0.3, -0.26), mainThread.textures[30], 1,1,1)); + polygons[polyIndex].shadowBias = 5000; + + v = new vector[]{put(-0.345, 0.3, 0.225), put(-0.14, 0.3, 0.225), put(-0.14, 0.3, -0.03), put(-0.345, 0.3, -0.03) }; + polyIndex = addPolygon(polygons, new polygon3D(v, put(-0.38, 0.3, 0.26), put(0.38, 0.3, 0.26), put(-0.38, 0.3, -0.26), mainThread.textures[30], 1,1,1)); + polygons[polyIndex].shadowBias = 5000; + + + v = new vector[]{put(-0.345, 0.3, -0.26), put(0.345, 0.3, -0.26), put(0.345, 0.28, -0.26), put(-0.345, 0.28, -0.26)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[30], 1,1f,1)); + + v = new vector[]{put(-0.345, 0.28,0.26), put(0.345, 0.28, 0.26), put(0.345, 0.3, 0.26), put(-0.345, 0.3, 0.26)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[30], 1,1f,1)); + + v = new vector[]{put(-0.38, 0.3, 0.225), put(-0.38, 0.3, -0.225), put(-0.38, 0.28, -0.225), put(-0.38, 0.28, 0.225)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[30], 1,1f,1)); + + v = new vector[]{put(0.38, 0.28, 0.225), put(0.38, 0.28, -0.225), put(0.38, 0.3, -0.225), put(0.38, 0.3, 0.225)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[30], 1,1f,1)); + + v = new vector[]{put(-0.345, 0.3, 0.26), put(-0.38, 0.3, 0.225), put(-0.38, 0.28, 0.225), put(-0.345, 0.28, 0.26)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[30], 1,1f,1)); + + v = new vector[]{put(0.345, 0.28, 0.26), put(0.38, 0.28, 0.225), put(0.38, 0.3, 0.225), put(0.345, 0.3, 0.26)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[30], 1,1f,1)); + + v = new vector[]{put(-0.345, 0.28, -0.26), put(-0.38, 0.28, -0.225), put(-0.38, 0.3, -0.225), put(-0.345, 0.3, -0.26)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[30], 1,1f,1)); + + v = new vector[]{put(0.345, 0.3, -0.26), put(0.38, 0.3, -0.225), put(0.38, 0.28, -0.225), put(0.345, 0.28, -0.26)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[30], 1,1f,1)); + + texture stripeTExture = mainThread.textures[31]; + if(teamNo == 1) + stripeTExture = mainThread.textures[32]; + + + float h = 0.315f; + float h2 = 0.29f; + v = new vector[]{put(-0.34, h, -0.03), put(-0.13f, h, -0.03), put(-0.13, h, -0.05), put(-0.34, h, -0.05)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), stripeTExture, 4,0.5f,1)); + + v = new vector[]{put(-0.34, h, -0.2), put(-0.13f, h, -0.2), put(-0.13, h, -0.22), put(-0.34, h, -0.22)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), stripeTExture, 4,0.5f,1)); + + v = new vector[]{put(-0.13, h, -0.05), put(-0.13, h, -0.2), put(-0.15, h, -0.2), put(-0.15, h, -0.05)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), stripeTExture, 3,0.5f,1)); + + v = new vector[]{put(-0.32, h, -0.05), put(-0.32, h, -0.2), put(-0.34, h, -0.2), put(-0.34, h, -0.05)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), stripeTExture, 3,0.5f,1)); + + v = new vector[]{put(-0.34, h, -0.03), put(-0.34, h, -0.22), put(-0.34, h2, -0.22), put(-0.34, h2, -0.03)}; + addPolygon(polygons, new polygon3D(v, put(-0.34, h, -0.05), put(-0.34, h, -0.2), put(-0.34, h2, -0.05), stripeTExture, 3f,0.5f,1)); + + v = new vector[]{put(-0.32, h2, -0.03), put(-0.32, h2, -0.22), put(-0.32, h, -0.22), put(-0.32, h, -0.03)}; + addPolygon(polygons, new polygon3D(v, put(-0.32, h, -0.2), put(-0.32, h, -0.05), put(-0.32, h2, -0.25), stripeTExture, 3f,0.5f,1)); + + v = new vector[]{put(-0.15, h, -0.03), put(-0.15, h, -0.22), put(-0.15, h2, -0.22), put(-0.15, h2, -0.03)}; + addPolygon(polygons, new polygon3D(v, put(-0.15, h, -0.05), put(-0.15, h, -0.2), put(-0.15, h2, -0.05), stripeTExture, 3f,0.5f,1)); + + v = new vector[]{put(-0.13, h2, -0.03), put(-0.13, h2, -0.22), put(-0.13, h, -0.22), put(-0.13, h, -0.03)}; + addPolygon(polygons, new polygon3D(v, put(-0.13, h, -0.2), put(-0.13, h, -0.05), put(-0.13, h2, -0.2), stripeTExture, 3f,0.5f,1)); + + v = new vector[]{put(-0.34, h, -0.05), put(-0.13, h, -0.05), put(-0.13, h2, -0.05), put(-0.34, h2, -0.05)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), stripeTExture, 4,0.5f,1)); + + v = new vector[]{put(-0.34, h, -0.22), put(-0.13, h, -0.22), put(-0.13, h2, -0.22), put(-0.34, h2, -0.22)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), stripeTExture, 4,0.5f,1)); + + v = new vector[]{put(-0.34, h2, -0.03), put(-0.13, h2, -0.03), put(-0.13, h, -0.03), put(-0.34, h, -0.03)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), stripeTExture, 4,0.5f,1)); + + v = new vector[]{put(-0.34, h2, -0.2), put(-0.13, h2, -0.2), put(-0.13, h, -0.2), put(-0.34, h, -0.2)}; + polyIndex = addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), stripeTExture, 4,0.5f,1)); + + + v = new vector[]{put(-0.32, 0.3, -0.05), put(-0.235, 0.3, -0.05), put(-0.235, 0.3, -0.2), put(-0.32, 0.3, -0.2)}; + storageCoverLeft = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[33], 4,4,1); + storageCoverLeft.shadowBias = 5000; + addPolygon(polygons, storageCoverLeft); + + + v = new vector[]{put(-0.235, 0.3, -0.05), put(-0.15, 0.3, -0.05), put(-0.15, 0.3, -0.2), put(-0.235, 0.3, -0.2)}; + storageCoverRight = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[33], 4,4f,1); + storageCoverRight.shadowBias = 5000; + addPolygon(polygons, storageCoverRight); + + v = new vector[]{put(-0.34, 0.27, -0.01), put(-0.13, 0.27, -0.01), put(-0.13, 0.27, -0.24), put(-0.34, 0.27, -0.24)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[34], 1,1f,3)); + + v = new vector[]{put(-0.34,0.3,0.08), put(-0.34,0.3,0.2), put(-0.2,0.4,0.2), put(-0.2,0.4,0.08)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.5f,0.3f,1)); + + v = new vector[]{put(-0.34,0.3,0.08), put(-0.2,0.4,0.08), put(-0.2,0.3,0.08)}; + addPolygon(polygons, new polygon3D(v, put(-0.34,0.4,0.08), put(-0.2,0.4,0.08), put(-0.34,0.3,0.08), mainThread.textures[35], 0.5f,0.3f,1)); + + v = new vector[]{put(-0.2,0.3,0.2), put(-0.2,0.4,0.2), put(-0.34,0.3,0.2)}; + addPolygon(polygons, new polygon3D(v, put(-0.34,0.4,0.2), put(-0.2,0.4,0.2), put(-0.34,0.3,0.2), mainThread.textures[35], 0.5f,0.3f,1)); + + v = new vector[]{put(-0.34,0.3,0.19), put(-0.2,0.4,0.19), put(-0.2,0.3,0.19)}; + addPolygon(polygons, new polygon3D(v, put(-0.34,0.4,0.19), put(-0.2,0.4,0.19), put(-0.34,0.3,0.19), mainThread.textures[35], 0.5f,0.3f,1)); + + v = new vector[]{put(-0.2,0.3,0.09), put(-0.2,0.4,0.09), put(-0.34,0.3,0.09)}; + addPolygon(polygons, new polygon3D(v, put(-0.34,0.4,0.09), put(-0.2,0.4,0.09), put(-0.34,0.3,0.09), mainThread.textures[35], 0.5f,0.3f,1)); + + v = new vector[]{put(-0.2,0.4,0.08), put(-0.2,0.4,0.09), put(-0.2,0.3,0.09), put(-0.2,0.3,0.08)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.1f,0.5f,1)); + + v = new vector[]{put(-0.2,0.4,0.19), put(-0.2,0.4,0.2), put(-0.2,0.3,0.2), put(-0.2,0.3,0.19)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.1f,0.5f,1)); + + v = new vector[]{put(-0.2,0.4,0.08), put(-0.2,0.4,0.2), put(-0.2,0.39,0.2), put(-0.2,0.39,0.08)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.5f,0.1f,1)); + + v = new vector[]{put(-0.22, 0.35, 0.09), put(0.23, 0.6, 0.09), put(0.23, 0.58, 0.09), put(-0.22, 0.33, 0.09)}; + addPolygon(polygons, new polygon3D(v, put(-0.34,0.4,0.09), put(-0.2,0.4,0.09), put(-0.34,0.3,0.09), mainThread.textures[35], 0.5f,0.3f,1)); + + v = new vector[]{put(-0.22, 0.33, 0.1), put(0.23, 0.58, 0.1), put(0.23, 0.6, 0.1), put(-0.22, 0.35, 0.1)}; + addPolygon(polygons, new polygon3D(v, put(-0.34,0.4,0.1), put(-0.2,0.4,0.1), put(-0.34,0.3,0.1), mainThread.textures[35], 0.5f,0.3f,1)); + + v = new vector[]{put(-0.22, 0.35, 0.09), put(-0.22, 0.35, 0.1), put(0.23, 0.6, 0.1), put(0.23, 0.6, 0.09)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.1f,1f,1)); + + v = new vector[]{put(-0.22, 0.35, 0.18), put(0.23, 0.6, 0.18), put(0.23, 0.58, 0.18), put(-0.22, 0.33, 0.18)}; + addPolygon(polygons, new polygon3D(v, put(-0.34,0.4,0.18), put(-0.2,0.4,0.18), put(-0.34,0.3,0.18), mainThread.textures[35], 0.5f,0.3f,1)); + + v = new vector[]{put(-0.22, 0.33, 0.19), put(0.23, 0.58, 0.19), put(0.23, 0.6, 0.19), put(-0.22, 0.35, 0.19)}; + addPolygon(polygons, new polygon3D(v, put(-0.34,0.4,0.19), put(-0.2,0.4,0.19), put(-0.34,0.3,0.19), mainThread.textures[35], 0.5f,0.3f,1)); + + v = new vector[]{put(-0.22, 0.35, 0.18), put(-0.22, 0.35, 0.19), put(0.23, 0.6, 0.19), put(0.23, 0.6, 0.18)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.1f,1f,1)); + + v = new vector[]{put(0.16, 0.65, 0.05), put(0.35, 0.75, 0.05), put(0.35, 0.3, 0.05), put(0.16, 0.3, 0.05)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), put(0.35, 0.65, 0.05), v[3].myClone(), mainThread.textures[36], 1f,1f,1)); + + v = new vector[]{put(0.16, 0.3, 0.23), put(0.35, 0.3, 0.23), put(0.35, 0.75, 0.23), put(0.16, 0.65, 0.23)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), put(0.35, 0.65, 0.23), v[3].myClone(), mainThread.textures[36], 1f,2f,1)); + + v = new vector[]{put(0.35, 0.75, 0.05), put(0.35, 0.75, 0.23), put(0.35, 0.3, 0.23), put(0.35, 0.3, 0.05)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), put(0.35, 0.65, 0.23), v[3].myClone(), mainThread.textures[36], 1f,2f,1)); + + v = new vector[]{put(0.16, 0.5, 0.23), put(0.16, 0.5, 0.05), put(0.16, 0.3, 0.05), put(0.16, 0.3, 0.23)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[36], 1f,1f,1)); + + v = new vector[]{put(0.16, 0.5, 0.05), put(0.16, 0.5, 0.23), put(0.34, 0.6, 0.23), put(0.34, 0.6, 0.05)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 1f,1f,1)); + + v = new vector[]{put(0.16, 0.65, 0.23), put(0.16, 0.65, 0.05), put(0.16, 0.6, 0.05), put(0.16, 0.6, 0.23)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[36], 1f,0.5f,1)); + + v = new vector[]{put(0.16, 0.6, 0.23), put(0.16, 0.6, 0.19), put(0.16, 0.5, 0.19), put(0.16, 0.5, 0.23)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[36], 0.2f,0.5f,1)); + + v = new vector[]{put(0.16, 0.6, 0.09), put(0.16, 0.6, 0.05), put(0.16, 0.5, 0.05), put(0.16, 0.5, 0.09)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[36], 0.2f,0.5f,1)); + + v = new vector[]{put(0.16, 0.65, 0.19), put(0.35, 0.75, 0.19), put(0.35, 0.3, 0.19), put(0.16, 0.3, 0.19)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), put(0.35, 0.65, 0.19), v[3].myClone(), mainThread.textures[36], 1f,1f,1)); + + v = new vector[]{put(0.16, 0.3, 0.09), put(0.35, 0.3, 0.09), put(0.35, 0.75, 0.09), put(0.16, 0.65, 0.09)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), put(0.35, 0.65, 0.09), v[3].myClone(), mainThread.textures[36], 1f,2f,1)); + + v = new vector[]{put(0.15, 0.66, 0.24), put(0.36, 0.76, 0.24), put(0.36, 0.76, 0.04), put(0.15, 0.66, 0.04)}; + addPolygon(polygons, new polygon3D(v, v[1].myClone(), v[2].myClone(), v[0].myClone(), mainThread.textures[37], 1f,2f,1)); + + v = new vector[]{put(0.15, 0.66, 0.04), put(0.36, 0.76, 0.04), put(0.36, 0.75, 0.04), put(0.15, 0.65, 0.04)}; + addPolygon(polygons, new polygon3D(v, v[1].myClone(), v[2].myClone(), v[0].myClone(), mainThread.textures[37], 1f,1f,1)); + + v = new vector[]{put(0.15, 0.65, 0.24), put(0.36, 0.75, 0.24), put(0.36, 0.76, 0.24), put(0.15, 0.66, 0.24)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[37], 1f,1f,1)); + + v = new vector[]{put(0.36, 0.76, 0.04), put(0.36, 0.76, 0.24), put(0.36, 0.75, 0.24), put(0.36, 0.75, 0.04)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[37], 1f,1f,1)); + + v = new vector[]{put(0.15, 0.66, 0.24), put(0.15, 0.66, 0.04), put(0.15, 0.65, 0.04), put(0.15, 0.65, 0.24)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[37], 1f,1f,1)); + + v = new vector[]{put(0.18, 0.58, 0.05), put(0.33, 0.58, 0.05), put(0.33, 0.5, -0.15), put(0.18, 0.5, -0.15)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[37], 0.8f,1f,1)); + + v = new vector[]{put(0.18, 0.5, -0.15), put(0.33, 0.5, -0.15), put(0.33, 0.49, -0.15), put(0.18, 0.49, -0.15)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[37], 1f,1f,1)); + + v = new vector[]{put(0.33, 0.5, -0.15), put(0.33, 0.58, 0.05), put(0.33, 0.57, 0.05), put(0.33, 0.49, -0.15)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[37], 1f,1f,1)); + + v = new vector[]{put(0.18, 0.49, -0.15), put(0.18, 0.57, 0.05), put(0.18, 0.58, 0.05), put(0.18, 0.5, -0.15)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[37], 1f,1f,1)); + + v = new vector[]{put(0.19, 0.5, -0.14), put(0.32, 0.5, -0.14), put(0.32, 0.43, -0.14), put(0.19, 0.43, -0.14)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[37], 1f,0.5f,1)); + + v = new vector[]{put(0.32, 0.5, -0.14), put(0.32, 0.58, 0.05), put(0.32, 0.43, 0.05), put(0.32, 0.43, -0.14)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), put(0.32, 0.5, 0.05), v[3].myClone(), mainThread.textures[36], 1f,0.5f,1)); + + v = new vector[]{put(0.19, 0.43, -0.14), put(0.19, 0.43, 0.05), put(0.19, 0.58, 0.05), put(0.19, 0.5, -0.14)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), put(0.19, 0.5, 0.05), v[3].myClone(), mainThread.textures[36], 1f,0.5f,1)); + + + v = new vector[]{put(0.3, 0.43, -0.14), put(0.32, 0.43, -0.14), put(0.32, 0.3, -0.14), put(0.3, 0.3, -0.14)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[36], 0.2f,1f,1)); + + v = new vector[]{put(0.3, 0.3, -0.12), put(0.32, 0.3, -0.12), put(0.32, 0.43, -0.12) ,put(0.3, 0.43, -0.12)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[36], 0.2f,1f,1)); + + v = new vector[]{put(0.32, 0.43, -0.14), put(0.32, 0.43, -0.12), put(0.32, 0.3, -0.12), put(0.32, 0.3, -0.14)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[36], 0.2f,1f,1)); + + v = new vector[]{put(0.3, 0.3, -0.14), put(0.3, 0.3, -0.12), put(0.3, 0.43, -0.12), put(0.3, 0.43, -0.14)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[36], 0.2f,1f,1)); + + + v = new vector[]{put(0.19, 0.43, -0.14), put(0.21, 0.43, -0.14), put(0.21, 0.3, -0.14), put(0.19, 0.3, -0.14)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[36], 0.2f,1f,1)); + + v = new vector[]{put(0.19, 0.3, -0.12), put(0.21, 0.3, -0.12), put(0.21, 0.43, -0.12) ,put(0.19, 0.43, -0.12)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[36], 0.2f,1f,1)); + + v = new vector[]{put(0.21, 0.43, -0.14), put(0.21, 0.43, -0.12), put(0.21, 0.3, -0.12), put(0.21, 0.3, -0.14)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[36], 0.2f,1f,1)); + + v = new vector[]{put(0.19, 0.3, -0.14), put(0.19, 0.3, -0.12), put(0.19, 0.43, -0.12), put(0.19, 0.43, -0.14)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[36], 0.2f,1f,1)); + + + + + start.add(0.27f,0.5f,0.14f); + double r = 0.028; + + double delta = Math.PI/8; + for(int i = 0; i < 16; i++){ + v = new vector[]{put(r*Math.cos(i*delta), 0.42, r*Math.sin(i*delta)), + put(r*Math.cos((i+1)*delta), 0.42, r*Math.sin((i+1)*delta)), + put(r*Math.cos((i+1)*delta), 0.2, r*Math.sin((i+1)*delta)), + put(r*Math.cos(i*delta), 0.2, r*Math.sin(i*delta)) + }; + + tempVector.set(v[1]); + tempVector.subtract(v[0]); + tempVector0.set(v[0]); + tempVector1.set(v[1]); + tempVector3.set(v[3]); + tempVector1.add(tempVector); + + int p = i % 2; + for(int j = 0; j < p; j++){ + tempVector0.subtract(tempVector); + tempVector1.subtract(tempVector); + tempVector3.subtract(tempVector); + } + + change(0,0.42f,0, tempVector); + polyIndex = addPolygon(polygons, new polygon3D(v, tempVector0.myClone(),tempVector1.myClone(), tempVector3.myClone(), mainThread.textures[40], 1f,2f,1)); + polygons[polyIndex].textureScaledWidth = (int)(polygons[polyIndex].myTexture.width*0.5); + polygons[polyIndex].createShadeSpan(tempVector, v[0].myClone(), v[1]); + + } + + double r2 = 0.028; + r = 0.02; + for(int i = 0; i < 16; i++){ + v = new vector[]{ + put(r*Math.cos(i*delta), 0.42, r*Math.sin(i*delta)), + put(r*Math.cos((i+1)*delta), 0.42, r*Math.sin((i+1)*delta)), + put(r2*Math.cos((i+1)*delta), 0.42, r2*Math.sin((i+1)*delta)), + put(r2*Math.cos(i*delta), 0.42, r2*Math.sin(i*delta)) + }; + + + + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[40], 1f,1f,1)); + } + + r = 0.02; + r2 = 0.02; + for(int i = 0; i < 16; i++){ + v = new vector[]{ + put(r*Math.cos(i*delta), 0.2, r*Math.sin(i*delta)), + put(r*Math.cos((i+1)*delta), 0.2, r*Math.sin((i+1)*delta)), + put(r2*Math.cos((i+1)*delta), 0.42, r2*Math.sin((i+1)*delta)), + put(r2*Math.cos(i*delta), 0.42, r2*Math.sin(i*delta)) + + + }; + + tempVector.set(v[1]); + tempVector.subtract(v[0]); + tempVector0.set(v[0]); + tempVector1.set(v[1]); + tempVector3.set(v[3]); + tempVector1.add(tempVector); + + int p = i % 2; + for(int j = 0; j < p; j++){ + tempVector0.subtract(tempVector); + tempVector1.subtract(tempVector); + tempVector3.subtract(tempVector); + } + + addPolygon(polygons, new polygon3D(v, tempVector0.myClone(),tempVector1.myClone(), tempVector3.myClone(), mainThread.textures[40], 0.5f,1,1)); + } + + start.add(-0.27f,-0.5f,-0.14f); + + + v = new vector[]{put(-0.095, 0.42, 0.09), put(-0.08, 0.42, 0.09), put(-0.08, 0.3, 0.09), put(-0.095, 0.3, 0.09)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.1f,1f,1)); + + v = new vector[]{put(-0.095, 0.3, 0.1), put(-0.08, 0.3, 0.1), put(-0.08, 0.42, 0.1), put(-0.095, 0.42, 0.1)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.1f,1f,1)); + + v = new vector[]{put(-0.08, 0.42, 0.09), put(-0.08, 0.42, 0.1), put(-0.08, 0.3, 0.1), put(-0.08, 0.3, 0.09)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.1f,1f,1)); + + v = new vector[]{put(-0.095, 0.3, 0.09), put(-0.095, 0.3, 0.1), put(-0.095, 0.42, 0.1), put(-0.095, 0.42, 0.09)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.1f,1f,1)); + + v = new vector[]{put(-0.095, 0.42, 0.18), put(-0.08, 0.42, 0.18), put(-0.08, 0.3, 0.18), put(-0.095, 0.3, 0.18)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.1f,1f,1)); + + v = new vector[]{put(-0.095, 0.3, 0.19), put(-0.08, 0.3, 0.19), put(-0.08, 0.42, 0.19), put(-0.095, 0.42, 0.19)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.1f,1f,1)); + + v = new vector[]{put(-0.08, 0.42, 0.18), put(-0.08, 0.42, 0.19), put(-0.08, 0.3, 0.19), put(-0.08, 0.3, 0.18)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.1f,1f,1)); + + v = new vector[]{put(-0.095, 0.3, 0.18), put(-0.095, 0.3, 0.19), put(-0.095, 0.42, 0.19), put(-0.095, 0.42, 0.18)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.1f,1f,1)); + + start.add(0,-0.01f,0); + v = new vector[]{put(-0.08, 0.365, 0.1), put(-0.08, 0.365, 0.18), put(-0.08, 0.35, 0.18), put(-0.08, 0.35, 0.1)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 1f,0.1f,1)); + + v = new vector[]{put(-0.095, 0.35, 0.1), put(-0.095, 0.35, 0.18), put(-0.095, 0.365, 0.18), put(-0.095, 0.365, 0.1)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 1f,0.1f,1)); + + v = new vector[]{put(-0.095, 0.365, 0.1), put(-0.095, 0.365, 0.18), put(-0.08, 0.365, 0.18), put(-0.08, 0.365, 0.1)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 1f,0.1f,1)); + + v = new vector[]{put(-0.08, 0.35, 0.1), put(-0.08, 0.35, 0.18), put(-0.095, 0.35, 0.18), put(-0.095, 0.35, 0.1)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 1f,0.1f,1)); + start.add(0,0.01f,0); + + start.add(0.13f,0,0); + v = new vector[]{put(-0.095, 0.48, 0.09), put(-0.08, 0.48, 0.09), put(-0.08, 0.3, 0.09), put(-0.095, 0.3, 0.09)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.1f,1f,1)); + + v = new vector[]{put(-0.095, 0.3, 0.1), put(-0.08, 0.3, 0.1), put(-0.08, 0.48, 0.1), put(-0.095, 0.48, 0.1)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.1f,1f,1)); + + v = new vector[]{put(-0.08, 0.48, 0.09), put(-0.08, 0.48, 0.1), put(-0.08, 0.3, 0.1), put(-0.08, 0.3, 0.09)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.1f,1f,1)); + + v = new vector[]{put(-0.095, 0.3, 0.09), put(-0.095, 0.3, 0.1), put(-0.095, 0.48, 0.1), put(-0.095, 0.48, 0.09)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.1f,1f,1)); + + v = new vector[]{put(-0.095, 0.48, 0.18), put(-0.08, 0.48, 0.18), put(-0.08, 0.3, 0.18), put(-0.095, 0.3, 0.18)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.1f,1f,1)); + + v = new vector[]{put(-0.095, 0.3, 0.19), put(-0.08, 0.3, 0.19), put(-0.08, 0.48, 0.19), put(-0.095, 0.48, 0.19)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.1f,1f,1)); + + v = new vector[]{put(-0.08, 0.48, 0.18), put(-0.08, 0.48, 0.19), put(-0.08, 0.3, 0.19), put(-0.08, 0.3, 0.18)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.1f,1f,1)); + + v = new vector[]{put(-0.095, 0.3, 0.18), put(-0.095, 0.3, 0.19), put(-0.095, 0.48, 0.19), put(-0.095, 0.48, 0.18)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 0.1f,1f,1)); + + start.add(0, 0.05f,0); + + v = new vector[]{put(-0.08, 0.365, 0.1), put(-0.08, 0.365, 0.18), put(-0.08, 0.35, 0.18), put(-0.08, 0.35, 0.1)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 1f,0.1f,1)); + + v = new vector[]{put(-0.095, 0.35, 0.1), put(-0.095, 0.35, 0.18), put(-0.095, 0.365, 0.18), put(-0.095, 0.365, 0.1)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 1f,0.1f,1)); + + v = new vector[]{put(-0.095, 0.365, 0.1), put(-0.095, 0.365, 0.18), put(-0.08, 0.365, 0.18), put(-0.08, 0.365, 0.1)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 1f,0.1f,1)); + + v = new vector[]{put(-0.08, 0.35, 0.1), put(-0.08, 0.35, 0.18), put(-0.095, 0.35, 0.18), put(-0.095, 0.35, 0.1)}; + addPolygon(polygons, new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[35], 1f,0.1f,1)); + + start.add(-0.13f,-0.05f,0); + + for(int i = 0; i < polygons.length; i++){ + polygons[i].findDiffuse(); + polygons[i].parentObject = this; + + } + + theAssetManager = mainThread.theAssetManager; + double distance = 10; + for(int i = 0; i < mainThread.theAssetManager.goldMines.length; i++){ + if(mainThread.theAssetManager.goldMines[i] == null) + continue; + + double newDistance = getDistance(mainThread.theAssetManager.goldMines[i]); + if(newDistance < distance && mainThread.theAssetManager.goldMines[i].goldDeposite > 1){ + distance = newDistance; + nearestGoldMine = theAssetManager.goldMines[i]; + } + } + + } + + public int addPolygon(polygon3D[] polys, polygon3D poly){ + for(int i = 0; i < polys.length; i++){ + if(polys[i] == null){ + polys[i] = poly; + return i; + } + } + return -1; + } + + + //update the model + public void update(){ + //process emerging from ground animation + if(centre.y < -0.79f){ + centre.y+=0.02f; + + float delta_h = 0.02f; + if(centre.y > -0.79f){ + delta_h = 0.0000007f; + centre.y = -0.79f; + } + + cargoY_left+=delta_h; + + for(int i = 0; i < polygons.length; i++){ + polygons[i].origin.y+=delta_h; + polygons[i].rightEnd.y+=delta_h; + polygons[i].bottomEnd.y+=delta_h; + + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + polygons[i].vertex3D[j].y+=delta_h; + } + + + } + shadowvertex0.y+=delta_h; + shadowvertex1.y+=delta_h; + shadowvertex2.y+=delta_h; + shadowvertex3.y+=delta_h; + + + //the building is invulnerable during emerging stage + currentHP = maxHP; + } + + if(underAttackCountDown > 0) + underAttackCountDown--; + + //check if power plant has been destroyed + if(currentHP <= 0){ + countDownToDeath--; + + if(countDownToDeath == 0){ + //spawn an explosion when the object is destroyed + float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount]; + tempFloat[0] = centre.x; + tempFloat[1] = centre.y + 0.45f; + tempFloat[2] = centre.z; + tempFloat[3] = 3.5f; + tempFloat[4] = 1; + tempFloat[5] = 0; + tempFloat[6] = 7; + tempFloat[7] = this.height; + theAssetManager.explosionCount++; + theAssetManager.removeObject(this); + + + //removeFromGridMap(); + mainThread.gridMap.tiles[tileIndex[0]][0] = null; + mainThread.gridMap.tiles[tileIndex[1]][0] = null; + mainThread.gridMap.tiles[tileIndex[2]][0] = null; + mainThread.gridMap.tiles[tileIndex[3]][0] = null; + mainThread.gridMap.tiles[tileIndex[4]][0] = null; + mainThread.gridMap.tiles[tileIndex[5]][0] = null; + + + mainThread.gridMap.tiles[tileIndex[0]][1] = null; + mainThread.gridMap.tiles[tileIndex[1]][1] = null; + mainThread.gridMap.tiles[tileIndex[2]][1] = null; + mainThread.gridMap.tiles[tileIndex[3]][1] = null; + mainThread.gridMap.tiles[tileIndex[4]][1] = null; + mainThread.gridMap.tiles[tileIndex[5]][1] = null; + + mainThread.gridMap.tiles[tileIndex[0]][2] = null; + mainThread.gridMap.tiles[tileIndex[1]][2] = null; + mainThread.gridMap.tiles[tileIndex[2]][2] = null; + mainThread.gridMap.tiles[tileIndex[3]][2] = null; + mainThread.gridMap.tiles[tileIndex[4]][2] = null; + mainThread.gridMap.tiles[tileIndex[5]][2] = null; + + mainThread.gridMap.tiles[tileIndex[0]][3] = null; + mainThread.gridMap.tiles[tileIndex[1]][3] = null; + mainThread.gridMap.tiles[tileIndex[2]][3] = null; + mainThread.gridMap.tiles[tileIndex[3]][3] = null; + mainThread.gridMap.tiles[tileIndex[4]][3] = null; + mainThread.gridMap.tiles[tileIndex[5]][3] = null; + + + mainThread.gridMap.tiles[tileIndex[0]][4] = null; + mainThread.gridMap.tiles[tileIndex[1]][4] = null; + mainThread.gridMap.tiles[tileIndex[2]][4] = null; + mainThread.gridMap.tiles[tileIndex[3]][4] = null; + mainThread.gridMap.tiles[tileIndex[4]][4] = null; + mainThread.gridMap.tiles[tileIndex[5]][4] = null; + + int tileIndex6 = tileIndex[5] + 128; + int tileIndex7 = tileIndex[5] + 128 - 1; + int tileIndex8 = tileIndex[5] + 128 + 1; + mainThread.gridMap.tiles[tileIndex6][4] = null; + mainThread.gridMap.tiles[tileIndex7][4] = null; + mainThread.gridMap.tiles[tileIndex8][4] = null; + + if(teamNo == 0) + mainThread.pc.theBaseInfo.numberOfRefinery--; + else + mainThread.ec.theBaseInfo.numberOfRefinery--; + + if(attacker.teamNo != teamNo) + attacker.experience+=35; + + return; + }else{ + + float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount]; + tempFloat[0] = centre.x + (float)Math.random()*0.6f - 0.3f; + tempFloat[1] = centre.y + 0.45f; + tempFloat[2] = centre.z + (float)Math.random()/2.5f - 0.2f; + tempFloat[3] = 1.5f; + tempFloat[4] = 1; + tempFloat[5] = 0; + tempFloat[6] = 6 + (gameData.getRandom()%4); + tempFloat[7] = this.height; + theAssetManager.explosionCount++; + + + } + } + + if(isRepairing && currentHP >0){ + if(mainThread.frameIndex%8==0 && theBaseInfo.currentCredit > 0 && currentHP maxHP) + currentHP = maxHP; + } + } + + //mark itself on obstacle map + mainThread.gridMap.currentObstacleMap[tileIndex[0]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[1]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[2]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[3]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[4]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[5]] = false; + + + //update center in camera coordinate + tempCentre.set(centre); + tempCentre.subtract(camera.position); + tempCentre.rotate_XZ(camera.XZ_angle); + tempCentre.rotate_YZ(camera.YZ_angle); + tempCentre.updateLocation(); + + + + //test if the object is visible in camera point of view + if(visibleBoundary.contains(tempCentre.screenX, tempCentre.screenY) && isRevealed){ + visible = true; + + if(screenBoundary.contains(tempCentre.screenX, tempCentre.screenY)) + withinViewScreen = true; + else + withinViewScreen = false; + + tempshadowvertex0.set(shadowvertex0); + tempshadowvertex0.subtract(camera.position); + tempshadowvertex0.rotate_XZ(camera.XZ_angle); + tempshadowvertex0.rotate_YZ(camera.YZ_angle); + tempshadowvertex0.updateLocation(); + + tempshadowvertex1.set(shadowvertex1); + tempshadowvertex1.subtract(camera.position); + tempshadowvertex1.rotate_XZ(camera.XZ_angle); + tempshadowvertex1.rotate_YZ(camera.YZ_angle); + tempshadowvertex1.updateLocation(); + + tempshadowvertex2.set(shadowvertex2); + tempshadowvertex2.subtract(camera.position); + tempshadowvertex2.rotate_XZ(camera.XZ_angle); + tempshadowvertex2.rotate_YZ(camera.YZ_angle); + tempshadowvertex2.updateLocation(); + + tempshadowvertex3.set(shadowvertex3); + tempshadowvertex3.subtract(camera.position); + tempshadowvertex3.rotate_XZ(camera.XZ_angle); + tempshadowvertex3.rotate_YZ(camera.YZ_angle); + tempshadowvertex3.updateLocation(); + + + + //if the object is visible then draw it on the shadow buffer from light point of view + if(shadowBoundary1.contains(tempshadowvertex0.screenX, tempshadowvertex0.screenY) || + shadowBoundary1.contains(tempshadowvertex1.screenX, tempshadowvertex1.screenY) || + shadowBoundary1.contains(tempshadowvertex2.screenX, tempshadowvertex2.screenY) || + shadowBoundary1.contains(tempshadowvertex3.screenX, tempshadowvertex3.screenY) + ){ + for(int i = 0; i < polygons.length; i++){ + polygons[i].update_lightspace(); + + + } + + } + + //add this object to visible unit list + theAssetManager.visibleUnit[theAssetManager.visibleUnitCount] = this; + theAssetManager.visibleUnitCount++; + + + }else{ + visible = false; + } + + + //create vision for enemy commander + if(teamNo == 1){ + int xPos = boundary2D.x1/16 - 8 + 10 + 1; + int yPos = 127 - boundary2D.y1/16 - 8 + 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; + } + } + } + + visionBoundary.x = (int)(tempCentre.screenX - 800); + visionBoundary.y = (int)(tempCentre.screenY - 1000); + visionInsideScreen = camera.screen.intersects(visionBoundary); + + + if(visionInsideScreen){ + if(teamNo == 0){ + 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++; + } + } + + if(theAssetManager.minimapBitmap[tileIndex[0]] || + theAssetManager.minimapBitmap[tileIndex[1]] || + theAssetManager.minimapBitmap[tileIndex[2]] || + theAssetManager.minimapBitmap[tileIndex[3]] || + theAssetManager.minimapBitmap[tileIndex[4]] || + theAssetManager.minimapBitmap[tileIndex[5]]) + isRevealed = true; + + visible_minimap = isRevealed; + + if(visible_minimap){ + tempInt = theAssetManager.unitsForMiniMap[theAssetManager.unitsForMiniMapCount]; + tempInt[0] = teamNo; + 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] = 10000; + theAssetManager.unitsForMiniMapCount++; + + + //spawn smoke particle + if((mainThread.frameIndex + ID) % 5 ==0 && centre.y >= -0.79f){ + float[] tempFloat = theAssetManager.smokeEmmiterList[theAssetManager.smokeEmmiterCount]; + tempFloat[0] = centre.x + 0.265f + (float)(Math.random()/40) - 0.0125f; + tempFloat[1] = centre.y + 0.4f + 0.5f; + tempFloat[2] = centre.z + 0.14f + (float)(Math.random()/40) - 0.0125f; + tempFloat[3] = 0.9f; + tempFloat[4] = 1; + tempFloat[5] = 11; + tempFloat[6] = this.height; + theAssetManager.smokeEmmiterCount++; + } + + } + + + + //handle cargo unloading + if(unloadOreCountDown > 0){ + + float doorSpeed = 0.0034f; + //open cargo door + if(unloadOreCountDown <= (unloadOreTime -1) && unloadOreCountDown > (unloadOreTime - 25)){ + storageCoverLeft.vertex3D[1].x -= doorSpeed; + storageCoverLeft.vertex3D[2].x -= doorSpeed; + storageCoverRight.vertex3D[0].x+=doorSpeed; + storageCoverRight.vertex3D[3].x+=doorSpeed; + + } + + if(unloadOreCountDown <= 24){ + storageCoverLeft.vertex3D[1].x += doorSpeed; + storageCoverLeft.vertex3D[2].x += doorSpeed; + storageCoverRight.vertex3D[0].x-=doorSpeed; + storageCoverRight.vertex3D[3].x-=doorSpeed; + + } + + unloadOreCountDown--; + } + + //running cargo thread + if(centre.y >= -0.79f){ + for(int i = 0; i cargoX_MaxRight){ + float dx = cargoX_left - cargoX; + float dy = cargoY_left - cargoY; + for(int j = 0; j < cargos[i].length; j++){ + vector[] cargoVertex = cargos[i][j].vertex3D; + for(int k = 0; k < cargoVertex.length; k++){ + cargoVertex[k].x+=dx; + cargoVertex[k].y+=dy; + } + + cargos[i][j].origin.x+=dx; + cargos[i][j].origin.y+=dy; + + cargos[i][j].rightEnd.x+=dx; + cargos[i][j].rightEnd.y+=dy; + + cargos[i][j].bottomEnd.x+=dx; + cargos[i][j].bottomEnd.y+=dy; + } + } + } + } + } + + public boolean droppingAreaIsFull(solidObject harvester){ + int tileIndex1 = tileIndex[5] + 128; + int tileIndex2 = tileIndex[5] + 127; + int tileIndex3 = tileIndex[5] + 129; + + boolean tile1Occpied = false; + boolean tile2Occpied = false; + boolean tile3Occpied = false; + + for(int i = 0; i < 4; i++){ + if(mainThread.gridMap.tiles[tileIndex1][i] != null && mainThread.gridMap.tiles[tileIndex1][i] != harvester && !(mainThread.gridMap.tiles[tileIndex1][i].isCloaked && mainThread.gridMap.tiles[tileIndex1][i].teamNo != teamNo)) + tile1Occpied = true; + if(mainThread.gridMap.tiles[tileIndex2][i] != null && mainThread.gridMap.tiles[tileIndex2][i] != harvester && !(mainThread.gridMap.tiles[tileIndex2][i].isCloaked && mainThread.gridMap.tiles[tileIndex2][i].teamNo != teamNo)) + tile2Occpied = true; + if(mainThread.gridMap.tiles[tileIndex3][i] != null && mainThread.gridMap.tiles[tileIndex3][i] != harvester && !(mainThread.gridMap.tiles[tileIndex3][i].isCloaked && mainThread.gridMap.tiles[tileIndex3][i].teamNo != teamNo)) + tile3Occpied = true; + } + + return tile1Occpied || tile2Occpied || tile3Occpied; + } + + public boolean hasExit(){ + int tileIndex2 = tileIndex[5] + 127; + int tileIndex3 = tileIndex[5] + 129; + + boolean tile2Occpied = false; + boolean tile3Occpied = false; + + for(int i = 0; i < 4; i++){ + if(mainThread.gridMap.tiles[tileIndex2][i] != null) + tile2Occpied = true; + if(mainThread.gridMap.tiles[tileIndex3][i] != null) + tile3Occpied = true; + } + + + return !(tile2Occpied && tile3Occpied); + } + + //draw the model + public void draw(){ + if(!visible) + return; + for(int i = 0; i < polygons.length; i++){ + + polygons[i].update(); + } + + for(int i = 0; i < polygons.length; i++){ + polygons[i].draw(); + } + } + + public vector getMovement(){ + return movenment; + } + + +} diff --git a/entity/rocketTank.java b/entity/rocketTank.java new file mode 100644 index 0000000..cf77bc2 --- /dev/null +++ b/entity/rocketTank.java @@ -0,0 +1,1110 @@ +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 tank object is visible from camera point of view + public final static Rectangle visibleBoundary = new Rectangle(-70,-25,908, 597); + + //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,688, 432); + + //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, 1300); + + //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 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.frameIndex%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 - 700); + visionBoundary.y = (int)(tempCentre.screenY - 650); + 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.frameIndex + 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.frameIndex)%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(){ + + 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*=1.25f; + } + + 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;} + +} diff --git a/entity/solidObject.java b/entity/solidObject.java new file mode 100644 index 0000000..59f4985 --- /dev/null +++ b/entity/solidObject.java @@ -0,0 +1,1651 @@ +package entity; + +import core.*; + +//this is the class for storing geometry information of a 3D model +public abstract class solidObject{ + + //reference point of the model (in world coordinate) + public vector start; + + //the reference axis of the model (in world coordinate) + public vector iDirection, jDirection, kDirection; + + //whether this model need to be sent to drawing pipeline + public boolean visible; + + //whether this model (only apply to static structures) has been revealed by player + public boolean isRevealed; + + //whether this model (only apply to static structures) has been revealed by AI + public boolean isRevealed_AI; + + //whether this model is completely bounded by the screen area + public boolean withinViewScreen; + + //whether this model is selected; + public boolean isSelected; + + //whether this model is selectable; + public boolean isSelectable = true; + + //change in center position between current frame and previous frame + public vector movement; + + //distance to desination + public float distanceToDesination; + + public boolean disableUnitLevelAI; + + public float distanceToDesination_PreviousFrame = 9999; + + public boolean closeToDestination; + + public int hugWallCoolDown; + + public int tightSpaceManeuverCountDown; + + public int stuckCount, insideDeistinationRadiusCount; + + public int bodyAngleDelta, turretAngleDelta; + + public float speed; + + public boolean visionInsideScreen, visible_lightspace, visible_minimap;; + + public int teamNo, type, currentHP; + + //this value represents the total amount of the inevitable damage that the unit will suffer, e.g damage from a incoming missile + public int incomingDamage; + + public float destinationX, destinationY, secondaryDestinationX, secondaryDestinationY; + + public int destinationX_, destinationY_; + + public boolean newDestinationisGiven; + + public solidObject attacker; + + public int myDamage; + + public Rect obstacle,tempObstacle; + public Rect unStableObstacle; + + //immediate destination Angle + public int immediateDestinationAngle; + public int tempAngle1, tempAngle2, tempAngle3,tempAngle4; + + //the index of tiles the harvester has occupied on the grid map + public int currentOccupiedTile, occupiedTile0, occupiedTile1,occupiedTile2,occupiedTile3, + previousOccupiedTile0, previousOccupiedTile1,previousOccupiedTile2,previousOccupiedTile3, + newOccupiedTile0, newOccupiedTile1, newOccupiedTile2,newOccupiedTile3, + tempTile0, tempTile1, tempTile2, tempTile3; + + public solidObject[] tile; + public int xPos, yPos, xPos2, yPos2, xPos_old, yPos_old; + public float[] tempFloat; + public int[] tempInt; + public int randomNumber; + public static Rect border = new Rect(0,0,16,16); + public static Rect destinationBlock = new Rect(0,0,0,0); + public static Rect probeBlock = new Rect(0,0,0,0); + + + public int currentCommand; + public static final int StandBy = 0; + public static final int move = 1; + public static final int attackCautiously = 2; + public static final int attackInNumbers = 3; + public static final int follow = 4; + public static final int attackMove = 5; + + public int secondaryCommand; + + + //movment status + public int currentMovementStatus; + public final static int freeToMove = 0; + public final static int hugLeft = 1; + public final static int hugRight = 2; + + //attack status + public int attackStatus; + public final static int noTarget = 0; + public final static int isAttacking = 1; + public final static int notInRange = 2; + public float attackRange, groupAttackRange; + + public int experience, level; + + //wether this object is under attack; + public int underAttackCountDown; + + //A cool down which prevents the object to change target too often + //public int changeTargetCountDown; + + //a rectangle which represent the object boundary in grid map + public Rect boundary2D; + + //vertices + public vector[] v; + + //the 3D polygons of the object + public polygon3D[] polygons; + + //the centre of the model in world coordinate + public vector centre; + + //the centre of the model in camera coordinate + public vector tempCentre = new vector(0,0,0); + public vector tempVector = new vector(0,0,0); + + public static int globalUniqID = 1; + + public int ID; + + public AssetManager theAssetManager; + + public float height; + + public static Rect fullSizedProbe = new Rect(0,0, 16, 16); + + public int progressStatus = -1; + + public drone myHealer; + + public boolean isCloaked; + public int cloakCooldownCount; + + public boolean isRepairing = true; + + public int screenX_gui, screenY_gui; + + //object that the unit is trying to attack + public solidObject targetObject; + + public int groupNo = 255; + + public boolean leftFactory; + + //get centre of this model in camera coordinate + public vector getCentre(){ + return tempCentre; + } + + //return centre in world coordinate + public vector getRealCentre(){ + return centre; + } + + //return visibility + public boolean getVisibility(){ + return visible; + } + + //create a arbitrary vertex + public vector put(double i, double j, double k){ + vector temp = start.myClone(); + temp.add(iDirection, (float)i); + temp.add(jDirection, (float)j); + temp.add(kDirection, (float)k); + return temp; + } + + //change the 3d geometry of a vertex + public void change(float i, float j, float k, vector v){ + v.set(start); + v.add(iDirection, i); + v.add(jDirection, j); + v.add(kDirection, k); + } + + //create color in binary format + public int createColor(int r, int g, int b){ + return b + (g << 5) + (r << 10); + } + + + //get ID + public int getID(){ + return ID; + } + + + //generate indexes for surrounding tile + public static int[] generateTileCheckList(float r){ + int[] list = new int[(int)((r+1)*(r+1)*Math.PI)]; + float[] distance = new float[list.length]; + + for(int i = 0; i < list.length; i++){ + list[i] = Integer.MAX_VALUE; + distance[i] = 10000000; + } + + int currentIndex = 0; + int R = (int)r; + if(R < r) + R++; + + for(int y = 0; y < R * 2 + 1; y++){ + for(int x = 0; x < R * 2 + 1; x++){ + int a = Math.abs(x-R); + int b = Math.abs(y-R); + if(r >= Math.sqrt(a*a + b*b)){ + list[currentIndex] = x - R + (y - R)*(32*4); + distance[currentIndex] = (float)Math.sqrt(a*a + b*b); + currentIndex++; + } + } + } + + for(int i = 1; i < list.length; i++){ + for(int j = 0; j distance[j+1]){ + float tempFloat = distance[j+1]; + distance[j+1] = distance[j]; + distance[j] = tempFloat; + + int tempInt = list[j+1]; + list[j+1] = list[j]; + list[j] = tempInt; + } + } + } + + return list; + } + + public boolean[] createBitmapVision(int radius){ + int l = radius*2+1; + boolean[] vision = new boolean[l*l]; + for(int y = 0; y < l; y++){ + for(int x = 0; x < l; x++){ + if( (x - radius)*(x - radius) + (y - radius)*(y - radius) < ((float)radius+0.5f)*((float)radius+0.5f)){ + vision[x + y*l] = true; + } + } + } + return vision; + } + + //clone a group of polygons (doesn't work on smooth shaded polygons) + public polygon3D[] clonePolygons(polygon3D[] polys, boolean createNewOUV){ + int l = polys.length; + + polygon3D[] clone = new polygon3D[l]; + + for(int i = 0; i < l; i++){ + if(polys[i] == null) + continue; + int length = polys[i].vertex3D.length; + v = new vector[length]; + for(int j = 0; j < length; j++){ + v[j] = polys[i].vertex3D[j].myClone(); + } + + int myType = polys[i].type; + float scaleX = polys[i].scaleX; + float scaleY = polys[i].scaleY; + texture myTexture = polys[i].myTexture; + if(createNewOUV) + clone[i] = new polygon3D(v, polys[i].origin.myClone(), polys[i].rightEnd.myClone(), polys[i].bottomEnd.myClone(), myTexture, scaleX, scaleY, myType); + else + clone[i] = new polygon3D(v, v[0], v[1], v[3], myTexture, scaleX, scaleY, myType); + clone[i].shadowBias = polys[i].shadowBias; + clone[i].diffuse_I = polys[i].diffuse_I; + clone[i].Ambient_I = polys[i].Ambient_I; + } + + + return clone; + } + + public boolean isStable(solidObject o){ + if(o != null){ + if(o.currentCommand == StandBy || (o.attackStatus == isAttacking && o.getMovement().x ==0 && o.getMovement().z ==0) || o.type > 100){ + + return true; + } + } + + return false; + } + + public void removeFromGridMap(){ + boundary2D.setOrigin(100000, 100000); + if(occupiedTile0 != -1){ + tile = mainThread.gridMap.tiles[occupiedTile0]; + for(int i = 0; i < 5; i++){ + if(tile[i] == this){ + tile[i] = null; + + } + } + } + + if(occupiedTile1 != -1){ + tile = mainThread.gridMap.tiles[occupiedTile1]; + for(int i = 0; i < 5; i++){ + if(tile[i] == this){ + tile[i] = null; + + } + } + } + + if(occupiedTile2 != -1){ + tile = mainThread.gridMap.tiles[occupiedTile2]; + for(int i = 0; i < 5; i++){ + if(tile[i] == this){ + tile[i] = null; + + } + } + } + + if(occupiedTile3 != -1){ + tile = mainThread.gridMap.tiles[occupiedTile3]; + for(int i = 0; i < 5; i++){ + if(tile[i] == this){ + tile[i] = null; + + } + } + } + + } + + public void updateOccupiedTiles(int x, int y){ + + previousOccupiedTile0 = occupiedTile0; + previousOccupiedTile1 = occupiedTile1; + previousOccupiedTile2 = occupiedTile2; + previousOccupiedTile3 = occupiedTile3; + + occupiedTile0= x/16 + (127 - (y-1)/16)*128; + occupiedTile1= -1; + occupiedTile2= -1; + occupiedTile3= -1; + if(movement.x == 0 && movement.z == 0){ + mainThread.gridMap.currentObstacleMap[occupiedTile0] = false; + } + + if(x%16 >0 && y%16 > 0){ + occupiedTile1= occupiedTile0 + 1; + occupiedTile2= occupiedTile0 + 128; + occupiedTile3= occupiedTile2 + 1; + + if(movement.x == 0 && movement.z == 0){ + mainThread.gridMap.currentObstacleMap[occupiedTile1] = false; + mainThread.gridMap.currentObstacleMap[occupiedTile2] = false; + mainThread.gridMap.currentObstacleMap[occupiedTile3] = false; + } + + }else if(x%16 > 0){ + occupiedTile1= occupiedTile0 + 1; + if(movement.x == 0 && movement.z == 0){ + mainThread.gridMap.currentObstacleMap[occupiedTile1] = false; + } + }else if(y%16 > 0){ + occupiedTile2= occupiedTile0 + 128; + if(movement.x == 0 && movement.z == 0){ + mainThread.gridMap.currentObstacleMap[occupiedTile2] = false; + } + } + + + //object occupies exactly the same tiles as before, then do nothing + if(previousOccupiedTile0 == occupiedTile0 && previousOccupiedTile1 == occupiedTile1 && previousOccupiedTile2 == occupiedTile2 && previousOccupiedTile3 == occupiedTile3){ + return; + } + + //remove the object from the old tiles + if(previousOccupiedTile0 != -1){ + tile = mainThread.gridMap.tiles[previousOccupiedTile0]; + for(int i = 0; i < 4; i++){ + if(tile[i] == this){ + tile[i] = null; + break; + } + } + } + if(previousOccupiedTile1 != -1){ + tile = mainThread.gridMap.tiles[previousOccupiedTile1]; + for(int i = 0; i < 4; i++){ + if(tile[i] == this){ + tile[i] = null; + break; + } + } + } + if(previousOccupiedTile2 != -1){ + tile = mainThread.gridMap.tiles[previousOccupiedTile2]; + for(int i = 0; i < 4; i++){ + if(tile[i] == this){ + tile[i] = null; + break; + } + } + } + if(previousOccupiedTile3 != -1){ + tile = mainThread.gridMap.tiles[previousOccupiedTile3]; + for(int i = 0; i < 4; i++){ + if(tile[i] == this){ + tile[i] = null; + break; + } + } + } + + //add the object to the new tiles + if(occupiedTile0 != -1){ + tile = mainThread.gridMap.tiles[occupiedTile0]; + for(int i = 0; i < 4; i++){ + if(tile[i] == null){ + tile[i] = this; + break; + } + } + } + if(occupiedTile1 != -1){ + tile = mainThread.gridMap.tiles[occupiedTile1]; + for(int i = 0; i < 4; i++){ + if(tile[i] == null){ + tile[i] = this; + break; + } + } + } + if(occupiedTile2 != -1){ + tile = mainThread.gridMap.tiles[occupiedTile2]; + for(int i = 0; i < 4; i++){ + if(tile[i] == null){ + tile[i] = this; + break; + } + } + } + if(occupiedTile3 != -1){ + tile = mainThread.gridMap.tiles[occupiedTile3]; + for(int i = 0; i < 4; i++){ + if(tile[i] == null){ + tile[i] = this; + break; + } + } + } + } + + public Rect retriveSurroundingObject(int xPos, int yPos){ + tempTile0 = xPos/16 + (127 - yPos/16)*128; + tempTile1 = tempTile0 + 1; + tempTile2 = tempTile0 + 128; + tempTile3 = tempTile0 + 129; + + Rect r = null; + + if(tempTile0 >=0 && tempTile0 < 16384){ + tile = mainThread.gridMap.tiles[tempTile0]; + for(int i = 0; i < 5; i++){ + if(tile[i] != null){ + if(tile[i].ID != ID){ + if(isStable(tile[i])) + return tile[i].boundary2D; + else + r = tile[i].boundary2D; + } + } + } + } + + if(tempTile1 >=0 && tempTile1 < 16384){ + tile = mainThread.gridMap.tiles[tempTile1]; + for(int i = 0; i < 5; i++){ + if(tile[i] != null){ + if( tile[i].ID != ID){ + if(isStable(tile[i])) + return tile[i].boundary2D; + else + r = tile[i].boundary2D; + } + } + } + } + + if(tempTile2 >=0 && tempTile2 < 16384){ + tile = mainThread.gridMap.tiles[tempTile2]; + for(int i = 0; i < 5; i++){ + if(tile[i] != null){ + if(tile[i].ID != ID){ + if(isStable(tile[i])) + return tile[i].boundary2D; + else + r = tile[i].boundary2D; + } + } + } + } + + if(tempTile3 >=0 && tempTile3 < 16384){ + tile = mainThread.gridMap.tiles[tempTile3]; + for(int i = 0; i < 5; i++){ + if(tile[i] != null){ + if(tile[i].ID != ID){ + if(isStable(tile[i])) + return tile[i].boundary2D; + else + r = tile[i].boundary2D; + } + } + } + } + + + return r; + } + + + public int validateMovement(){ + + + + xPos_old = boundary2D.x1; + yPos_old = boundary2D.y1; + xPos = (int)((centre.x + movement.x)*64) - 8; + yPos = (int)((centre.z + movement.z)*64) + 8; + boundary2D.setOrigin(xPos, yPos); + + obstacle = checkForCollision(boundary2D); + + boundary2D.setOrigin(xPos_old, yPos_old); + + if(obstacle == null){ + + return freeToMove; + }else{ + destinationX_ = (int)(destinationX*64); + destinationY_ = (int)(destinationY*64); + + int x = 0; + int y = 0; + if(obstacle.owner!= null){ + x = obstacle.owner.boundary2D.x1; + y = obstacle.owner.boundary2D.y1; + + if(x - xPos_old < -16) + x+=16; + + if(y - yPos_old > 16) + y-=16; + + if(x - xPos_old > 16) + x-=16; + + if(y - yPos_old < -16) + y+=16; + + if(obstacle.owner.teamNo != teamNo) + obstacle.owner.cloakCooldownCount = 60; + + }else{ + x = obstacle.x1; + y = obstacle.y1; + } + + float dx = Math.abs(centre.x - destinationX); + float dy = Math.abs(centre.z - destinationY); + + float dx_ = 0; + float dy_ = 0; + if(obstacle.owner != null){ + dx_ = centre.x - obstacle.owner.centre.x; + dy_ = centre.z - obstacle.owner.centre.z; + } + + + + + + //figure out which action should be taken next + float upDistance = 0; + float downDistance =0; + float leftDistance = 0; + float rightDistance = 0; + + if(obstacle.x1 > boundary2D.x2){ + + if((currentCommand == attackCautiously || currentCommand == attackInNumbers) && distanceToDesination <= 1.5f){ + upDistance = countOccupiedBlocksDuringAttack(x, y, 0, 16, 16, 0) * 0.25f; + downDistance = countOccupiedBlocksDuringAttack(x, y, 0, -16, 16, 0) * 0.25f; + }else{ + upDistance = countOccupiedBlocks(x, y, 0, 16, 16, 0) * 0.25f; + downDistance = countOccupiedBlocks(x, y, 0, -16, 16, 0) * 0.25f; + } + + if(destinationY < centre.z){ + + if(downDistance <= dy || dx < 0.125f){ + immediateDestinationAngle = 180; + return hugLeft; + } + + if(downDistance < upDistance){ + immediateDestinationAngle = 180; + return hugLeft; + }else{ + if(upDistance == downDistance){ + if(dy_ < 0){ + immediateDestinationAngle = 180; + return hugLeft; + } + } + + immediateDestinationAngle = 0; + return hugRight; + } + }else{ + + + + if(upDistance <= dy || dx < 0.125f){ + immediateDestinationAngle = 0; + return hugRight; + } + + if(upDistance < downDistance){ + immediateDestinationAngle = 0; + return hugRight; + }else{ + + immediateDestinationAngle = 180; + return hugLeft; + } + + } + + } + + if(obstacle.x2 < boundary2D.x1){ + + if((currentCommand == attackCautiously || currentCommand == attackInNumbers) && distanceToDesination <= 1.5f){ + upDistance = countOccupiedBlocksDuringAttack(x, y, 0, 16, -16, 0) * 0.25f; + downDistance = countOccupiedBlocksDuringAttack(x, y, 0, -16, -16, 0) * 0.25f; + + }else{ + upDistance = countOccupiedBlocks(x, y, 0, 16, -16, 0) * 0.25f; + downDistance = countOccupiedBlocks(x, y, 0, -16, -16, 0) * 0.25f; + } + + + + if(destinationY < centre.z){ + if(downDistance <= dy || dx < 0.125f){ + immediateDestinationAngle = 180; + return hugRight; + } + + if(downDistance < upDistance){ + immediateDestinationAngle = 180; + return hugRight; + }else{ + + if(upDistance == downDistance){ + if(dy_ < 0){ + immediateDestinationAngle = 180; + return hugRight; + } + } + + immediateDestinationAngle = 0; + return hugLeft; + } + }else{ + if(upDistance <= dy || dx < 0.125f){ + immediateDestinationAngle = 0; + return hugLeft; + } + + if(upDistance < downDistance){ + immediateDestinationAngle = 0; + return hugLeft; + }else{ + + immediateDestinationAngle = 180; + return hugRight; + } + + } + } + + if(obstacle.y2 > boundary2D.y1){ + + if((currentCommand == attackCautiously || currentCommand == attackInNumbers) && distanceToDesination <= 1.5f){ + leftDistance = countOccupiedBlocksDuringAttack(x, y, -16, 0, 0, 16) * 0.25f; + rightDistance = countOccupiedBlocksDuringAttack(x, y, 16, 0, 0, 16) * 0.25f; + }else{ + leftDistance = countOccupiedBlocks(x, y, -16, 0, 0, 16) * 0.25f; + rightDistance = countOccupiedBlocks(x, y, 16, 0, 0, 16) * 0.25f; + } + + if(destinationX < centre.x){ + if(leftDistance <= dx || dy < 0.125f){ + immediateDestinationAngle = 270; + return hugRight; + } + + if(leftDistance < rightDistance){ + immediateDestinationAngle = 270; + return hugRight; + }else{ + immediateDestinationAngle = 90; + return hugLeft; + } + }else{ + + + if(rightDistance <= dx || dy < 0.125f){ + immediateDestinationAngle = 90; + + + return hugLeft; + } + if(rightDistance < leftDistance){ + immediateDestinationAngle = 90; + return hugLeft; + }else{ + + if(rightDistance == leftDistance){ + if(dx_ > 0){ + immediateDestinationAngle = 90; + return hugLeft; + } + } + + immediateDestinationAngle = 270; + return hugRight; + } + } + } + + if(obstacle.y1 < boundary2D.y2){ + + + if((currentCommand == attackCautiously || currentCommand == attackInNumbers) && distanceToDesination <= 1.5f){ + leftDistance = countOccupiedBlocksDuringAttack(x, y, -16, 0, 0, -16) * 0.25f; + rightDistance = countOccupiedBlocksDuringAttack(x, y, 16, 0, 0, -16) * 0.25f; + }else{ + leftDistance = countOccupiedBlocks(x, y, -16, 0, 0, -16) * 0.25f; + rightDistance = countOccupiedBlocks(x, y, 16, 0, 0, -16) * 0.25f; + } + + if(destinationX < centre.x){ + + if(leftDistance <= dx || dy < 0.125f){ + immediateDestinationAngle = 270; + return hugLeft; + } + + if(leftDistance < rightDistance){ + immediateDestinationAngle = 270; + return hugLeft; + }else{ + immediateDestinationAngle = 90; + return hugRight; + } + }else{ + if(rightDistance <= dx || dy < 0.125f){ + immediateDestinationAngle = 90; + return hugRight; + } + if(rightDistance < leftDistance){ + immediateDestinationAngle = 90; + + return hugRight; + }else{ + if(rightDistance == leftDistance){ + if(dx_ > 0){ + immediateDestinationAngle = 90; + return hugRight; + } + } + + + immediateDestinationAngle = 270; + return hugLeft; + } + } + } + + return -1; + } + } + + //count the number of occupied block (up to 10 blocks) in a given direction + public int countOccupiedBlocks(int x, int y, int dx, int dy, int dx_, int dy_){ + int count = 0; + for(int i = 0; i < 10; i++, x+=dx, y +=dy){ + if(x > 127*16 || x < 0 || y > 127*16 || y < 0) + continue; + fullSizedProbe.setOrigin(x, y); + if(checkForCollision(fullSizedProbe) != null){ + count++; + }else{ + if(fullSizedProbe.contains(destinationX_, destinationY_)){ + break; + } + + fullSizedProbe.setOrigin(x+dx_, y+dy_); + if(checkForCollision(fullSizedProbe) != null){ + fullSizedProbe.setOrigin(x+dx, y+dy); + if(checkForCollision(fullSizedProbe) != null){ + count++; + }else{ + break; + } + }else + break; + } + + } + count-=1; + + if(count < 0) + count = 0; + + return count; + } + + //count the number of occupied block (up to 10 blocks) in a given direction + public int countOccupiedBlocksDuringAttack(int x, int y, int dx, int dy, int dx_, int dy_){ + int count = 0; + Rect tempRect; + for(int i = 0; i < 10; i++, x+=dx, y +=dy){ + if(x > 127*16 || x < 0 || y > 127*16 || y < 0) + continue; + fullSizedProbe.setOrigin(x, y); + + tempRect = checkForCollision(fullSizedProbe); + if(tempRect != null){ + if(tempRect.owner != null && tempRect.owner == targetObject) + return 0; + count++; + }else{ + if(fullSizedProbe.contains(destinationX_, destinationY_)){ + break; + } + + fullSizedProbe.setOrigin(x+dx_, y+dy_); + if(checkForCollision(fullSizedProbe) != null){ + fullSizedProbe.setOrigin(x+dx, y+dy); + if(checkForCollision(fullSizedProbe) != null){ + count++; + }else{ + break; + } + }else + break; + } + + } + count-=1; + + if(count < 0) + count = 0; + + return count; + } + + public Rect checkForCollision(Rect myRect){ + if(obstacle != null){ + if(myRect.intersect(obstacle) && (isStable(obstacle.owner))){ + return obstacle; + } + } + + + //check if the tank collide with the border + if(myRect.x1 < 0){ + border.setOrigin(-16, myRect.y1); + + return border; + } + + if(myRect.x2 > 2047){ + border.setOrigin(2048, myRect.y1); + return border; + } + + if(myRect.y2 < 1){ + border.setOrigin(myRect.x1, 0); + return border; + } + + if(myRect.y1 > 2048){ + border.setOrigin(myRect.x1, 2064); + return border; + } + + newOccupiedTile0= myRect.x1/16 + (127 - myRect.y1/16)*128; + + if(myRect.y1 == 2048) + newOccupiedTile0= myRect.x1/16 + (127 - (myRect.y1-1)/16)*128; + + newOccupiedTile1 = newOccupiedTile0 + 1; + newOccupiedTile2 = newOccupiedTile0 + 128; + newOccupiedTile3 = newOccupiedTile0 + 129; + + + + + tempObstacle = null; + + if(newOccupiedTile0 >= 0 && newOccupiedTile0 < 16384){ + tile = mainThread.gridMap.tiles[newOccupiedTile0]; + for(int i = 0; i < 5; i++){ + if(tile[i] != null){ + if(tile[i].boundary2D.intersect(myRect) && tile[i].ID != ID) + if(isStable(tile[i]) ){ + return tile[i].boundary2D; + }else{ + if(tempObstacle == null) + tempObstacle = tile[i].boundary2D; + } + } + } + } + + if(newOccupiedTile1 >= 0 && newOccupiedTile1 < 16384){ + tile = mainThread.gridMap.tiles[newOccupiedTile1]; + for(int i = 0; i < 5; i++){ + if(tile[i] != null){ + if(tile[i].boundary2D.intersect(myRect) && tile[i].ID != ID) + if(isStable(tile[i]) ){ + return tile[i].boundary2D; + }else{ + if(tempObstacle == null) + tempObstacle = tile[i].boundary2D; + } + } + } + } + + if(newOccupiedTile2 >= 0 && newOccupiedTile2 < 16384){ + tile = mainThread.gridMap.tiles[newOccupiedTile2]; + for(int i = 0; i < 5; i++){ + if(tile[i] != null){ + if(tile[i].boundary2D.intersect(myRect) && tile[i].ID != ID) + if(isStable(tile[i]) ){ + return tile[i].boundary2D; + }else{ + if(tempObstacle == null) + tempObstacle = tile[i].boundary2D; + } + } + } + } + + if(newOccupiedTile3 >= 0 && newOccupiedTile3 < 16384){ + tile = mainThread.gridMap.tiles[newOccupiedTile3]; + for(int i = 0; i < 5; i++){ + if(tile[i] != null){ + if(tile[i].boundary2D.intersect(myRect) && tile[i].ID != ID) + if(isStable(tile[i]) ){ + return tile[i].boundary2D; + }else{ + if(tempObstacle == null) + tempObstacle = tile[i].boundary2D; + } + } + } + } + + if(tempObstacle != null) + unStableObstacle = tempObstacle; + + return tempObstacle; + } + + public void calculateMovement(){ + movement.set(destinationX - centre.x, 0, destinationY - centre.z); + movement.unit(); + movement.scale(speed); + } + + public void changeMovement(int angle){ + if(angle == 0) + movement.set(0,0,speed); + if(angle == 90) + movement.set(speed,0,0); + if(angle == 180) + movement.set(0,0,-speed); + if(angle == 270) + movement.set(-speed,0,0); + } + + public boolean checkIfTileIsOccupiedByStaticUnitProbe(float x, float y){ + xPos = (int)(x*64); + yPos = (int)(y*64); + if(xPos <= 0 || yPos <= 0 || xPos >= 2048 || yPos >=2048) + return true; + + probeBlock.setOrigin(xPos-6, yPos+6); + tile = mainThread.gridMap.tiles[xPos/16 + (127 - yPos/16)*128]; + + for(int i = 0; i < 4; i++){ + if(tile[i] != null){ + if(tile[i].boundary2D.intersect(probeBlock) && isStable(tile[i]) ) + return true; + } + } + + return false; + } + + public boolean checkIfTileIsOccupiedByStaticUnitPoint(float x, float y){ + xPos = (int)(x*64); + yPos = (int)(y*64); + + if(xPos <= 0 || yPos <= 0 || xPos >= 2048 || yPos >=2048) + return true; + tile = mainThread.gridMap.tiles[xPos/16 + (127 - yPos/16)*128]; + + for(int i = 0; i < 4; i++){ + if(tile[i] != null){ + if(tile[i].boundary2D.contains(xPos, yPos) && isStable(tile[i]) ) + return true; + } + } + + return false; + } + + //a maneuver that follow the edge of the obstacles until the path to its destination is clear + public void hugWalls(){ + + + xPos_old = boundary2D.x1; + yPos_old = boundary2D.y1; + + tempVector.set(movement); + calculateMovement(); + + xPos = (int)((centre.x + movement.x)*64) - 8; + yPos = (int)((centre.z + movement.z)*64) + 8; + + + //if there is nothing nearby then re-issue the command to move towards destination + + boundary2D.setOrigin(xPos, yPos); + boolean destinationImmediatelyReachable = true; + + //check if the next move towards the destination will result in collision + if(checkForCollision(boundary2D) == null){ + movement.scale(4); + xPos = (int)((centre.x + movement.x)*64) - 8; + yPos = (int)((centre.z + movement.z)*64) + 8; + boundary2D.setOrigin(xPos, yPos); + + //if there is no collision then check if the obstacle found in previous move is static or not + if(checkForCollision(boundary2D) == null){ + if(obstacle.owner != null){ + //if the obstacle is not static (e.g another moving tank) then re-issue the command to move towards destination + if(obstacle.owner.getMovement().x != 0 || obstacle.owner.getMovement().z !=0 || (Math.abs(obstacle.owner.immediateDestinationAngle - immediateDestinationAngle) < 10 && !isStable(obstacle.owner))){ + newDestinationisGiven = true; + movement.reset(); + currentMovementStatus = freeToMove; + hugWallCoolDown = 0; + obstacle = null; + boundary2D.setOrigin(xPos_old, yPos_old); + return; + } + } + + //check more moves towards destination for potential collisions to ensure the path is really clear + movement.scale(4); + xPos = (int)((centre.x + movement.x)*64) - 8; + yPos = (int)((centre.z + movement.z)*64) + 8; + boundary2D.setOrigin(xPos, yPos); + if(checkForCollision(boundary2D) == null){ + movement.scale(2); + xPos = (int)((centre.x + movement.x)*64) - 8; + yPos = (int)((centre.z + movement.z)*64) + 8; + boundary2D.setOrigin(xPos, yPos); + + + if(checkForCollision(boundary2D) == null){ + //finally if no collision is found, and the destination direction is not opposite to the tank's current direction, + //then re-issue the command to move towards destination + + + Rect surroundingObject = retriveSurroundingObject(xPos, yPos); + boolean shouldMoveTowardsDestination = false; + + if(surroundingObject != null){ + if(surroundingObject.owner != null){ + if(!isStable(surroundingObject.owner)){ + + shouldMoveTowardsDestination = true; + } + } + } + + + + + if(tempVector.dot(movement) > 0 || shouldMoveTowardsDestination){ + + + newDestinationisGiven = true; + calculateMovement(); + currentMovementStatus = freeToMove; + boundary2D.setOrigin(xPos_old, yPos_old); + hugWallCoolDown = 0; + obstacle = null; + return; + } + movement.reset(); + boundary2D.setOrigin(xPos_old, yPos_old); + } + } + + + } + }else{ + obstacle = checkForCollision(boundary2D); + if(isStable(obstacle.owner)) + destinationImmediatelyReachable = false; + } + + + + + if(currentMovementStatus == hugRight){ + + tempAngle1 = (immediateDestinationAngle + 90)%360; + tempAngle2 = immediateDestinationAngle; + tempAngle3 = (immediateDestinationAngle - 90 + 360)%360; + tempAngle4 = (immediateDestinationAngle - 180 + 360)%360; + + }else{ + + tempAngle1 = (immediateDestinationAngle - 90 + 360)%360; + tempAngle2 = immediateDestinationAngle; + tempAngle3 = (immediateDestinationAngle + 90)%360; + tempAngle4 = (immediateDestinationAngle + 180)%360; + } + + if(hugWallCoolDown >0){ + hugWallCoolDown--; + + }else{ + if(obstacle.owner != null){ + if(obstacle.owner.type >= 100){ + changeMovement(tempAngle2); + movement.scale(16); + xPos = (int)((centre.x + movement.x)*64) - 8; + yPos = (int)((centre.z + movement.z)*64) + 8; + boundary2D.setOrigin(xPos, yPos); + + if(checkForCollision(boundary2D) == null){ + float x = movement.x; + float z = movement.z; + changeMovement(tempAngle1); + movement.scale(16); + + if(tightSpaceManeuverCountDown ==0){ + if(x * (destinationX - centre.x) + z * (destinationY - centre.z) > movement.x * (destinationX - centre.x) + movement.z * (destinationY - centre.z)){ + boundary2D.setOrigin(xPos_old, yPos_old); + changeMovement(tempAngle2); + tightSpaceManeuverCountDown = 64; + return; + } + }else{ + if((movement.x * (destinationX - centre.x) + movement.z * (destinationY - centre.z)) > 0){ + boundary2D.setOrigin(xPos_old, yPos_old); + changeMovement(tempAngle2); + return; + } + } + } + } + } + + //Check if turning is possible + if(obstacle.owner != null){ + if(obstacle.owner.getMovement().x == 0 && obstacle.owner.getMovement().z ==0){ + changeMovement(tempAngle1); + movement.scale(16); + xPos = (int)((centre.x + movement.x)*64) - 8; + yPos = (int)((centre.z + movement.z)*64) + 8; + boundary2D.setOrigin(xPos, yPos); + //if turning is possible but it drives the tank further away from the destination then change + if(checkForCollision(boundary2D) == null){ + + boolean shouldTurn = true; + movement.scale(3.3f); + float l = movement.getLength(); + if(distanceToDesination >= l){ + xPos = (int)((centre.x + movement.x)*64) - 8; + yPos = (int)((centre.z + movement.z)*64) + 8; + boundary2D.setOrigin(xPos, yPos); + if(checkForCollision(boundary2D) != null && (!checkIfTileIsOccupiedByStaticUnitPoint(destinationX, destinationY) || distanceToDesination > 1.6)){ + + shouldTurn = false; + } + }else{ + movement.scale(0.9f); + xPos = (int)((centre.x + movement.x)*64) - 8; + yPos = (int)((centre.z + movement.z)*64) + 8; + boundary2D.setOrigin(xPos, yPos); + if(checkForCollision(boundary2D) != null && !checkIfTileIsOccupiedByStaticUnitPoint(destinationX, destinationY) && !(distanceToDesination < 0.4f)){ + + shouldTurn = false; + } + } + + if(shouldTurn){ + if((movement.x * (destinationX - centre.x) + movement.z * (destinationY - centre.z)) < 0){ + + changeMovement(tempAngle3); + xPos = (int)((centre.x + movement.x*8)*64) - 8; + yPos = (int)((centre.z + movement.z*8)*64) + 8; + boundary2D.setOrigin(xPos, yPos); + + if(checkForCollision(boundary2D) == null){ + + + changeMovement(tempAngle4); + xPos2 = (int)((centre.x + movement.x*8)*64) - 8; + yPos2 = (int)((centre.z + movement.z*8)*64) + 8; + boundary2D.setOrigin((xPos+xPos2)/2, (yPos+yPos2)/2); + + + + if(checkForCollision(boundary2D) != null && isStable(obstacle.owner)){ + obstacle = checkForCollision(boundary2D); + boundary2D.setOrigin(xPos_old, yPos_old); + movement.reset(); + immediateDestinationAngle = tempAngle3; + hugWallCoolDown = 15; + + + if(currentMovementStatus == hugRight) + currentMovementStatus = hugLeft; + else + currentMovementStatus = hugRight; + return; + } + } + } + boundary2D.setOrigin(xPos_old, yPos_old); + movement.reset(); + immediateDestinationAngle = tempAngle1; + if(destinationImmediatelyReachable) + hugWallCoolDown = 60; + else + hugWallCoolDown = 15; + return; + } + + } + } + } + } + + + changeMovement(tempAngle2); + xPos = (int)((centre.x + movement.x)*64) - 8; + yPos = (int)((centre.z + movement.z)*64) + 8; + boundary2D.setOrigin(xPos, yPos); + + tempObstacle = checkForCollision(boundary2D); + if(tempObstacle == null){ + changeMovement(tempAngle3); + movement.scale(16); + xPos = (int)((centre.x + movement.x)*64) - 8; + yPos = (int)((centre.z + movement.z)*64) + 8; + boundary2D.setOrigin(xPos, yPos); + tempObstacle = checkForCollision(boundary2D); + if(tempObstacle != null){ + if(tempObstacle.owner != null) + if(isStable(tempObstacle.owner)){ + if((movement.x * (destinationX - centre.x) + movement.z * (destinationY - centre.z)) > 0){ + + if(currentMovementStatus == hugRight) + currentMovementStatus = hugLeft; + else + currentMovementStatus = hugRight; + } + } + } + + changeMovement(tempAngle2); + boundary2D.setOrigin(xPos_old, yPos_old); + return; + } else if(tempObstacle.owner != null){ + if((tempObstacle.owner.getMovement().x != 0 || tempObstacle.owner.getMovement().z != 0) && !destinationImmediatelyReachable){ + + movement.reset(); + boundary2D.setOrigin(xPos_old, yPos_old); + return; + } + } + + + if(obstacle.owner != null){ + if(obstacle.owner.getMovement().x == 0 && obstacle.owner.getMovement().z ==0){ + changeMovement(tempAngle3); + xPos = (int)((centre.x + movement.x)*64) - 8; + yPos = (int)((centre.z + movement.z)*64) + 8; + boundary2D.setOrigin(xPos, yPos); + if(checkForCollision(boundary2D) == null){ + boundary2D.setOrigin(xPos_old, yPos_old); + movement.reset(); + immediateDestinationAngle = tempAngle3; + return; + } + } + + if(obstacle.owner.getMovement().x == 0 && obstacle.owner.getMovement().z ==0){ + changeMovement(tempAngle4); + xPos = (int)((centre.x + movement.x)*64) - 8; + yPos = (int)((centre.z + movement.z)*64) + 8; + boundary2D.setOrigin(xPos, yPos); + if(checkForCollision(boundary2D) == null){ + boundary2D.setOrigin(xPos_old, yPos_old); + movement.reset(); + immediateDestinationAngle = tempAngle4; + return; + } + } + } + + boundary2D.setOrigin(xPos_old, yPos_old); + movement.reset(); + + } + + public boolean checkIfDestinationReached(){ + distanceToDesination = (float)Math.sqrt((destinationX - centre.x) * (destinationX - centre.x) + (destinationY - centre.z) * (destinationY - centre.z)); + + + + if(distanceToDesination < 1.5 && checkIfTileIsOccupiedByStaticUnitPoint(destinationX, destinationY)){ + closeToDestination = true; + + if(distanceToDesination > distanceToDesination_PreviousFrame){ + distanceToDesination_PreviousFrame = 9999; + return true; + } + + distanceToDesination_PreviousFrame = distanceToDesination; + + }else{ + if(closeToDestination){ + closeToDestination = false; + distanceToDesination_PreviousFrame = 9999; + return true; + } + + } + + if(distanceToDesination > 1.5) + return false; + + if(distanceToDesination < 0.1){ + insideDeistinationRadiusCount = 0; + distanceToDesination_PreviousFrame = 9999; + return true; + } + + if(distanceToDesination < 0.5){ + insideDeistinationRadiusCount++; + }else{ + insideDeistinationRadiusCount = 0; + } + + if(insideDeistinationRadiusCount >= 64){ + insideDeistinationRadiusCount = 0; + distanceToDesination_PreviousFrame = 9999; + return true; + } + + + //if the desitnation is already occupied, test if the tank is adjacent to destination tile + xPos_old = boundary2D.x1; + yPos_old = boundary2D.y1; + xPos = (int)((centre.x + movement.x)*64) - 8; + yPos = (int)((centre.z + movement.z)*64) + 8; + boundary2D.setOrigin(xPos, yPos); + if(checkForCollision(boundary2D) == null){ + + if(distanceToDesination < 0.5 && checkIfTileIsOccupiedByStaticUnitPoint(destinationX, destinationY)){ + destinationBlock.setOrigin((int)(destinationX*64)-8, (int)(destinationY*64)+8); + xPos = (int)((centre.x + (destinationX - centre.x)/32)*64) - 8; + yPos = (int)((centre.z + (destinationY - centre.z)/32)*64) + 8; + boundary2D.setOrigin(xPos, yPos); + if(boundary2D.intersect(destinationBlock)){ + boundary2D.setOrigin(xPos_old, yPos_old); + distanceToDesination_PreviousFrame = 9999; + return true; + } + } + + + + boundary2D.setOrigin(xPos_old, yPos_old); + return false; + } + + if(distanceToDesination < 0.5){ + if(checkIfTileIsOccupiedByStaticUnitPoint(destinationX, destinationY)){ + boundary2D.setOrigin(xPos_old, yPos_old); + distanceToDesination_PreviousFrame = 9999; + return true; + } + } + + + if(distanceToDesination < 1.2){ + + if(checkIfTileIsOccupiedByStaticUnitProbe(destinationX + 0.25f, destinationY + 0.25f) && + checkIfTileIsOccupiedByStaticUnitProbe(destinationX + 0.25f, destinationY - 0.25f) && + checkIfTileIsOccupiedByStaticUnitProbe(destinationX - 0.25f, destinationY + 0.25f) && + checkIfTileIsOccupiedByStaticUnitProbe(destinationX - 0.25f, destinationY - 0.25f)){ + boundary2D.setOrigin(xPos_old, yPos_old); + distanceToDesination_PreviousFrame = 9999; + return true; + } + } + + boundary2D.setOrigin(xPos_old, yPos_old); + + return false; + } + + public void avoidGettingStucked(){ + //if the object can't move for some period then recalculate the path + if(movement.x == 0 && movement.z == 0 && bodyAngleDelta == 0 && attackStatus != isAttacking){ + stuckCount++; + } + + + if(obstacle != null && attackStatus != isAttacking){ + if((unStableObstacle != null || !isStable(obstacle.owner)) && (ID + randomNumber + mainThread.frameIndex)%128 ==0){ + + newDestinationisGiven = true; + currentMovementStatus = freeToMove; + hugWallCoolDown = 0; + stuckCount = 0; + randomNumber = gameData.getRandom(); + } + } + + + + if(stuckCount > 128){ + newDestinationisGiven = true; + stuckCount = 0; + currentMovementStatus = freeToMove; + hugWallCoolDown = 0; + + } + } + + public String toString(){ + String label = ""; + if(type == 0) + label+="lightTank"; + if(type == 1) + label+="rocketTank"; + if(type == 101) + label+="powerPlant"; + if(type == 2) + label+="harvester"; + if(type==102) + label+="refinery"; + if(type==3) + label+="constructionVehichle"; + if(type ==4) + label+="tokenObject"; + if(type== 6) + label+="stealthTank"; + if(type == 7) + label+="heavyTank"; + if(type==103) + label+="goldMine"; + if(type==104) + label+="constructionYard"; + if(type==105) + label+="factory"; + if(type==106) + label+="communicationCenter"; + if(type==107) + label+="techCenter"; + if(type == 200) + label+="gunTurret"; + if(type == 199) + label+="missileTurret"; + + return label + " " + centre.x + " " + centre.z; + } + + + public void printCurrentCommand(){ + if(currentCommand == StandBy) + System.out.println("currentCommand = Standby"); + if(currentCommand == move) + System.out.println("currentCommand = move"); + if(currentCommand == attackCautiously) + System.out.println("currentCommand = attackCautiously"); + if(currentCommand == attackInNumbers) + System.out.println("currentCommand = attackInNumbers"); + if(currentCommand == attackMove) + System.out.println("currentCommand = attackMove"); + } + + public void printMovementStatus(){ + if(currentMovementStatus == freeToMove) + System.out.println("currentMovementStatus = freeToMove"); + if(currentMovementStatus == hugLeft) + System.out.println("currentMovementStatus = hugLeft"); + if(currentMovementStatus == hugRight) + System.out.println("currentMovementStatus = hugRight"); + } + + public void printAttackStatus(){ + if(attackStatus == noTarget) + System.out.println("attackStatus = noTarget"); + if(attackStatus == isAttacking) + System.out.println("attackStatus = isAttacking"); + if(attackStatus == notInRange) + System.out.println("attackStatus = notInRange"); + } + + + public double getDistance(solidObject o){ + return Math.sqrt((centre.x - o.centre.x)*(centre.x - o.centre.x) + (centre.z - o.centre.z)*(centre.z - o.centre.z)); + } + + public void attackMoveTo(float destinationX, float destinationY){ + + + movement.reset(); + turretAngleDelta = 0; + bodyAngleDelta = 0; + currentMovementStatus = freeToMove; + attackStatus = noTarget; + stuckCount = 0; + //destinationX = centre.x; + //destinationY = centre.z; + insideDeistinationRadiusCount = 0; + obstacle = null; + closeToDestination = false; + + this.destinationX = destinationX; + this.destinationY = destinationY; + newDestinationisGiven = true; + + secondaryDestinationX = destinationX; + secondaryDestinationY = destinationY; + } + + public vector getMovement(){ + return movement; + } + + public void moveTo(float destinationX, float destinationY){ + float distanceToDestination = (destinationX - centre.x)*(destinationX - centre.x) + (destinationY - centre.z)*(destinationY - centre.z); + + if((destinationX - this.destinationX)*(destinationX - this.destinationX) + (destinationY - this.destinationY)*(destinationY - this.destinationY) > 0.05 || distanceToDestination < 0.1){ + resetLogicStatus(); + + this.destinationX = destinationX; + this.destinationY = destinationY; + + + newDestinationisGiven = true; + + } + } + + + + + + public void attack(solidObject o){ + if(targetObject != o){ + targetObject = o; + resetLogicStatus(); + } + } + + public void resetLogicStatus(){ + if(movement != null) + movement.reset(); + turretAngleDelta = 0; + bodyAngleDelta = 0; + currentMovementStatus = freeToMove; + attackStatus = noTarget; + stuckCount = 0; + destinationX = centre.x; + destinationY = centre.z; + insideDeistinationRadiusCount = 0; + obstacle = null; + closeToDestination = false; + } + + + public boolean willDieFromIncomingAttack() { + return currentHP - incomingDamage <= 0; + } + + //to be implemented in child classes + public void update(){} + public void draw(){} + public void harvest(solidObject o){} + public void returnToRefinery(solidObject o){} + public void hold(){currentCommand = StandBy;} + public int getMaxHp(){return 0;} + +} diff --git a/entity/stealthTank.java b/entity/stealthTank.java new file mode 100644 index 0000000..55a934f --- /dev/null +++ b/entity/stealthTank.java @@ -0,0 +1,1364 @@ +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,908, 597); + + //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,688, 432); + + //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= 80; + + //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.frameIndex%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(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 - 1000); + 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]; + + if(teamNo == 0 || attackStatus == isAttacking || exposedCountDown > 0 || visible_minimap){ + if(!(isCloaked && teamNo!=0)){ + 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.frameIndex + 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.frameIndex)%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){ + 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 == 7 || targetObject.type > 100 || targetObject.type == 2 || targetObject.type == 3){ + myDamageModified=(int)(myDamage*0.4); + } + + //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(secondaryTargets[i].type == 7 || targetObject.type == 2 || targetObject.type == 3){ + myDamageModified=(int)(myDamage*0.4); + } + + + 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.frameIndex * 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;} +} diff --git a/entity/techCenter.java b/entity/techCenter.java new file mode 100644 index 0000000..ba88f85 --- /dev/null +++ b/entity/techCenter.java @@ -0,0 +1,1871 @@ +package entity; + +import java.awt.Rectangle; + +import core.*; +import enemyAI.enemyCommander; + +//the power plant model +public class techCenter extends solidObject{ + + //the polygons of the model + private polygon3D[] polygons; + + public static int maxHP = 600; + + public int countDownToDeath = 16; + + public vector tempVector = new vector(0,0,0); + public vector tempVector0 = new vector(0,0,0); + public vector tempVector1 = new vector(0,0,0); + public vector tempVector2 = new vector(0,0,0); + public vector tempVector3 = new vector(0,0,0); + + public int [] tileIndex = new int[9]; + public int[] tempInt; + + public float[] tempFloat; + + public vector shadowvertex0, tempshadowvertex0,shadowvertex1, tempshadowvertex1,shadowvertex2, tempshadowvertex2,shadowvertex3, tempshadowvertex3; + + //a screen space boundary which is used to test if the object is visible from camera point of view + public final static Rectangle visibleBoundary = new Rectangle(-85,-85,920, 762); + + //a screen space boundary which is used to test if the entire object is within the screen + public final static Rectangle screenBoundary = new Rectangle(60,60,648, 402); + + //screen space boundary which is used to test if the shadow of the object is within the screen + public final static Rectangle shadowBoundary1 = new Rectangle(0,0,768, 512); + + //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,1600, 2000); + + //a bitmap representation of the vision of the power plant for enemy commander + public static boolean[] bitmapVisionForEnemy; + + //Tech center never moves + public final static vector movenment = new vector(0,0,0); + + public baseInfo theBaseInfo; + + public int towerTopRed = 31; + public int towerTopGreen = 0; + public int towerTopBlue = 0; + + public int towerTopRedBase = 12; + public int towerTopGreenBase = 4; + public int towerTopBlueBase = 4; + + public static boolean lightTankResearched_player, lightTankResearched_enemy, + rocketTankResearched_player,rocketTankResearched_enemy, + stealthTankResearched_player, stealthTankResearched_enemy, + heavyTankResearched_player,heavyTankResearched_enemy; + + public static int lightTankResearchProgress_player = 255, lightTankResearchProgress_enemy = 255, + rocketTankResearchProgress_player = 255, rocketTankResearchProgress_enemy = 255, + stealthTankResearchProgress_player = 255, stealthTankResearchProgress_enemy = 255, + heavyTankResearchProgress_player = 255, heavyTankResearchProgress_enemy = 255; + + public static int creditSpentOnResearching_player, creditSpentOnResearching_enemy; + + public static int intendedDeployLocation = -1; + + public techCenter(float x, float y, float z, int teamNo){ + //uncontrollable unit, but act as a big sized static collidable agent + type = 107; + + if(teamNo == 0){ + isRevealed = true; + theBaseInfo = mainThread.pc.theBaseInfo; + }else{ + theBaseInfo = mainThread.ec.theBaseInfo; + } + + ID = globalUniqID++; + + theBaseInfo.numberOfTechCenter++; + + currentHP = 600; + + this.teamNo = teamNo; + + currentCommand = StandBy; + + if(teamNo == 0){ + isRevealed = true; + } + + if(bitmapVisionForEnemy == null){ + bitmapVisionForEnemy = createBitmapVision(8); + } + + //create 2D boundary + boundary2D = new Rect((int)(x*64) - 16, (int)(z*64) + 16, 32, 32); + boundary2D.owner = this; + int centerX = (int)(x*64); + int centerY = (int)(z*64); + + tileIndex[0] = (centerX - 8)/16 + (127 - (centerY + 8)/16)*128; + tileIndex[1] = (centerX + 8)/16 + (127 - (centerY + 8)/16)*128; + tileIndex[2] = (centerX + 8)/16 + (127 - (centerY - 8)/16)*128; + tileIndex[3] = (centerX - 8)/16 + (127 - (centerY - 8)/16)*128; + + mainThread.gridMap.tiles[tileIndex[0]][0] = this; + mainThread.gridMap.tiles[tileIndex[1]][0] = this; + mainThread.gridMap.tiles[tileIndex[2]][0] = this; + mainThread.gridMap.tiles[tileIndex[3]][0] = this; + + mainThread.gridMap.tiles[tileIndex[0]][1] = this; + mainThread.gridMap.tiles[tileIndex[1]][1] = this; + mainThread.gridMap.tiles[tileIndex[2]][1] = this; + mainThread.gridMap.tiles[tileIndex[3]][1] = this; + + mainThread.gridMap.tiles[tileIndex[0]][2] = this; + mainThread.gridMap.tiles[tileIndex[1]][2] = this; + mainThread.gridMap.tiles[tileIndex[2]][2] = this; + mainThread.gridMap.tiles[tileIndex[3]][2] = this; + + mainThread.gridMap.tiles[tileIndex[0]][3] = this; + mainThread.gridMap.tiles[tileIndex[1]][3] = this; + mainThread.gridMap.tiles[tileIndex[2]][3] = this; + mainThread.gridMap.tiles[tileIndex[3]][3] = this; + + mainThread.gridMap.tiles[tileIndex[0]][4] = this; + mainThread.gridMap.tiles[tileIndex[1]][4] = this; + mainThread.gridMap.tiles[tileIndex[2]][4] = this; + mainThread.gridMap.tiles[tileIndex[3]][4] = this; + + if(teamNo != 0){ + tileIndex[4] = tileIndex[1] - 128; + tileIndex[5] = tileIndex[1] - 130; + tileIndex[6] = tileIndex[1] + 256; + tileIndex[7] = tileIndex[1] + 254; + tileIndex[8] = tileIndex[1] + 126; + + mainThread.gridMap.tiles[tileIndex[4]][4] = this; + mainThread.gridMap.tiles[tileIndex[5]][4] = this; + mainThread.gridMap.tiles[tileIndex[6]][4] = this; + mainThread.gridMap.tiles[tileIndex[7]][4] = this; + mainThread.gridMap.tiles[tileIndex[8]][4] = this; + } + + + + //init model + start = new vector(x,y,z); + iDirection = new vector(1f,0,0); + jDirection = new vector(0,1f,0); + kDirection = new vector(0,0,1f); + + + //define centre of the model in world coordinate + start = new vector(x,y,z); + centre = start.myClone(); + tempCentre = start.myClone(); + + shadowvertex0 =start.myClone(); + shadowvertex0.add(-0.45f,-0.2f, -0.15f); + tempshadowvertex0 = new vector(0,0,0); + + shadowvertex1 =start.myClone(); + shadowvertex1.add(-0.45f,-0.2f, 0.2f); + tempshadowvertex1 = new vector(0,0,0); + + shadowvertex2 =start.myClone(); + shadowvertex2.add(0.2f,-0.2f, -0.15f); + tempshadowvertex2 = new vector(0,0,0); + + shadowvertex3 =start.myClone(); + shadowvertex3.add(0.2f,-0.2f, 0.2f); + tempshadowvertex3 = new vector(0,0,0); + + + makePolygons(); + + } + + public void makePolygons(){ + int textureIndex = 44; + if(teamNo == 1) + textureIndex = 53; + + polygons = new polygon3D[365]; + + v = new vector[]{put(-0.25, 0.01, 0.22), put(-0.215, 0.01, 0.255), put(0.215, 0.01, 0.255), put(0.25, 0.01, 0.22), put(0.25, 0.01, -0.22), put(0.215, 0.01, -0.255), put(-0.215, 0.01, -0.255), put(-0.25, 0.01, -0.22)}; + polygons[0] = new polygon3D(v, put(-0.38, 0.01, 0.385), put(0.38, 0.01, 0.385), put(-0.38, 0.01, -0.385), mainThread.textures[30], 0.66f,0.66f,1); + polygons[0].shadowBias = 10000; + + v = new vector[]{put(-0.215, 0.01, 0.255), put(-0.25, 0.01, 0.22), put(-0.25, 0.00, 0.22), put(-0.215, 0.0, 0.255)}; + polygons[1] = new polygon3D(v, put(-0.215, 0.01, 0.255), put(-0.25, 0.01, 0.22), put(-0.215, 0.0, 0.255), mainThread.textures[30], 0.66f,0.1f,1); + + v = new vector[]{put(0.215, 0.01, 0.255), put(-0.215, 0.01, 0.255), put(-0.215, 0, 0.255), put(0.215, 0.0, 0.255)}; + polygons[2] = new polygon3D(v, put(0.215, 0.01, 0.255), put(-0.215, 0.01, 0.255), put(0.215, 0.0, 0.255), mainThread.textures[30], 0.55f, 0.1f, 1); + + v = new vector[]{put(0.25, 0.01, 0.22), put(0.215, 0.01, 0.255), put(0.215, 0.0, 0.255), put(0.25, 0.0, 0.22)}; + polygons[3] = new polygon3D(v, put(0.25, 0.01, 0.22), put(0.215, 0.01, 0.255), put(0.25, 0.0, 0.22), mainThread.textures[30], 0.66f,0.1f,1); + + v = new vector[]{put(0.25, 0.01, -0.22), put(0.25, 0.01, 0.22), put(0.25, 0.0, 0.22), put(0.25, 0.0, -0.22)}; + polygons[4] = new polygon3D(v, put(0.25, 0.01, -0.22), put(0.25, 0.01, 0.22), put(0.25, 0.0, -0.22), mainThread.textures[30], 0.66f,0.1f,1); + + v = new vector[]{put(0.215, 0.01, -0.255), put(0.25, 0.01, -0.22), put(0.25, 0.0, -0.22), put(0.215, 0.0, -0.255)}; + polygons[5] = new polygon3D(v, put(0.215, 0.01, -0.255), put(0.25, 0.01, -0.22), put(0.215, 0.0, -0.255), mainThread.textures[30], 0.66f,0.1f,1); + + v = new vector[]{put(-0.215, 0.01, -0.255), put(0.215, 0.01, -0.255), put(0.215, 0.0, -0.255), put(-0.215, 0.0, -0.255)}; + polygons[6] = new polygon3D(v, put(-0.215, 0.01, -0.255), put(0.215, 0.01, -0.255), put(-0.215, 0.0, -0.255), mainThread.textures[30], 0.66f,0.1f,1); + + v = new vector[]{put(-0.25, 0.01, -0.22), put(-0.215, 0.01, -0.255), put(-0.215, 0, -0.255), put(-0.25, 0, -0.22)}; + polygons[7] = new polygon3D(v, put(-0.25, 0.01, -0.22), put(-0.215, 0.01, -0.255), put(-0.25, 0, -0.22), mainThread.textures[30], 0.66f,0.1f,1); + + v = new vector[]{put(-0.25, 0.01, 0.22), put(-0.25, 0.01, -0.22), put(-0.25, 0, -0.22), put(-0.25, 0, 0.22)}; + polygons[8] = new polygon3D(v, put(-0.25, 0.01, 0.22), put(-0.25, 0.01, -0.22), put(-0.25, 0, 0.22), mainThread.textures[30], 0.66f,0.1f,1); + + float w = 0.1105f; + float l = 0.17425f; + float h = 0.16f; + + start.z+=0.11; + + vector [] a = new vector[]{ + put(-l - 0.01f, h, -w + 0.008f ), + put(-l - 0.02f, h, -w + 0.018f ), + put(-l - 0.03f, h, -w + 0.035f ), + put(-l - 0.03f, h, w - 0.035f ), + put(-l - 0.02f, h, w - 0.018f ), + put(-l - 0.01f, h, w - 0.008f ), + + put(-l +0.01f,h, w), + + put(l - 0.01f,h, w), + + put(l + 0.01f, h, w - 0.008f ), + put(l + 0.02f, h, w - 0.018f ), + put(l + 0.03f, h, w - 0.035f ), + put(l + 0.03f, h, -w + 0.035f ), + put(l + 0.02f, h, -w + 0.018f ), + put(l + 0.01f, h, -w + 0.008f ), + + put(l-0.01f,h, -w), + + put(-l+0.01f,h, -w), + }; + + + polygons[9] = new polygon3D(a, put(-l,h, w), put(l,h, w), put(-l,h, -w), mainThread.textures[51], 1,0.5f,1); + polygons[9].diffuse_I-=10; + polygons[9].shadowBias = 5000; + + w = 0.13f; + l = 0.205f; + h = 0.009f; + vector [] b = new vector[]{ + put(-l - 0.01f, h, -w + 0.008f ), + put(-l - 0.02f, h, -w + 0.018f ), + put(-l - 0.03f, h, -w + 0.035f ), + put(-l - 0.03f, h, w - 0.035f ), + put(-l - 0.02f, h, w - 0.018f ), + put(-l - 0.01f, h, w - 0.008f ), + + put(-l +0.01f,h, w), + + put(l - 0.01f,h, w), + + put(l + 0.01f, h, w - 0.008f ), + put(l + 0.02f, h, w - 0.018f ), + put(l + 0.03f, h, w - 0.035f ), + put(l + 0.03f, h, -w + 0.035f ), + put(l + 0.02f, h, -w + 0.018f ), + put(l + 0.01f, h, -w + 0.008f ), + + put(l-0.01f,h, -w), + + put(-l+0.01f,h, -w), + }; + + byte[] diffuse = new byte[]{16,16,16,20,26,34,40,44,47,44,40,34,26,20,16,16}; + + + for(int i = 0; i < 16; i++){ + v = new vector[]{ + a[(i+1)%16].myClone(), + a[i].myClone(), + b[i].myClone(), + b[(i+1)%16].myClone() + }; + + polygons[10 + i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[51], 0.5f,0.5f,1); + polygons[10 + i].diffuse_I = diffuse[i] + (byte)((diffuse[i] - 16)*1.1) ; + } + + //outer + w = 0.13f * 0.86f; + l = 0.205f * 0.86f; + h = 0.18f; + vector [] c = new vector[]{ + put(-l - 0.01f, h, -w + 0.008f ), + put(-l - 0.02f, h, -w + 0.018f ), + put(-l - 0.03f, h, -w + 0.035f ), + put(-l - 0.03f, h, w - 0.035f ), + put(-l - 0.02f, h, w - 0.018f ), + put(-l - 0.01f, h, w - 0.008f ), + + put(-l +0.01f,h, w), + + put(l - 0.01f,h, w), + + put(l + 0.01f, h, w - 0.008f ), + put(l + 0.02f, h, w - 0.018f ), + put(l + 0.03f, h, w - 0.035f ), + put(l + 0.03f, h, -w + 0.035f ), + put(l + 0.02f, h, -w + 0.018f ), + put(l + 0.01f, h, -w + 0.008f ), + + put(l-0.01f,h, -w), + + put(-l+0.01f,h, -w), + }; + + //outer + w = 0.13f * 0.86f; + l = 0.205f * 0.86f; + h = 0.15f; + + vector [] d = new vector[]{ + put(-l - 0.01f, h, -w + 0.008f ), + put(-l - 0.02f, h, -w + 0.018f ), + put(-l - 0.03f, h, -w + 0.035f ), + put(-l - 0.03f, h, w - 0.035f ), + put(-l - 0.02f, h, w - 0.018f ), + put(-l - 0.01f, h, w - 0.008f ), + + put(-l +0.01f,h, w), + + put(l - 0.01f,h, w), + + put(l + 0.01f, h, w - 0.008f ), + put(l + 0.02f, h, w - 0.018f ), + put(l + 0.03f, h, w - 0.035f ), + put(l + 0.03f, h, -w + 0.035f ), + put(l + 0.02f, h, -w + 0.018f ), + put(l + 0.01f, h, -w + 0.008f ), + + put(l-0.01f,h, -w), + + put(-l+0.01f,h, -w), + }; + + for(int i = 0; i < 16; i++){ + + if(i !=14){ + v = new vector[]{ + c[(i+1)%16].myClone(), + c[i].myClone(), + d[i].myClone(), + d[(i+1)%16].myClone() + }; + + + + polygons[26 + i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 10f,10f,1); + polygons[26 + i].diffuse_I = diffuse[i] + (byte)((diffuse[i] - 16)*1.1) ; + }else{ + v = new vector[]{ + c[(i+1)%16].myClone(), + put(l-0.3f,0.18, -w), + put(l-0.3f,0.15, -w), + d[(i+1)%16].myClone() + }; + + + + polygons[26 + i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 10f,10f,1); + polygons[26 + i].diffuse_I = 16; + + + } + + } + + + //inner + w = 0.13f * 0.78f; + l = 0.205f * 0.82f; + h = 0.18f; + vector [] e = new vector[]{ + put(-l - 0.01f, h, -w + 0.008f ), + put(-l - 0.02f, h, -w + 0.018f ), + put(-l - 0.03f, h, -w + 0.035f ), + put(-l - 0.03f, h, w - 0.035f ), + put(-l - 0.02f, h, w - 0.018f ), + put(-l - 0.01f, h, w - 0.008f ), + + put(-l +0.01f,h, w), + + put(l - 0.01f,h, w), + + put(l + 0.01f, h, w - 0.008f ), + put(l + 0.02f, h, w - 0.018f ), + put(l + 0.03f, h, w - 0.035f ), + put(l + 0.03f, h, -w + 0.035f ), + put(l + 0.02f, h, -w + 0.018f ), + put(l + 0.01f, h, -w + 0.008f ), + + put(l-0.01f,h, -w), + + put(-l+0.01f,h, -w), + }; + + + + //inner + w = 0.13f * 0.78f; + l = 0.205f * 0.82f; + h = 0.15f; + + vector [] f = new vector[]{ + put(-l - 0.01f, h, -w + 0.008f ), + put(-l - 0.02f, h, -w + 0.018f ), + put(-l - 0.03f, h, -w + 0.035f ), + put(-l - 0.03f, h, w - 0.035f ), + put(-l - 0.02f, h, w - 0.018f ), + put(-l - 0.01f, h, w - 0.008f ), + + put(-l +0.01f,h, w), + + put(l - 0.01f,h, w), + + put(l + 0.01f, h, w - 0.008f ), + put(l + 0.02f, h, w - 0.018f ), + put(l + 0.03f, h, w - 0.035f ), + put(l + 0.03f, h, -w + 0.035f ), + put(l + 0.02f, h, -w + 0.018f ), + put(l + 0.01f, h, -w + 0.008f ), + + put(l-0.01f,h, -w), + + put(-l+0.01f,h, -w), + }; + + for(int i = 0; i < 16; i++){ + + if(i != 14){ + v = new vector[]{ + f[(i+1)%16].myClone(), + f[i].myClone(), + e[i].myClone(), + e[(i+1)%16].myClone() + }; + + polygons[42 + i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 10f,10f,1); + polygons[42 + i].diffuse_I = diffuse[(i+8)%16] + (byte)((diffuse[(i+8)%16] - 16)*1.1); + }else{ + v = new vector[]{ + f[(i+1)%16].myClone(), + put(-0.12370001f,0.15, -w), + put(-0.12370001f,0.18, -w), + e[(i+1)%16].myClone() + + }; + polygons[42 + i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 10f,10f,1); + polygons[42 + i].diffuse_I = 66; + + } + } + + v = new vector[]{ + put(-0.12370001f,0.18, -(0.13f * 0.86f)), + put(-0.12370001f,0.18, -w), + put(-0.12370001f,0.15, -w), + put(-0.12370001f,0.15, -(0.13f * 0.86f)), + + }; + polygons[58] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 10f,10f,1); + + + //top + for(int i = 0; i < 16; i++){ + if(i != 15){ + v = new vector[]{ + e[i].myClone(), + e[(i+15)%16].myClone(), + c[(i+15)%16].myClone(), + c[i].myClone() + }; + + polygons[59+ i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 10f,10f,1); + }else{ + v = new vector[]{ + e[i].myClone(), + put(-0.12370001f,0.18, -w), + put(-0.12370001f,0.18, -(0.13f * 0.86f)), + c[i].myClone() + }; + + polygons[59+ i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex],10f,10f,1); + } + } + + v = new vector[]{ + put(l-0.1f,0.18, -(0.13f * 0.86f)), + c[14].myClone(), + d[14].myClone(), + put(l-0.1f,0.15, -(0.13f * 0.86f)), + + }; + polygons[75] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex],10f,10f,1); + + v = new vector[]{ + put(l-0.1f,0.15, -(0.13f * 0.78f)), + f[14].myClone(), + e[14].myClone(), + put(l-0.1f,0.18, -(0.13f * 0.78f)) + }; + polygons[76] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex],10f,10f,1); + + + v = new vector[]{ + put(l-0.1f,0.18, -(0.13f * 0.86f)), + put(l-0.1f,0.18, -(0.13f * 0.78f)), + e[14].myClone(), + c[14].myClone(), + }; + polygons[77] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex],10f,10f,1); + + + v = new vector[]{ + put(l-0.1f,0.18, -(0.13f * 0.78f)), + put(l-0.1f,0.18, -(0.13f * 0.86f)), + put(l-0.1f,0.15, -(0.13f * 0.86f)), + put(l-0.1f,0.15, -(0.13f * 0.78f)), + }; + polygons[78] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex],10f,10f,1); + + + //south part of the building + + start.z-=0.195; + start.x-=0.03; + + w = 0.15f*0.7f; + l = 0.1f*0.7f; + h = 0.16f; + + a = new vector[]{ + put(-l - 0.01f, h, -w + 0.008f ), + put(-l - 0.02f, h, -w + 0.018f ), + put(-l - 0.03f, h, -w + 0.035f ), + put(-l - 0.03f, h, w - 0.035f ), + put(-l - 0.02f, h, w - 0.018f ), + put(-l - 0.01f, h, w - 0.008f ), + + put(-l +0.01f,h, w), + + put(l - 0.01f,h, w), + + put(l + 0.01f, h, w - 0.008f ), + put(l + 0.02f, h, w - 0.018f ), + put(l + 0.03f, h, w - 0.035f ), + put(l + 0.03f, h, -w + 0.035f ), + put(l + 0.02f, h, -w + 0.018f ), + put(l + 0.01f, h, -w + 0.008f ), + + put(l-0.01f,h, -w), + + put(-l+0.01f,h, -w), + }; + + + polygons[79] = new polygon3D(a, put(-l,h, w), put(l,h, w), put(-l,h, -w), mainThread.textures[51], 1,0.5f,1); + polygons[79].diffuse_I-=10; + polygons[79].shadowBias = 5000; + + w = 0.15f; + l = 0.1f; + h = 0.009f; + b = new vector[]{ + put(-l - 0.01f, h, -w + 0.008f ), + put(-l - 0.02f, h, -w + 0.018f ), + put(-l - 0.03f, h, -w + 0.035f ), + put(-l - 0.03f, h, w - 0.035f ), + put(-l - 0.02f, h, w - 0.018f ), + put(-l - 0.01f, h, w - 0.008f ), + + put(-l +0.01f,h, w), + + put(l - 0.01f,h, w), + + put(l + 0.01f, h, w - 0.008f ), + put(l + 0.02f, h, w - 0.018f ), + put(l + 0.03f, h, w - 0.035f ), + put(l + 0.03f, h, -w + 0.035f ), + put(l + 0.02f, h, -w + 0.018f ), + put(l + 0.01f, h, -w + 0.008f ), + + put(l-0.01f,h, -w), + + put(-l+0.01f,h, -w), + }; + + + for(int i = 0; i < 16; i++){ + v = new vector[]{ + a[(i+1)%16].myClone(), + a[i].myClone(), + b[i].myClone(), + b[(i+1)%16].myClone() + }; + + polygons[80 + i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[51], 0.5f,0.5f,1); + polygons[80 + i].diffuse_I = diffuse[i] + (byte)((diffuse[i] - 16)*1.1) ; + } + + //inner + start.z +=0.01f; + start.x+=0.003f; + + w = 0.12f*0.9f; + l = 0.08f*0.85f; + h = 0.18f; + + a = new vector[]{ + put(-l - 0.01f, h, -w + 0.008f ), + put(-l - 0.02f, h, -w + 0.018f ), + put(-l - 0.03f, h, -w + 0.035f ), + put(-l - 0.03f, h, w - 0.035f ), + put(-l - 0.02f, h, w - 0.018f ), + put(-l - 0.01f, h, w - 0.008f ), + + put(-l +0.01f,h, w), + + put(l - 0.01f,h, w), + + put(l + 0.01f, h, w - 0.008f ), + put(l + 0.02f, h, w - 0.018f ), + put(l + 0.03f, h, w - 0.035f ), + put(l + 0.03f, h, -w + 0.035f ), + put(l + 0.02f, h, -w + 0.018f ), + put(l + 0.01f, h, -w + 0.008f ), + + put(l-0.01f,h, -w), + + put(-l+0.01f,h, -w), + }; + + h = 0.15f; + c = new vector[]{ + put(-l - 0.01f, h, -w + 0.008f ), + put(-l - 0.02f, h, -w + 0.018f ), + put(-l - 0.03f, h, -w + 0.035f ), + put(-l - 0.03f, h, w - 0.035f ), + put(-l - 0.02f, h, w - 0.018f ), + put(-l - 0.01f, h, w - 0.008f ), + + put(-l +0.01f,h, w), + + put(l - 0.01f,h, w), + + put(l + 0.01f, h, w - 0.008f ), + put(l + 0.02f, h, w - 0.018f ), + put(l + 0.03f, h, w - 0.035f ), + put(l + 0.03f, h, -w + 0.035f ), + put(l + 0.02f, h, -w + 0.018f ), + put(l + 0.01f, h, -w + 0.008f ), + + put(l-0.01f,h, -w), + + put(-l+0.01f,h, -w), + }; + + //outer + w = 0.12f; + l = 0.08f; + h = 0.18f; + b = new vector[]{ + put(-l - 0.01f, h, -w + 0.008f ), + put(-l - 0.02f, h, -w + 0.018f ), + put(-l - 0.03f, h, -w + 0.035f ), + put(-l - 0.03f, h, w - 0.035f ), + put(-l - 0.02f, h, w - 0.018f ), + put(-l - 0.01f, h, w - 0.008f ), + + put(-l +0.01f,h, w), + + put(l - 0.01f,h, w), + + put(l + 0.01f, h, w - 0.008f ), + put(l + 0.02f, h, w - 0.018f ), + put(l + 0.03f, h, w - 0.035f ), + put(l + 0.03f, h, -w + 0.035f ), + put(l + 0.02f, h, -w + 0.018f ), + put(l + 0.01f, h, -w + 0.008f ), + + put(l-0.01f,h, -w), + + put(-l+0.01f,h, -w), + }; + + h = 0.15f; + d = new vector[]{ + put(-l - 0.01f, h, -w + 0.008f ), + put(-l - 0.02f, h, -w + 0.018f ), + put(-l - 0.03f, h, -w + 0.035f ), + put(-l - 0.03f, h, w - 0.035f ), + put(-l - 0.02f, h, w - 0.018f ), + put(-l - 0.01f, h, w - 0.008f ), + + put(-l +0.01f,h, w), + + put(l - 0.01f,h, w), + + put(l + 0.01f, h, w - 0.008f ), + put(l + 0.02f, h, w - 0.018f ), + put(l + 0.03f, h, w - 0.035f ), + put(l + 0.03f, h, -w + 0.035f ), + put(l + 0.02f, h, -w + 0.018f ), + put(l + 0.01f, h, -w + 0.008f ), + + put(l-0.01f,h, -w), + + put(-l+0.01f,h, -w), + }; + + + for(int i = 0; i < 16; i++){ + if(i >= 3 && i <=9){ + continue; + } + + v = new vector[]{ + a[(i+1)%16].myClone(), + a[i].myClone(), + b[i].myClone(), + b[(i+1)%16].myClone() + }; + + polygons[96 + i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 10f,10f,1); + } + + //outer + for(int i = 0; i < 16; i++){ + if(i >= 4 && i <=10) + continue; + + v = new vector[]{ + b[i].myClone(), + b[(i+15)%16].myClone(), + d[(i+15)%16].myClone(), + d[i].myClone(), + }; + polygons[112 + i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 10f,10f,1); + polygons[112 + i].diffuse_I = diffuse[i] + (byte)((diffuse[i] - 16)*1.1); + polygons[112 + i].shadowBias = 10000; + + } + + //inner + for(int i = 0; i < 16; i++){ + if(i >= 4 && i <=10) + continue; + + v = new vector[]{ + c[i].myClone(), + c[(i+15)%16].myClone(), + a[(i+15)%16].myClone(), + a[i].myClone() + }; + polygons[128 + i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 10f,10f,1); + polygons[128 + i].diffuse_I = diffuse[(i+8)%16] + (byte)((diffuse[(i+8)%16] - 16)*1.1); + + } + + + //top part of the building + start.z+=0.18; + start.x-=0.04; + + w = 0.15f*0.55f; + l = 0.12f*0.45f; + h = 0.3f; + + a = new vector[]{ + put(-l - 0.01f, h, -w + 0.008f ), + put(-l - 0.02f, h, -w + 0.018f ), + put(-l - 0.03f, h, -w + 0.035f ), + put(-l - 0.03f, h, w - 0.035f ), + put(-l - 0.02f, h, w - 0.018f ), + put(-l - 0.01f, h, w - 0.008f ), + + put(-l +0.01f,h, w), + + put(l - 0.01f,h, w), + + put(l + 0.01f, h, w - 0.008f ), + put(l + 0.02f, h, w - 0.018f ), + put(l + 0.03f, h, w - 0.035f ), + put(l + 0.03f, h, -w + 0.035f ), + put(l + 0.02f, h, -w + 0.018f ), + put(l + 0.01f, h, -w + 0.008f ), + + put(l-0.01f,h, -w), + + put(-l+0.01f,h, -w), + }; + + + polygons[144] = new polygon3D(a, put(-l,h, w), put(l,h, w), put(-l,h, -w), mainThread.textures[13], 0.5f,0.5f,1); + polygons[144].diffuse_I-=10; + polygons[144].shadowBias = 5000; + + w = 0.15f*0.55f; + l = 0.12f*0.6f; + h = 0.16f; + b = new vector[]{ + put(-l - 0.01f, h, -w + 0.008f ), + put(-l - 0.02f, h, -w + 0.018f ), + put(-l - 0.03f, h, -w + 0.035f ), + put(-l - 0.03f, h, w - 0.035f ), + put(-l - 0.02f, h, w - 0.018f ), + put(-l - 0.01f, h, w - 0.008f ), + + put(-l +0.01f,h, w), + + put(l - 0.01f,h, w), + + put(l + 0.01f, h, w - 0.008f ), + put(l + 0.02f, h, w - 0.018f ), + put(l + 0.03f, h, w - 0.035f ), + put(l + 0.03f, h, -w + 0.035f ), + put(l + 0.02f, h, -w + 0.018f ), + put(l + 0.01f, h, -w + 0.008f ), + + put(l-0.01f,h, -w), + + put(-l+0.01f,h, -w), + }; + + + for(int i = 0; i < 16; i++){ + v = new vector[]{ + a[(i+1)%16].myClone(), + a[i].myClone(), + b[i].myClone(), + b[(i+1)%16].myClone() + }; + + polygons[145 + i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[13], 0.5f,0.5f,1); + polygons[145 + i].diffuse_I = diffuse[i] + (byte)((diffuse[i] - 16)*1.1) ; + } + + + //outer + w = 0.15f*0.55f; + l = 0.12f*0.45f; + h = 0.32f; + + a = new vector[]{ + put(-l - 0.01f, h, -w + 0.008f ), + put(-l - 0.02f, h, -w + 0.018f ), + put(-l - 0.03f, h, -w + 0.035f ), + put(-l - 0.03f, h, w - 0.035f ), + put(-l - 0.02f, h, w - 0.018f ), + put(-l - 0.01f, h, w - 0.008f ), + + put(-l +0.01f,h, w), + + put(l - 0.01f,h, w), + + put(l + 0.01f, h, w - 0.008f ), + put(l + 0.02f, h, w - 0.018f ), + put(l + 0.03f, h, w - 0.035f ), + put(l + 0.03f, h, -w + 0.035f ), + put(l + 0.02f, h, -w + 0.018f ), + put(l + 0.01f, h, -w + 0.008f ), + + put(l-0.01f,h, -w), + + put(-l+0.01f,h, -w), + }; + + h = 0.29f; + c = new vector[]{ + put(-l - 0.01f, h, -w + 0.008f ), + put(-l - 0.02f, h, -w + 0.018f ), + put(-l - 0.03f, h, -w + 0.035f ), + put(-l - 0.03f, h, w - 0.035f ), + put(-l - 0.02f, h, w - 0.018f ), + put(-l - 0.01f, h, w - 0.008f ), + + put(-l +0.01f,h, w), + + put(l - 0.01f,h, w), + + put(l + 0.01f, h, w - 0.008f ), + put(l + 0.02f, h, w - 0.018f ), + put(l + 0.03f, h, w - 0.035f ), + put(l + 0.03f, h, -w + 0.035f ), + put(l + 0.02f, h, -w + 0.018f ), + put(l + 0.01f, h, -w + 0.008f ), + + put(l-0.01f,h, -w), + + put(-l+0.01f,h, -w), + }; + + //inner + w = 0.15f*0.49f; + l = 0.12f*0.38f; + h = 0.32f; + + b = new vector[]{ + put(-l - 0.01f, h, -w + 0.008f ), + put(-l - 0.02f, h, -w + 0.018f ), + put(-l - 0.03f, h, -w + 0.035f ), + put(-l - 0.03f, h, w - 0.035f ), + put(-l - 0.02f, h, w - 0.018f ), + put(-l - 0.01f, h, w - 0.008f ), + + put(-l +0.01f,h, w), + + put(l - 0.01f,h, w), + + put(l + 0.01f, h, w - 0.008f ), + put(l + 0.02f, h, w - 0.018f ), + put(l + 0.03f, h, w - 0.035f ), + put(l + 0.03f, h, -w + 0.035f ), + put(l + 0.02f, h, -w + 0.018f ), + put(l + 0.01f, h, -w + 0.008f ), + + put(l-0.01f,h, -w), + + put(-l+0.01f,h, -w), + }; + + h = 0.29f; + + d = new vector[]{ + put(-l - 0.01f, h, -w + 0.008f ), + put(-l - 0.02f, h, -w + 0.018f ), + put(-l - 0.03f, h, -w + 0.035f ), + put(-l - 0.03f, h, w - 0.035f ), + put(-l - 0.02f, h, w - 0.018f ), + put(-l - 0.01f, h, w - 0.008f ), + + put(-l +0.01f,h, w), + + put(l - 0.01f,h, w), + + put(l + 0.01f, h, w - 0.008f ), + put(l + 0.02f, h, w - 0.018f ), + put(l + 0.03f, h, w - 0.035f ), + put(l + 0.03f, h, -w + 0.035f ), + put(l + 0.02f, h, -w + 0.018f ), + put(l + 0.01f, h, -w + 0.008f ), + + put(l-0.01f,h, -w), + + put(-l+0.01f,h, -w), + }; + + for(int i = 0; i < 16; i++){ + v = new vector[]{ + b[i].myClone(), + b[(i+15)%16].myClone(), + a[(i+15)%16].myClone(), + a[i].myClone(), + }; + polygons[161 + i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 10f,10f,1); + + } + + for(int i = 0; i < 16; i++){ + v = new vector[]{ + a[i].myClone(), + a[(i+15)%16].myClone(), + c[(i+15)%16].myClone(), + c[i].myClone(), + }; + polygons[177 + i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 10f,10f,1); + polygons[177 + i].diffuse_I = diffuse[i] + (byte)((diffuse[i] - 16)*1.1); + } + + for(int i = 0; i < 16; i++){ + v = new vector[]{ + d[i].myClone(), + d[(i+15)%16].myClone(), + b[(i+15)%16].myClone(), + b[i].myClone(), + }; + polygons[193 + i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[textureIndex], 10f,10f,1); + polygons[193 + i].diffuse_I = diffuse[(i+8)%16] + (byte)((diffuse[(i+8)%16] - 16)*1.1); + } + + start.z-=0.24f; + start.y-=0.04f; + start.x+=0.01f; + v = new vector[]{put(-0.04, 0.3, 0.04), put(0.04, 0.24, 0.04), put(0.04, 0.24, -0.04), put(-0.04, 0.3, -0.04)}; + polygons[209] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[70], 1f,1f,1); + + v = new vector[]{put(-0.007,0.27, 0.007), put(-0.007,0.27, -0.007), put(-0.007, 0.2, -0.007), put(-0.007, 0.2, 0.007)}; + polygons[210] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[26], 10f,10f,1); + + v = new vector[]{put(-0.007,0.27, -0.007), put(0.007,0.27, -0.007), put(0.007,0.2, -0.007), put(-0.007,0.2, -0.007)}; + polygons[211] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[26], 10f,10f,1); + + v = new vector[]{put(-0.007,0.2, 0.007), put(0.007,0.2, 0.007), put(0.007,0.27, 0.007), put(-0.007,0.27, 0.007)}; + polygons[212] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[26], 10f,10f,1); + + v = new vector[]{put(0.007, 0.2, 0.007), put(0.007, 0.2, -0.007), put(0.007,0.27, -0.007), put(0.007,0.27, 0.007)}; + polygons[213] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[26], 10f,10f,1); + + v = new vector[]{put(-0.04, 0.3, 0.04), put(-0.04, 0.3, -0.04), put(-0.04, 0.29, -0.04), put(-0.04, 0.29, 0.04)}; + polygons[214] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10f,10f,1); + + v = new vector[]{put(-0.04, 0.3, -0.04), put(0.04, 0.24, -0.04), put(0.04, 0.23, -0.04), put(-0.04, 0.29, -0.04)}; + polygons[215] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10f,10f,1); + + v = new vector[]{put(-0.04, 0.29, 0.04), put(0.04, 0.23, 0.04), put(0.04, 0.24, 0.04), put(-0.04, 0.3, 0.04)}; + polygons[216] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10f,10f,1); + + v = new vector[]{put(0.04, 0.235, 0.04), put(0.04, 0.235, -0.04), put(0.04, 0.24, -0.04), put(0.04, 0.24, 0.04)}; + polygons[217] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10f,10f,1); + + + + start.z+=0.1f; + start.x+=0.06f; + v = new vector[]{put(-0.04, 0.3, 0.04), put(0.04, 0.24, 0.04), put(0.04, 0.24, -0.04), put(-0.04, 0.3, -0.04)}; + polygons[218] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[70], 1f,1f,1); + + v = new vector[]{put(-0.007,0.27, 0.007), put(-0.007,0.27, -0.007), put(-0.007, 0.2, -0.007), put(-0.007, 0.2, 0.007)}; + polygons[219] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[26], 10f,10f,1); + + v = new vector[]{put(-0.007,0.27, -0.007), put(0.007,0.27, -0.007), put(0.007,0.2, -0.007), put(-0.007,0.2, -0.007)}; + polygons[220] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[26], 10f,10f,1); + + v = new vector[]{put(-0.007,0.2, 0.007), put(0.007,0.2, 0.007), put(0.007,0.27, 0.007), put(-0.007,0.27, 0.007)}; + polygons[221] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[26], 10f,10f,1); + + v = new vector[]{put(0.007, 0.2, 0.007), put(0.007, 0.2, -0.007), put(0.007,0.27, -0.007), put(0.007,0.27, 0.007)}; + polygons[222] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[26], 10f,10f,1); + + v = new vector[]{put(-0.04, 0.3, 0.04), put(-0.04, 0.3, -0.04), put(-0.04, 0.29, -0.04), put(-0.04, 0.29, 0.04)}; + polygons[223] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10f,10f,1); + + v = new vector[]{put(-0.04, 0.3, -0.04), put(0.04, 0.24, -0.04), put(0.04, 0.23, -0.04), put(-0.04, 0.29, -0.04)}; + polygons[224] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10f,10f,1); + + v = new vector[]{put(-0.04, 0.29, 0.04), put(0.04, 0.23, 0.04), put(0.04, 0.24, 0.04), put(-0.04, 0.3, 0.04)}; + polygons[225] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10f,10f,1); + + v = new vector[]{put(0.04, 0.235, 0.04), put(0.04, 0.235, -0.04), put(0.04, 0.24, -0.04), put(0.04, 0.24, 0.04)}; + polygons[226] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10f,10f,1); + + + start.z+=0.09f; + start.x+=0.11f; + + + v = new vector[]{put(-0.04, 0.3, 0.04), put(0.04, 0.24, 0.04), put(0.04, 0.24, -0.04), put(-0.04, 0.3, -0.04)}; + polygons[227] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[70], 1f,1f,1); + + v = new vector[]{put(-0.007,0.27, 0.007), put(-0.007,0.27, -0.007), put(-0.007, 0.2, -0.007), put(-0.007, 0.2, 0.007)}; + polygons[228] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[26], 10f,10f,1); + + v = new vector[]{put(-0.007,0.27, -0.007), put(0.007,0.27, -0.007), put(0.007,0.2, -0.007), put(-0.007,0.2, -0.007)}; + polygons[229] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[26], 10f,10f,1); + + v = new vector[]{put(-0.007,0.2, 0.007), put(0.007,0.2, 0.007), put(0.007,0.27, 0.007), put(-0.007,0.27, 0.007)}; + polygons[230] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[26], 10f,10f,1); + + v = new vector[]{put(0.007, 0.2, 0.007), put(0.007, 0.2, -0.007), put(0.007,0.27, -0.007), put(0.007,0.27, 0.007)}; + polygons[231] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[26], 10f,10f,1); + + v = new vector[]{put(-0.04, 0.3, 0.04), put(-0.04, 0.3, -0.04), put(-0.04, 0.29, -0.04), put(-0.04, 0.29, 0.04)}; + polygons[232] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10f,10f,1); + + v = new vector[]{put(-0.04, 0.3, -0.04), put(0.04, 0.24, -0.04), put(0.04, 0.23, -0.04), put(-0.04, 0.29, -0.04)}; + polygons[233] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10f,10f,1); + + v = new vector[]{put(-0.04, 0.29, 0.04), put(0.04, 0.23, 0.04), put(0.04, 0.24, 0.04), put(-0.04, 0.3, 0.04)}; + polygons[234] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10f,10f,1); + + v = new vector[]{put(0.04, 0.235, 0.04), put(0.04, 0.235, -0.04), put(0.04, 0.24, -0.04), put(0.04, 0.24, 0.04)}; + polygons[235] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10f,10f,1); + + + start.z+=0.1f; + v = new vector[]{put(-0.04, 0.3, 0.04), put(0.04, 0.24, 0.04), put(0.04, 0.24, -0.04), put(-0.04, 0.3, -0.04)}; + polygons[236] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[70], 1f,1f,1); + + v = new vector[]{put(-0.007,0.27, 0.007), put(-0.007,0.27, -0.007), put(-0.007, 0.2, -0.007), put(-0.007, 0.2, 0.007)}; + polygons[237] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[26], 10f,10f,1); + + v = new vector[]{put(-0.007,0.27, -0.007), put(0.007,0.27, -0.007), put(0.007,0.2, -0.007), put(-0.007,0.2, -0.007)}; + polygons[238] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[26], 10f,10f,1); + + v = new vector[]{put(-0.007,0.2, 0.007), put(0.007,0.2, 0.007), put(0.007,0.27, 0.007), put(-0.007,0.27, 0.007)}; + polygons[239] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[26], 10f,10f,1); + + v = new vector[]{put(0.007, 0.2, 0.007), put(0.007, 0.2, -0.007), put(0.007,0.27, -0.007), put(0.007,0.27, 0.007)}; + polygons[240] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[26], 10f,10f,1); + + v = new vector[]{put(-0.04, 0.3, 0.04), put(-0.04, 0.3, -0.04), put(-0.04, 0.29, -0.04), put(-0.04, 0.29, 0.04)}; + polygons[241] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10f,10f,1); + + v = new vector[]{put(-0.04, 0.3, -0.04), put(0.04, 0.24, -0.04), put(0.04, 0.23, -0.04), put(-0.04, 0.29, -0.04)}; + polygons[242] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10f,10f,1); + + v = new vector[]{put(-0.04, 0.29, 0.04), put(0.04, 0.23, 0.04), put(0.04, 0.24, 0.04), put(-0.04, 0.3, 0.04)}; + polygons[243] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10f,10f,1); + + v = new vector[]{put(0.04, 0.235, 0.04), put(0.04, 0.235, -0.04), put(0.04, 0.24, -0.04), put(0.04, 0.24, 0.04)}; + polygons[244] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10f,10f,1); + + + double r1 = 0.004; + double r2 = 0.008; + double theta = Math.PI/8; + + start.y+=0.25; + start.x-=0.15; + start.z-=0.05; + + for(int i = 0; i < 16; i++){ + v = new vector[]{ + put(r1*Math.cos(i*theta), 0.45, r1*Math.sin(i*theta)), + put(r1*Math.cos((i+1)*theta), 0.45, r1*Math.sin((i+1)*theta)), + put(r2*Math.cos((i+1)*theta), 0.05, r2*Math.sin((i+1)*theta)), + put(r2*Math.cos(i*theta), 0.05, r2*Math.sin(i*theta)) + }; + polygons[245 +i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10,10,1); + } + + for(int i = 0; i < 16; i++){ + v = new vector[]{ + put(r1*Math.cos(i*theta), 0.457, r1*Math.sin(i*theta)), + put(r1*Math.cos((i+1)*theta), 0.457, r1*Math.sin((i+1)*theta)), + put(r1*Math.cos((i+1)*theta), 0.45, r1*Math.sin((i+1)*theta)), + put(r1*Math.cos(i*theta), 0.45, r1*Math.sin(i*theta)) + }; + polygons[261 +i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), null, 10,10,0); + } + + v = new vector[16]; + for(int i = 0; i < 16; i++){ + v[15-i] = put(r1*Math.cos(i*theta), 0.457, r1*Math.sin(i*theta)); + } + polygons[277] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), null, 10,10,0); + + + start.x-=0.05; + for(int i = 0; i < 16; i++){ + v = new vector[]{ + put(r1*Math.cos(i*theta), 0.38, r1*Math.sin(i*theta)), + put(r1*Math.cos((i+1)*theta), 0.38, r1*Math.sin((i+1)*theta)), + put(r2*Math.cos((i+1)*theta), 0.05, r2*Math.sin((i+1)*theta)), + put(r2*Math.cos(i*theta), 0.05, r2*Math.sin(i*theta)) + }; + polygons[278 +i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10,10,1); + } + + for(int i = 0; i < 16; i++){ + v = new vector[]{ + put(r1*Math.cos(i*theta), 0.387, r1*Math.sin(i*theta)), + put(r1*Math.cos((i+1)*theta), 0.387, r1*Math.sin((i+1)*theta)), + put(r1*Math.cos((i+1)*theta), 0.38, r1*Math.sin((i+1)*theta)), + put(r1*Math.cos(i*theta), 0.38, r1*Math.sin(i*theta)) + }; + polygons[294 +i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), null, 10,10,0); + } + + + v = new vector[16]; + for(int i = 0; i < 16; i++){ + v[15-i] = put(r1*Math.cos(i*theta), 0.387, r1*Math.sin(i*theta)); + } + polygons[310] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), null, 10,10,0); + + + + start.y+=0.26; + start.x-=0.25; + r1 = 0.005f; + for(int i = 0; i < 16; i++){ + v = new vector[]{ + put(0.25, r1*Math.cos(i*theta),r1*Math.sin(i*theta)), + put(0.25, r1*Math.cos((i+1)*theta), r1*Math.sin((i+1)*theta)), + put(0.3, r1*Math.cos((i+1)*theta), r1*Math.sin((i+1)*theta)), + put(0.3, r1*Math.cos(i*theta),r1*Math.sin(i*theta)) + }; + polygons[311 +i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10,10,1); + } + + start.y+=0.04; + for(int i = 0; i < 16; i++){ + v = new vector[]{ + put(0.25, r1*Math.cos(i*theta),r1*Math.sin(i*theta)), + put(0.25, r1*Math.cos((i+1)*theta), r1*Math.sin((i+1)*theta)), + put(0.3, r1*Math.cos((i+1)*theta), r1*Math.sin((i+1)*theta)), + put(0.3, r1*Math.cos(i*theta),r1*Math.sin(i*theta)) + }; + polygons[327 +i] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[25], 10,10,1); + } + + + + start.x+=0.26f; + start.y-=0.05f; + start.z+=0.01f; + iDirection.rotate_XZ(125); + iDirection.scale(0.85f); + kDirection.rotate_XZ(125); + + v = new vector[]{put(-0.019, 0.017, 0.017), put(0.019, 0.017, 0.017), put(0.019, -0.017, 0.017), put(-0.019, -0.017, 0.017)}; + polygons[343] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[65], 1,1,1); + + v = new vector[]{put(-0.017, -0.017, 0.023), put(0.017, -0.017, 0.023), put(0.017, 0.017, 0.023),put(-0.017, 0.017, 0.023)}; + polygons[344] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[65], 1,1,1); + + v = new vector[]{put(-0.017, 0.017, 0.023), put(0.017, 0.017, 0.023), put(0.019, 0.017, 0.017), put(-0.019, 0.017, 0.017)}; + polygons[345] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[65], 1,1,1); + + v = new vector[]{put(0.017, 0.017, 0.023), put(0.047, 0.013, 0.04), put(0.048, 0.013, 0.035), put(0.019, 0.017, 0.017)}; + polygons[346] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[65], 1,1,1); + + v = new vector[]{put(0.019, 0.017, 0.017), put(0.048, 0.013, 0.035), put(0.048, -0.013, 0.035), put(0.019, -0.017, 0.017)}; + polygons[347] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[65], 1,1,1); + + v = new vector[]{put(0.048, 0.013, 0.035), put(0.047, 0.013, 0.04), put(0.047, -0.013, 0.04), put(0.048, -0.013, 0.035)}; + polygons[348] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[65], 1,1,1); + + v = new vector[]{put(0.047, 0.013, 0.04), put(0.017, 0.017, 0.023), put(0.017, -0.017, 0.023), put(0.047, -0.013, 0.04)}; + polygons[349] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[65], 1,1,1); + + v = new vector[]{put(-0.019, 0.017, 0.017), put(-0.048, 0.013, 0.035), put(-0.047, 0.013, 0.04) ,put(-0.017, 0.017, 0.023)}; + polygons[350] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[65], 1,1,1); + + v = new vector[]{put(-0.019, -0.017, 0.017), put(-0.048, -0.013, 0.035), put(-0.048, 0.013, 0.035) ,put(-0.019, 0.017, 0.017)}; + polygons[351] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[65], 1,1,1); + + v = new vector[]{put(-0.048, -0.013, 0.035), put(-0.047, -0.013, 0.04), put(-0.047, 0.013, 0.04), put(-0.048, 0.013, 0.035)}; + polygons[352] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[65], 1,1,1); + + v = new vector[]{put(-0.047, -0.013, 0.04), put(-0.017, -0.017, 0.023), put(-0.017, 0.017, 0.023), put(-0.047, 0.013, 0.04)}; + polygons[353] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[65], 1,1,1); + + + start.y+=0.08f; + start.x+=0.024f; + start.z-=0.01f; + iDirection.rotate_XZ(165); + kDirection.rotate_XZ(165); + + v = new vector[]{put(-0.019, 0.017, 0.017), put(0.019, 0.017, 0.017), put(0.019, -0.017, 0.017), put(-0.019, -0.017, 0.017)}; + polygons[354] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[65], 1,1,1); + + v = new vector[]{put(-0.017, -0.017, 0.023), put(0.017, -0.017, 0.023), put(0.017, 0.017, 0.023),put(-0.017, 0.017, 0.023)}; + polygons[355] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[65], 1,1,1); + + v = new vector[]{put(-0.017, 0.017, 0.023), put(0.017, 0.017, 0.023), put(0.019, 0.017, 0.017), put(-0.019, 0.017, 0.017)}; + polygons[356] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[65], 1,1,1); + + v = new vector[]{put(0.017, 0.017, 0.023), put(0.047, 0.013, 0.04), put(0.048, 0.013, 0.035), put(0.019, 0.017, 0.017)}; + polygons[357] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[65], 1,1,1); + + v = new vector[]{put(0.019, 0.017, 0.017), put(0.048, 0.013, 0.035), put(0.048, -0.013, 0.035), put(0.019, -0.017, 0.017)}; + polygons[358] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[65], 1,1,1); + + v = new vector[]{put(0.048, 0.013, 0.035), put(0.047, 0.013, 0.04), put(0.047, -0.013, 0.04), put(0.048, -0.013, 0.035)}; + polygons[359] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[65], 1,1,1); + + v = new vector[]{put(0.047, 0.013, 0.04), put(0.017, 0.017, 0.023), put(0.017, -0.017, 0.023), put(0.047, -0.013, 0.04)}; + polygons[360] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[65], 1,1,1); + + v = new vector[]{put(-0.019, 0.017, 0.017), put(-0.048, 0.013, 0.035), put(-0.047, 0.013, 0.04) ,put(-0.017, 0.017, 0.023)}; + polygons[361] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[65], 1,1,1); + + v = new vector[]{put(-0.019, -0.017, 0.017), put(-0.048, -0.013, 0.035), put(-0.048, 0.013, 0.035) ,put(-0.019, 0.017, 0.017)}; + polygons[362] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[65], 1,1,1); + + v = new vector[]{put(-0.048, -0.013, 0.035), put(-0.047, -0.013, 0.04), put(-0.047, 0.013, 0.04), put(-0.048, 0.013, 0.035)}; + polygons[363] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[65], 1,1,1); + + v = new vector[]{put(-0.047, -0.013, 0.04), put(-0.017, -0.017, 0.023), put(-0.017, 0.017, 0.023), put(-0.047, 0.013, 0.04)}; + polygons[364] = new polygon3D(v, v[0].myClone(), v[1].myClone(), v[3].myClone(), mainThread.textures[65], 1,1,1); + + + } + + //update the model + public void update(){ + + //process emerging from ground animation + if(centre.y < -0.5f){ + centre.y+=0.02f; + + if(centre.y > -0.5){ + for(int i = 0; i < polygons.length; i++){ + if(polygons[i] == null) + continue; + polygons[i].origin.y+=0.0000005; + polygons[i].rightEnd.y+=0.0000005; + polygons[i].bottomEnd.y+=0.0000005; + + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + polygons[i].vertex3D[j].y+=0.0000005; + } + + + + } + shadowvertex0.y+=0.0000005; + shadowvertex1.y+=0.0000005; + shadowvertex2.y+=0.0000005; + shadowvertex3.y+=0.0000005; + + centre.y = -0.5f; + }else{ + for(int i = 0; i < polygons.length; i++){ + if(polygons[i] == null) + continue; + + polygons[i].origin.y+=0.02; + polygons[i].rightEnd.y+=0.02; + polygons[i].bottomEnd.y+=0.02; + + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + polygons[i].vertex3D[j].y+=0.02; + } + + + } + shadowvertex0.y+=0.02; + shadowvertex1.y+=0.02; + shadowvertex2.y+=0.02; + shadowvertex3.y+=0.02; + } + + //the building is invulnerable during emerging stage + currentHP = maxHP; + } + + if(underAttackCountDown > 0) + underAttackCountDown--; + + //check if power plant has been destroyed + if(currentHP <= 0){ + countDownToDeath--; + + if(countDownToDeath == 0){ + //spawn an explosion when the tank is destroyed + float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount]; + tempFloat[0] = centre.x; + tempFloat[1] = centre.y + 0.15f; + tempFloat[2] = centre.z; + tempFloat[3] = 3.5f; + tempFloat[4] = 1; + tempFloat[5] = 0; + tempFloat[6] = 7; + tempFloat[7] = this.height; + theAssetManager.explosionCount++; + theAssetManager.removeObject(this); + if(theBaseInfo.numberOfTechCenter == 1) + cancelResearch(teamNo); + + theBaseInfo.numberOfTechCenter--; + + //removeFromGridMap(); + mainThread.gridMap.tiles[tileIndex[0]][0] = null; + mainThread.gridMap.tiles[tileIndex[1]][0] = null; + mainThread.gridMap.tiles[tileIndex[2]][0] = null; + mainThread.gridMap.tiles[tileIndex[3]][0] = null; + + mainThread.gridMap.tiles[tileIndex[0]][1] = null; + mainThread.gridMap.tiles[tileIndex[1]][1] = null; + mainThread.gridMap.tiles[tileIndex[2]][1] = null; + mainThread.gridMap.tiles[tileIndex[3]][1] = null; + + mainThread.gridMap.tiles[tileIndex[0]][2] = null; + mainThread.gridMap.tiles[tileIndex[1]][2] = null; + mainThread.gridMap.tiles[tileIndex[2]][2] = null; + mainThread.gridMap.tiles[tileIndex[3]][2] = null; + + mainThread.gridMap.tiles[tileIndex[0]][3] = null; + mainThread.gridMap.tiles[tileIndex[1]][3] = null; + mainThread.gridMap.tiles[tileIndex[2]][3] = null; + mainThread.gridMap.tiles[tileIndex[3]][3] = null; + + mainThread.gridMap.tiles[tileIndex[0]][4] = null; + mainThread.gridMap.tiles[tileIndex[1]][4] = null; + mainThread.gridMap.tiles[tileIndex[2]][4] = null; + mainThread.gridMap.tiles[tileIndex[3]][4] = null; + + if(teamNo != 0){ + mainThread.gridMap.tiles[tileIndex[4]][4] = null; + mainThread.gridMap.tiles[tileIndex[5]][4] = null; + mainThread.gridMap.tiles[tileIndex[6]][4] = null; + mainThread.gridMap.tiles[tileIndex[7]][4] = null; + mainThread.gridMap.tiles[tileIndex[8]][4] = null; + } + + if(attacker.teamNo != teamNo) + attacker.experience+=50; + return; + }else{ + + float[] tempFloat = theAssetManager.explosionInfo[theAssetManager.explosionCount]; + tempFloat[0] = centre.x + (float)Math.random()/2.5f - 0.2f; + tempFloat[1] = centre.y + 0.15f; + tempFloat[2] = centre.z + (float)Math.random()/2.5f - 0.2f; + tempFloat[3] = 1.5f; + tempFloat[4] = 1; + tempFloat[5] = 0; + tempFloat[6] = 6 + (gameData.getRandom()%4); + tempFloat[7] = this.height; + theAssetManager.explosionCount++; + + + } + } + + //processing repair event + if(isRepairing && currentHP >0){ + if(mainThread.frameIndex%8==0 && theBaseInfo.currentCredit > 0 && currentHP maxHP) + currentHP = maxHP; + } + } + + //process researching + if(mainThread.frameIndex%2==0 && (!(theBaseInfo.lowPower && mainThread.frameIndex%4==0))){ + + //light tank research + if(teamNo == 0){ + if(lightTankResearchProgress_player < 240){ + if(mainThread.pc.theBaseInfo.currentCredit >0){ + mainThread.pc.theBaseInfo.currentCredit--; + creditSpentOnResearching_player++; + lightTankResearchProgress_player = 240 * creditSpentOnResearching_player/1500; + } + + if(lightTankResearchProgress_player == 240){ + lightTankResearched_player = true; + rocketTankResearchProgress_player = 255; + stealthTankResearchProgress_player = 255; + heavyTankResearchProgress_player = 255; + creditSpentOnResearching_player = 0; + upgradeLightTank(0); + } + } + }else{ + if(lightTankResearchProgress_enemy < 240){ + if(mainThread.ec.theBaseInfo.currentCredit >0){ + mainThread.ec.theBaseInfo.currentCredit--; + creditSpentOnResearching_enemy++; + lightTankResearchProgress_enemy = 240 * creditSpentOnResearching_enemy/1500; + } + } + + if(lightTankResearchProgress_enemy == 240){ + lightTankResearched_enemy = true; + rocketTankResearchProgress_enemy = 255; + stealthTankResearchProgress_enemy = 255; + heavyTankResearchProgress_enemy = 255; + creditSpentOnResearching_enemy = 0; + upgradeLightTank(1); + } + } + + //rocket tank research + if(teamNo == 0){ + if(rocketTankResearchProgress_player < 240){ + if(mainThread.pc.theBaseInfo.currentCredit >0){ + mainThread.pc.theBaseInfo.currentCredit--; + creditSpentOnResearching_player++; + rocketTankResearchProgress_player = 240 * creditSpentOnResearching_player/2000; + } + + if(rocketTankResearchProgress_player == 240){ + rocketTankResearched_player = true; + lightTankResearchProgress_player = 255; + stealthTankResearchProgress_player = 255; + heavyTankResearchProgress_player = 255; + creditSpentOnResearching_player = 0; + upgradeRocketTank(0); + } + } + }else{ + if(rocketTankResearchProgress_enemy < 240){ + if(mainThread.ec.theBaseInfo.currentCredit >0){ + mainThread.ec.theBaseInfo.currentCredit--; + creditSpentOnResearching_enemy++; + rocketTankResearchProgress_enemy = 240 * creditSpentOnResearching_enemy/2000; + } + } + + if(rocketTankResearchProgress_enemy == 240){ + rocketTankResearched_enemy = true; + lightTankResearchProgress_enemy = 255; + stealthTankResearchProgress_enemy = 255; + heavyTankResearchProgress_enemy = 255; + creditSpentOnResearching_enemy = 0; + upgradeRocketTank(1); + } + } + + //stealth tank research + if(teamNo == 0){ + if(stealthTankResearchProgress_player < 240){ + if(mainThread.pc.theBaseInfo.currentCredit >0){ + mainThread.pc.theBaseInfo.currentCredit--; + creditSpentOnResearching_player++; + stealthTankResearchProgress_player = 240 * creditSpentOnResearching_player/2000; + } + + if(stealthTankResearchProgress_player == 240){ + stealthTankResearched_player = true; + lightTankResearchProgress_player = 255; + rocketTankResearchProgress_player = 255; + heavyTankResearchProgress_player = 255; + creditSpentOnResearching_player = 0; + upgradeStealthTank(0); + } + } + }else{ + if(stealthTankResearchProgress_enemy < 240){ + if(mainThread.ec.theBaseInfo.currentCredit >0){ + mainThread.ec.theBaseInfo.currentCredit--; + creditSpentOnResearching_enemy++; + stealthTankResearchProgress_enemy = 240 * creditSpentOnResearching_enemy/2000; + } + } + + if(stealthTankResearchProgress_enemy == 240){ + stealthTankResearched_enemy = true; + lightTankResearchProgress_enemy = 255; + rocketTankResearchProgress_enemy = 255; + heavyTankResearchProgress_enemy = 255; + creditSpentOnResearching_enemy = 0; + upgradeStealthTank(1); + } + } + + //heavy tank research + if(teamNo == 0){ + if(heavyTankResearchProgress_player < 240){ + if(mainThread.pc.theBaseInfo.currentCredit >0){ + mainThread.pc.theBaseInfo.currentCredit--; + creditSpentOnResearching_player++; + heavyTankResearchProgress_player = 240 * creditSpentOnResearching_player/2500; + } + + if(heavyTankResearchProgress_player == 240){ + heavyTankResearched_player = true; + lightTankResearchProgress_player = 255; + rocketTankResearchProgress_player = 255; + stealthTankResearchProgress_player = 255; + creditSpentOnResearching_player = 0; + upgradeHeavyTank(0); + } + } + }else{ + if(heavyTankResearchProgress_enemy < 240){ + if(mainThread.ec.theBaseInfo.currentCredit >0){ + mainThread.ec.theBaseInfo.currentCredit--; + creditSpentOnResearching_enemy++; + heavyTankResearchProgress_enemy = 240 * creditSpentOnResearching_enemy/2500; + } + } + + if(heavyTankResearchProgress_enemy == 240){ + heavyTankResearched_enemy = true; + lightTankResearchProgress_enemy = 255; + rocketTankResearchProgress_enemy = 255; + stealthTankResearchProgress_enemy = 255; + creditSpentOnResearching_enemy = 0; + upgradeHeavyTank(1); + } + } + } + + + + //mark itself on obstacle map + mainThread.gridMap.currentObstacleMap[tileIndex[0]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[1]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[2]] = false; + mainThread.gridMap.currentObstacleMap[tileIndex[3]] = false; + + + //update center in camera coordinate + tempCentre.set(centre); + tempCentre.subtract(camera.position); + tempCentre.rotate_XZ(camera.XZ_angle); + tempCentre.rotate_YZ(camera.YZ_angle); + tempCentre.updateLocation(); + + theAssetManager = mainThread.theAssetManager; + + //test if the palm tree is visible in camera point of view + if(visibleBoundary.contains(tempCentre.screenX, tempCentre.screenY) && isRevealed){ + visible = true; + + if(screenBoundary.contains(tempCentre.screenX, tempCentre.screenY)) + withinViewScreen = true; + else + withinViewScreen = false; + + tempshadowvertex0.set(shadowvertex0); + tempshadowvertex0.subtract(camera.position); + tempshadowvertex0.rotate_XZ(camera.XZ_angle); + tempshadowvertex0.rotate_YZ(camera.YZ_angle); + tempshadowvertex0.updateLocation(); + + tempshadowvertex1.set(shadowvertex1); + tempshadowvertex1.subtract(camera.position); + tempshadowvertex1.rotate_XZ(camera.XZ_angle); + tempshadowvertex1.rotate_YZ(camera.YZ_angle); + tempshadowvertex1.updateLocation(); + + tempshadowvertex2.set(shadowvertex2); + tempshadowvertex2.subtract(camera.position); + tempshadowvertex2.rotate_XZ(camera.XZ_angle); + tempshadowvertex2.rotate_YZ(camera.YZ_angle); + tempshadowvertex2.updateLocation(); + + tempshadowvertex3.set(shadowvertex3); + tempshadowvertex3.subtract(camera.position); + tempshadowvertex3.rotate_XZ(camera.XZ_angle); + tempshadowvertex3.rotate_YZ(camera.YZ_angle); + tempshadowvertex3.updateLocation(); + + + + //if the object is visible then draw it on the shadow buffer from light point of view + if(shadowBoundary1.contains(tempshadowvertex0.screenX, tempshadowvertex0.screenY) || + shadowBoundary1.contains(tempshadowvertex1.screenX, tempshadowvertex1.screenY) || + shadowBoundary1.contains(tempshadowvertex2.screenX, tempshadowvertex2.screenY) || + shadowBoundary1.contains(tempshadowvertex3.screenX, tempshadowvertex3.screenY) + ){ + for(int i = 0; i < polygons.length; i++){ + if(polygons[i] != null) + polygons[i].update_lightspace(); + + } + + } + + //add this object to visible unit list + theAssetManager.visibleUnit[theAssetManager.visibleUnitCount] = this; + theAssetManager.visibleUnitCount++; + + + }else{ + visible = false; + } + + if(visible){ + float ratio = ((float)Math.sin((float)(mainThread.frameIndex + ID)/10) + 1)/2; + + + + int color = (int)(towerTopRedBase + ratio * (towerTopRed - towerTopRedBase)) << 10 | (int)(towerTopGreenBase + ratio * (towerTopGreen - towerTopGreenBase)) << 5 | (int)(towerTopBlueBase + ratio * (towerTopBlue - towerTopBlueBase)); + + for(int i = 261; i < 278; i++){ + polygons[i].color = color; + polygons[i].diffuse_I = 127; + } + + ratio = 1 - ratio; + color = (int)(towerTopRedBase + ratio * (towerTopRed - towerTopRedBase)) << 10 | (int)(towerTopGreenBase + ratio * (towerTopGreen - towerTopGreenBase)) << 5 | (int)(towerTopBlueBase + ratio * (towerTopBlue - towerTopBlueBase)); + + for(int i = 294; i < 311; i ++){ + polygons[i].color = color; + polygons[i].diffuse_I = 127; + } + } + + + //create vision for enemy commander + if(teamNo == 1){ + int xPos = boundary2D.x1/16 - 8 + 10; + int yPos = 127 - boundary2D.y1/16 - 8 + 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; + } + } + } + + visionBoundary.x = (int)(tempCentre.screenX - 800); + visionBoundary.y = (int)(tempCentre.screenY - 1000); + visionInsideScreen = camera.screen.intersects(visionBoundary); + + + if(visionInsideScreen){ + if(teamNo == 0){ + 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++; + } + } + + if(theAssetManager.minimapBitmap[tileIndex[0]] || + theAssetManager.minimapBitmap[tileIndex[1]] || + theAssetManager.minimapBitmap[tileIndex[2]] || + theAssetManager.minimapBitmap[tileIndex[3]] ) + isRevealed = true; + visible_minimap = isRevealed; + + if(visible_minimap){ + tempInt = theAssetManager.unitsForMiniMap[theAssetManager.unitsForMiniMapCount]; + tempInt[0] = teamNo; + 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] = 10000; + theAssetManager.unitsForMiniMapCount++; + } + + } + + public static void researchLightTank(int teamNo){ + if(teamNo == 0){ + lightTankResearchProgress_player = 0; + rocketTankResearchProgress_player = 254; + stealthTankResearchProgress_player = 254; + heavyTankResearchProgress_player = 254; + }else{ + lightTankResearchProgress_enemy = 0; + rocketTankResearchProgress_enemy = 254; + stealthTankResearchProgress_enemy = 254; + heavyTankResearchProgress_enemy = 254; + } + } + + public static void researchRocketTank(int teamNo){ + if(teamNo == 0){ + lightTankResearchProgress_player = 254; + rocketTankResearchProgress_player = 0; + stealthTankResearchProgress_player = 254; + heavyTankResearchProgress_player = 254; + }else{ + lightTankResearchProgress_enemy = 254; + rocketTankResearchProgress_enemy = 0; + stealthTankResearchProgress_enemy = 254; + heavyTankResearchProgress_enemy = 254; + } + } + + public static void researchStealthTank(int teamNo){ + if(teamNo == 0){ + lightTankResearchProgress_player = 254; + rocketTankResearchProgress_player = 254; + stealthTankResearchProgress_player = 0; + heavyTankResearchProgress_player = 254; + }else{ + lightTankResearchProgress_enemy = 254; + rocketTankResearchProgress_enemy = 254; + stealthTankResearchProgress_enemy = 0; + heavyTankResearchProgress_enemy = 254; + } + } + + public static void researchHeavyTank(int teamNo){ + if(teamNo == 0){ + lightTankResearchProgress_player = 254; + rocketTankResearchProgress_player = 254; + stealthTankResearchProgress_player = 254; + heavyTankResearchProgress_player = 0; + }else{ + lightTankResearchProgress_enemy = 254; + rocketTankResearchProgress_enemy = 254; + stealthTankResearchProgress_enemy = 254; + heavyTankResearchProgress_enemy = 0; + } + } + + //cancel research + public static void cancelResearch(int teamNo){ + if(teamNo == 0){ + lightTankResearchProgress_player = 255; + rocketTankResearchProgress_player = 255; + stealthTankResearchProgress_player = 255; + heavyTankResearchProgress_player = 255; + mainThread.pc.theBaseInfo.currentCredit+=creditSpentOnResearching_player; + creditSpentOnResearching_player = 0; + }else{ + lightTankResearchProgress_enemy = 255; + rocketTankResearchProgress_enemy = 255; + stealthTankResearchProgress_enemy = 255; + heavyTankResearchProgress_enemy = 255; + mainThread.pc.theBaseInfo.currentCredit+=creditSpentOnResearching_enemy; + creditSpentOnResearching_enemy = 0; + } + } + + + public void upgradeLightTank(int teamNo){ + for(int i = 0; i < mainThread.theAssetManager.lightTanks.length; i++){ + if(mainThread.theAssetManager.lightTanks[i] != null && mainThread.theAssetManager.lightTanks[i].teamNo == teamNo){ + mainThread.theAssetManager.lightTanks[i].attackRange = 1.99f; + } + } + + if(teamNo == 0) + lightTank.tileCheckList_player = generateTileCheckList(6); + else + lightTank.tileCheckList_enemy = generateTileCheckList(6); + } + + public void upgradeRocketTank(int teamNo){ + for(int i = 0; i < mainThread.theAssetManager.rocketTanks.length; i++){ + if(mainThread.theAssetManager.rocketTanks[i] != null && mainThread.theAssetManager.rocketTanks[i].teamNo == teamNo){ + mainThread.theAssetManager.rocketTanks[i].damageMultiplier =2; + } + } + } + + public void upgradeStealthTank(int teamNo){ + for(int i = 0; i < mainThread.theAssetManager.stealthTanks.length; i++){ + if(mainThread.theAssetManager.stealthTanks[i] != null && mainThread.theAssetManager.stealthTanks[i].teamNo == teamNo){ + mainThread.theAssetManager.stealthTanks[i].hasMultiShotUpgrade = true; + } + } + } + + public void upgradeHeavyTank(int teamNo){ + for(int i = 0; i < mainThread.theAssetManager.heavyTanks.length; i++){ + if(mainThread.theAssetManager.heavyTanks[i] != null && mainThread.theAssetManager.heavyTanks[i].teamNo == teamNo){ + mainThread.theAssetManager.heavyTanks[i].canSelfRepair = true; + } + } + } + + //draw the model + public void draw(){ + if(!visible) + return; + + for(int i = polygons.length - 1; i >= 0; i--){ + if(polygons[i] != null){ + polygons[i].update(); + polygons[i].draw(); + } + } + } + + public vector getMovement(){ + return movenment; + } +} \ No newline at end of file diff --git a/entity/tokenObject.java b/entity/tokenObject.java new file mode 100644 index 0000000..d62b3b5 --- /dev/null +++ b/entity/tokenObject.java @@ -0,0 +1,50 @@ +package entity; + +import core.Rect; +import core.mainThread; +import core.postProcessingThread; +import core.vector; + +//the only purpose of this object is to create an invisible boundary block +public class tokenObject extends solidObject{ + public int tileIndex; + public boolean noNeedForThisToken; + + public tokenObject(float x, float y, float z, int color){ + ID = -1; + type = 4; + teamNo = -1; + centre = new vector(x,y,z); + + currentCommand = StandBy; + + movement = new vector(0,0,0); + + boundary2D = new Rect((int)(x*64) - 8, (int)(z*64) + 8, 16, 16); + + + tileIndex = boundary2D.x1/16 + (127 - (boundary2D.y1 - 1)/16)*128; + + + if(x < 0 || mainThread.gridMap.tiles[tileIndex][0]!= null){ + noNeedForThisToken = true; + return; + } + + + if(!(x == 0 && y ==0 && z ==0)) + updateOccupiedTiles(boundary2D.x1, boundary2D.y1); + + + boundary2D.owner = this; + postProcessingThread.theMiniMap.background[tileIndex] = color; + + + } + + + public vector getMovement(){ + return movement; + } + +} diff --git a/gui/.gitignore b/gui/.gitignore new file mode 100644 index 0000000..ea77f02 --- /dev/null +++ b/gui/.gitignore @@ -0,0 +1,7 @@ +/MiniMap.class +/SideBar.class +/confirmationIcon.class +/deployGrid.class +/inputHandler.class +/playerCommander.class +/sideBarManager.class diff --git a/gui/MiniMap.java b/gui/MiniMap.java new file mode 100644 index 0000000..218f266 --- /dev/null +++ b/gui/MiniMap.java @@ -0,0 +1,376 @@ +package gui; + +import core.mainThread; +import core.postProcessingThread; +import core.vector; + +public class MiniMap { + + public int[] background; + public boolean[] tempBitmap; + public boolean[][] bitmapVision; + public static vector corner1, corner2, corner3, corner4; + public static boolean isDrawingWindow; + + + public void init(){ + //load terrain image as background for minimap + background = new int[128*128]; + int r = (int)(193 * 0.95); + int g = (int)(176 * 0.95); + int b = (int)(128 * 0.95 ); + + for(int i = 0; i < 128 * 128; i++) + background[i]= (r << 16) | (g << 8) | b; + + tempBitmap = new boolean[148 * 148]; + + bitmapVision = new boolean[4][]; + + bitmapVision[0] = createBitmapVision(6); + bitmapVision[1] = createBitmapVision(2); + bitmapVision[2] = createBitmapVision(7); + bitmapVision[3] = createBitmapVision(11); + + corner1 = new vector(0,0,0); + corner2 = new vector(0,0,0); + corner3 = new vector(0,0,0); + corner4 = new vector(0,0,0); + } + + + public void draw(int[] screen, boolean[] minimapBitmap, int[][] unitsForMiniMap, int unitsForMiniMapCount){ + //draw mini map window frame + drawFrame(screen); + + //create bitmap + createBitmap(minimapBitmap, unitsForMiniMap, unitsForMiniMapCount); + + //draw background + drawBackground(screen, minimapBitmap); + + //remove fog of war for testing + for(int i = 0; i < minimapBitmap.length; i++) + minimapBitmap[i] = true; + + + //draw unit positions on minimap + drawUnit(screen, minimapBitmap, unitsForMiniMap, unitsForMiniMapCount); + + //draw view window + drawViewWindow(screen); + + } + + public void drawViewWindow(int[] screen){ + int xPos1, xPos2, xPos3,xPos4, yPos1, yPos2, yPos3, yPos4; + + + xPos1 = (int)(corner1.x*64/16); + yPos1 = 127 - (int)(corner1.z*64/16); + xPos2 = (int)(corner2.x*64/16); + yPos2 = 127 - (int)(corner2.z*64/16); + xPos3 = (int)(corner3.x*64/16); + yPos3 = 127 - (int)(corner3.z*64/16); + xPos4 = (int)(corner4.x*64/16); + yPos4 = 127 - (int)(corner4.z*64/16); + + + drawLine(xPos1+1, yPos1, xPos2-1,yPos2, screen); + drawLine(xPos2, yPos2, xPos3,yPos3, screen); + drawLine(xPos3-1, yPos3, xPos4+1,yPos4, screen); + drawLine(xPos4, yPos4, xPos1,yPos1, screen); + + + + + } + + public void findCorners(){ + + corner1.set(postProcessingThread.my2Dto3DFactory.get3DLocation(mainThread.theAssetManager.Terrain.ground[0], -40, -40)); + corner2.set(postProcessingThread.my2Dto3DFactory.get3DLocation(mainThread.theAssetManager.Terrain.ground[0], 807, -40)); + corner3.set(postProcessingThread.my2Dto3DFactory.get3DLocation(mainThread.theAssetManager.Terrain.ground[0], 807, 551)); + corner4.set(postProcessingThread.my2Dto3DFactory.get3DLocation(mainThread.theAssetManager.Terrain.ground[0], -40, 551)); + + } + + public void drawLine(int xPos1, int yPos1, int xPos2, int yPos2, int[] screen){ + int start = 381 * 768 + 3; + int x, y; + int xDirection, yDirection; + + if(xPos1 < xPos2) + xDirection = 1; + else + xDirection = -1; + + if(yPos1 < yPos2) + yDirection = 1; + else + yDirection = -1; + + int color; + + if(Math.abs(xPos2 - xPos1) > Math.abs(yPos2 - yPos1)){ + float slope = (float)(yPos2 - yPos1)/(xPos2 - xPos1); + for(int i = 0; i <= Math.abs(xPos2 - xPos1); i ++){ + x = xPos1 + i*xDirection; + y = (int)(yPos1 + slope*i*xDirection); + + if(x < 0 || x > 127 || y < 0 || y > 127) + continue; + color = screen[start + x + y*768]; + screen[start + x + y*768] = ((((color&0xFEFEFE)>>1)&0xFEFEFE)>>1) + 0xbfbfbf; + } + + }else{ + float slope = (float)(xPos2 - xPos1)/(yPos2 - yPos1); + for(int i = 0; i <= Math.abs(yPos2 - yPos1); i ++){ + y = yPos1 + i*yDirection; + x = (int)(xPos1 + slope*i*yDirection); + + if(x < 0 || x > 127 || y < 0 || y > 127) + continue; + color = screen[start + x + y*768]; + screen[start + x + y*768] = ((((color&0xFEFEFE)>>1)&0xFEFEFE)>>1) + 0xbfbfbf; + + } + } + } + + + public void drawUnit(int[] screen, boolean[] minimapBitmap, int[][] unitsForMiniMap, int unitsForMiniMapCount){ + int xPos = 0; + int yPos = 0; + int start = 381 * 768 + 3; + int index = 0; + int friendlyUnitColor = 170 << 8; + int friendlyBuildingColor = 46 << 16 | 114 << 8 | 22; + + float p = (1f + (float)Math.sin((float)(postProcessingThread.frameIndex)/5))/2; + int c = (int)(255*p); + int underAttackColor = 0xffff0000 | (c << 8) | c; + + int enemyUnitColor = 224 << 16; + int enemyBuildingColor1 = 153 << 16; + int enemyBuildingColor2 = 90 << 16; + int type = 0; + + for(int i = 0; i < unitsForMiniMapCount; i++){ + xPos = unitsForMiniMap[i][1]; + yPos = unitsForMiniMap[i][2]; + index = start + xPos + yPos*768; + + type = unitsForMiniMap[i][0] >> 8; + + if((unitsForMiniMap[i][0] & 0xff) == 0){ + int color; + if(unitsForMiniMap[i][3] >= 2 && type != 6) + color = friendlyBuildingColor; + else + color = friendlyUnitColor; + if(unitsForMiniMap[i][4] == 10001){ + color = underAttackColor; + } + + if((screen[index]>>24) == 0) + screen[index] = color; + if((screen[index + 1]>>24) == 0) + screen[index+1] = color; + if((screen[index+768]>>24) == 0) + screen[index+768] = color; + if((screen[index+768 + 1]>>24) == 0) + screen[index+768 + 1] = color; + + }else{ + int position = xPos + yPos*128; + if(position >=0 && position < 16384){ + if(minimapBitmap[xPos + yPos*128] || unitsForMiniMap[i][4] == 10000){ + int color; + if(!minimapBitmap[xPos + yPos*128]){ + color = enemyBuildingColor2; + }else{ + if(unitsForMiniMap[i][3] >= 2 && type != 6) + color = enemyBuildingColor1; + else + color = enemyUnitColor; + } + + screen[index] = color; + screen[index+1] = color; + screen[index+768] = color; + screen[index+768 + 1] = color; + } + } + } + } + } + + + public boolean[] createBitmapVision(int radius){ + int l = radius*2+1; + boolean[] vision = new boolean[l*l]; + for(int y = 0; y < l; y++){ + for(int x = 0; x < l; x++){ + if( (x - radius)*(x - radius) + (y - radius)*(y - radius) < ((float)radius+0.5f)*((float)radius+0.5f)){ + vision[x + y*l] = true; + } + } + } + return vision; + } + + + public void createBitmap(boolean[] minimapBitmap, int[][] unitsForMiniMap, int unitsForMiniMapCount){ + + for(int i = 0 ;i < tempBitmap.length; i++){ + tempBitmap[i] = false; + } + + boolean[] vision; + int visionType = 0; + int xPos = 0; + int yPos = 0; + int l = 0; + int r = 0; + for(int i = 0; i < unitsForMiniMapCount; i++){ + if((unitsForMiniMap[i][0] & 0xff) != 0){ + //if(unitsForMiniMap[i][4] != 1) + // continue; + visionType = 1; + }else{ + + visionType = unitsForMiniMap[i][3]; + } + + vision = bitmapVision[visionType]; + + if(visionType == 0){ + l = 13; + r = 6; + }else if(visionType == 1){ + l = 5; + r = 2; + }else if(visionType == 2){ + l = 15; + r = 7; + }else if(visionType == 3){ + l = 23; + r = 11; + } + + xPos = unitsForMiniMap[i][1] - r + 10; + yPos = unitsForMiniMap[i][2] - r + 10; + + if((unitsForMiniMap[i][0] & 0xff) != 0 && (unitsForMiniMap[i][4] == 0 || unitsForMiniMap[i][4] == 10000)){ + continue; + } + + for(int y = 0; y < l; y++){ + for(int x = 0; x < l; x++){ + if(vision[x+ y*l]) + tempBitmap[xPos + x + (yPos+y)*148] =true; + } + } + } + + + + for(int y = 0; y < 128; y++){ + for(int x = 0; x < 128; x++){ + minimapBitmap[x + y*128] = tempBitmap[x + 10 + (y + 10)*148]; + } + } + + } + + + public void drawBackground(int[] screen, boolean[] minimapBitmap){ + int start = 381 * 768 + 3; + int color = 0; + + + + int goldMineColor = 196 << 16 | 138 << 8 | 0; + + + for(int y = 0; y < 128; y++){ + for(int x = 0; x < 128; x ++){ + color = background[x + y*128]; + if(minimapBitmap[x + y*128]){ + screen[start + x + y*768] = color; + }else{ + if(((color & 0xf000000) >> 24) == 12) + screen[start + x + y*768] = goldMineColor; + else + screen[start + x + y*768] = (color&0xFEFEFE)>>1; + } + } + } + } + + + + public void drawFrame(int[] screen){ + int color1 = 0xa0a0a0; + int color2 = 0xe0e0e0; + + int start = 378*768; + for(int x = 1; x < 133; x++){ + screen[start + x] = color1; + } + start = 379*768; + for(int x = 1; x < 133; x++){ + screen[start + x] = color2; + } + start = 380*768; + for(int x = 2; x < 132; x++){ + screen[start + x] = color1; + } + + start = 509*768; + for(int x = 2; x < 132; x++){ + screen[start + x] = color1; + } + start = 510*768; + for(int x = 1; x < 133; x++){ + screen[start + x] = color2; + } + start = 511*768; + for(int x = 0; x < 134; x++){ + screen[start + x] = color1; + } + + start = 378*768 + 133; + for(int y = 1; y < 132; y++){ + screen[start + y*768] = color1; + } + + start = 379*768 + 132; + for(int y = 0; y < 132; y++){ + screen[start + y*768] = color2; + } + + start = 380*768 + 131; + for(int y = 0; y < 131; y++){ + screen[start + y*768] = color1; + } + + start = 378*768; + for(int y = 1; y < 132; y++){ + screen[start + y*768] = color1; + } + + start = 379*768 + 1; + for(int y = 0; y < 132; y++){ + screen[start + y*768] = color2; + } + + start = 380*768 + 2; + for(int y = 0; y < 131; y++){ + screen[start + y*768] = color1; + } + } + +} diff --git a/gui/SideBar.java b/gui/SideBar.java new file mode 100644 index 0000000..7a4d78d --- /dev/null +++ b/gui/SideBar.java @@ -0,0 +1,646 @@ +package gui; + +import java.awt.image.PixelGrabber; +import java.awt.*; + +import javax.imageio.ImageIO; + +import core.mainThread; +import core.postProcessingThread; + +public class SideBar { + public String imageFolder = ""; + + public int[][] iconImages; + public int[][] iconImages_dark; + public int[] xStart; + public int[] yStart; + + public int[] autoRepairMark; + + public boolean[][] progressBitmaps; + + public int onScreenPlayerMoney; + + public int MASK7Bit = 0xFEFEFF; + public int pixel, overflow, screenIndex; + + public void init(){ + xStart = new int[]{634, 677, 722, 634, 677, 722,634, 677, 722}; + yStart = new int[]{381, 381, 381, 425, 425, 425,468, 468, 468}; + + progressBitmaps = new boolean[240][44*44]; + prepareProgressBitmaps(); + + autoRepairMark = new int[74]; + for(int i = 0; i < 20; i++){ + autoRepairMark[i] = 724 + i*2 + 470*768; + + } + + for(int i = 20; i < 37; i++){ + autoRepairMark[i] = 724 + 38 + (472+(i-20)*2)*768; + } + for(int i = 37; i < 57; i++){ + autoRepairMark[i] = 724 + 38 - (i-37)*2 + (470+36)*768; + + } + for(int i = 57; i < 74; i++){ + autoRepairMark[i] = 724 + (470+(74-i)*2)*768; + + } + + + iconImages = new int[24][44 * 44]; + iconImages_dark = new int[24][44 * 44]; + String folder = "../images/"; + loadTexture(folder + "44.jpg", iconImages[0], 44, 44, iconImages_dark[0]); + loadTexture(folder + "47.jpg", iconImages[1], 44, 44, iconImages_dark[1]); + loadTexture(folder + "48.jpg", iconImages[2], 44, 44, iconImages_dark[2]); + loadTexture(folder + "49.jpg", iconImages[3], 16, 16, iconImages_dark[3]); + loadTexture(folder + "50.jpg", iconImages[4], 16, 16, iconImages_dark[4]); + loadTexture(folder + "57.jpg", iconImages[5], 44, 44, iconImages_dark[5]); + loadTexture(folder + "58.jpg", iconImages[6], 44, 44, iconImages_dark[6]); + loadTexture(folder + "59.jpg", iconImages[7], 44, 44, iconImages_dark[7]); + loadTexture(folder + "60.jpg", iconImages[8], 44, 44, iconImages_dark[8]); + loadTexture(folder + "65.jpg", iconImages[9], 44, 44, iconImages_dark[9]); + loadTexture(folder + "66.jpg", iconImages[10], 44, 44, iconImages_dark[10]); + loadTexture(folder + "67.jpg", iconImages[11], 44, 44, iconImages_dark[11]); + loadTexture(folder + "72.jpg", iconImages[12], 44, 44, iconImages_dark[12]); + loadTexture(folder + "75.jpg", iconImages[13], 44, 44, iconImages_dark[13]); + loadTexture(folder + "76.jpg", iconImages[14], 44, 44, iconImages_dark[14]); + loadTexture(folder + "77.jpg", iconImages[15], 44, 44, iconImages_dark[15]); + loadTexture(folder + "78.jpg", iconImages[16], 44, 44, iconImages_dark[16]); + loadTexture(folder + "79.jpg", iconImages[17], 44, 44, iconImages_dark[17]); + loadTexture(folder + "81.jpg", iconImages[18], 44, 44, iconImages_dark[18]); + loadTexture(folder + "83.jpg", iconImages[19], 44, 44, iconImages_dark[19]); + loadTexture(folder + "86.jpg", iconImages[20], 44, 44, iconImages_dark[20]); + loadTexture(folder + "87.jpg", iconImages[21], 44, 44, iconImages_dark[21]); + loadTexture(folder + "88.jpg", iconImages[22], 44, 44, iconImages_dark[22]); + loadTexture(folder + "89.jpg", iconImages[23], 44, 44, iconImages_dark[23]); + + + } + + public void draw(int[] screen, int[] sideBarInfo){ + + drawBackground(screen); + + drawSideBarInfo(screen, sideBarInfo); + + drawCreditAndPowerLevel(screen, postProcessingThread.playerMoney, postProcessingThread.playerPowerStatus); + + drawFrame(screen); + } + + + public void drawCreditAndPowerLevel(int[] screen, int playerMoney, int playerPowerStatus){ + + drawInfoBackGround(screen, 637, 3, 129, 16, 100); + int startIndex = 639 + 3 * 768; + + drawIcon(screen, startIndex, 3); + + calculateOnScreenPlayerMoney(playerMoney); + + postProcessingThread.theTextRenderer.drawText(657, 3, onScreenPlayerMoney+"", screen, 245,197,51); + + if(playerPowerStatus != -1){ + drawIcon(screen, startIndex + 60, 4); + + int currentPowerConsumption = playerPowerStatus >> 16; + int currentPowerLevel = playerPowerStatus&0xffff; + + if(currentPowerConsumption <= currentPowerLevel){ + postProcessingThread.theTextRenderer.drawText(714, 3, currentPowerConsumption/50 + "/"+currentPowerLevel/50, screen, 0,205,0); + }else{ + + postProcessingThread.theTextRenderer.drawText(714, 3, currentPowerConsumption/50 + "", screen, 255,0,0); + int l = (currentPowerConsumption/50 + "").length(); + postProcessingThread.theTextRenderer.drawText(714+l*7, 3, "/"+currentPowerLevel/50, screen, 0,205,0); + } + } + + } + + public void drawIcon(int[] screen, int startIndex, int iconIndex){ + int screenIndex = 0; + for(int i = 0; i < 16; i++){ + for(int j = 0; j < 16; j++){ + screenIndex = startIndex + j + (i+1)*768; + pixel=(iconImages[iconIndex][j + i*16]&MASK7Bit)+(screen[screenIndex]&MASK7Bit); + overflow=pixel&0x1010100; + overflow=overflow-(overflow>>8); + screen[screenIndex] = overflow|pixel; + } + } + } + + public void calculateOnScreenPlayerMoney(int playerMoney){ + + int difference = playerMoney - onScreenPlayerMoney; + + if(difference > 1000) + onScreenPlayerMoney+=73; + else if(difference > 23 && difference <= 750) + onScreenPlayerMoney+=23; + else if(difference <= 23 && difference > 0) + onScreenPlayerMoney+=difference; + else + onScreenPlayerMoney+=difference; + + } + + public void drawSideBarInfo(int[] screen, int[] sideBarInfo){ + int displayInfo, iconTextureIndex, progress, text; + + int powerPlantInfo = 1; + int deployMCVInfo = 2; + int refineryInfo = 3; + int factoryInfo = 4; + int lightTankInfo = 5; + int rocketTankInfo = 6; + int harvesterInfo = 7; + int droneInfo = 8; + int communicationCenterInfo = 9; + int MCVInfo = 10; + int stealthTankInfo = 11; + int gunTurretInfo = 12; + int repairBuildingInfo = 13; + int missileTurretInfo = 14; + int harvesterResearchInfo = 15; + int missileTurretResearchInfo = 16; + int rapidfireTooltipInfo = 17; + int techCenterInfo = 18; + int heavyTankInfo = 19; + int lightTankResearchInfo = 20; + int rocketTankResearchInfo = 21; + int stealthTankResearchInfo = 22; + int heavyTankResearchInfo = 23; + + for(int i = 0; i < 9; i ++){ + if(sideBarInfo[i] != -1){ + displayInfo = (sideBarInfo[i] >> 24) & 255; + iconTextureIndex = (sideBarInfo[i] >> 16) & 255; + progress = (sideBarInfo[i] >> 8) & 255; + text = sideBarInfo[i] & 255; + + if(progress == 254){ + drawIconImage(xStart[i],yStart[i],screen,iconImages_dark[iconTextureIndex]); + }else if(progress >= 240){ + drawIconImage(xStart[i],yStart[i],screen,iconImages[iconTextureIndex]); + }else if(progress == 0){ + drawIconImage(xStart[i],yStart[i],screen,iconImages_dark[iconTextureIndex]); + }else{ + drawIconImage(xStart[i],yStart[i],screen,iconImages[iconTextureIndex], iconImages_dark[iconTextureIndex], progress); + } + + if(text == 1){ + postProcessingThread.theTextRenderer.drawFlashingText(xStart[i] + 5, yStart[i] + 11, "Ready", screen); + }else if(text > 100){ + postProcessingThread.theTextRenderer.drawText(xStart[i] + 5, yStart[i] + 0, ""+ (text - 100), screen, 255,255,255); + } + + //draw display infos + if(displayInfo == powerPlantInfo){ + drawInfoBackGround(screen, 637, 344, 129, 32, 128); + postProcessingThread.theTextRenderer.drawText(639, 344, "Power Plant", screen, 255,255,200); + postProcessingThread.theTextRenderer.drawText(639, 360, "$:500", screen, 245,197,51); + drawIcon(screen, 690 + 360*768, 4); + postProcessingThread.theTextRenderer.drawText(706, 360, "+10", screen, 0,205,0); + + }else if(displayInfo == deployMCVInfo){ + drawInfoBackGround(screen, 637, 360, 129,16,128); + postProcessingThread.theTextRenderer.drawText(639, 360, "Deploy MCV", screen, 255,255,255); + }else if(displayInfo == refineryInfo){ + drawInfoBackGround(screen, 637, 344, 129,32,128); + postProcessingThread.theTextRenderer.drawText(639, 344, "Refinery", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 360, "$:1200", screen, 245,197,51); + drawIcon(screen, 690 + 360*768, 4); + postProcessingThread.theTextRenderer.drawText(706, 360, "-3", screen, 255,0,0); + }else if(displayInfo == factoryInfo){ + drawInfoBackGround(screen, 637, 344, 129,32,128); + postProcessingThread.theTextRenderer.drawText(639, 344, "Factory", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 360, "$:1400", screen, 245,197,51); + drawIcon(screen, 690 + 360*768, 4); + postProcessingThread.theTextRenderer.drawText(706, 360, "-4", screen, 255,0,0); + }else if(displayInfo == lightTankInfo){ + drawInfoBackGround(screen, 637, 344, 129,32,128); + postProcessingThread.theTextRenderer.drawText(639, 344, "Light Tank", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 360, "$:300", screen, 245,197,51); + }else if(displayInfo == rocketTankInfo){ + drawInfoBackGround(screen, 637, 344, 129,32,128); + postProcessingThread.theTextRenderer.drawText(639, 344, "Rocket Tank", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 360, "$:450", screen, 245,197,51); + }else if(displayInfo == harvesterInfo){ + drawInfoBackGround(screen, 637, 344, 129,32,128); + postProcessingThread.theTextRenderer.drawText(639, 344, "Harvester", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 360, "$:800", screen, 245,197,51); + }else if(displayInfo == droneInfo){ + drawInfoBackGround(screen, 637, 344, 129,32,128); + postProcessingThread.theTextRenderer.drawText(639, 344, "Repair Drone", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 360, "$:250", screen, 245,197,51); + }else if(displayInfo == communicationCenterInfo){ + drawInfoBackGround(screen, 637, 344, 129,32,128); + postProcessingThread.theTextRenderer.drawText(639, 344, "COMM. Centre", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 360, "$:1000", screen, 245,197,51); + drawIcon(screen, 690 + 360*768, 4); + postProcessingThread.theTextRenderer.drawText(706, 360, "-5", screen, 255,0,0); + }else if(displayInfo == MCVInfo){ + drawInfoBackGround(screen, 637, 344, 129,32,128); + postProcessingThread.theTextRenderer.drawText(639, 344, "MCV", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 360, "$:1700", screen, 245,197,51); + }else if(displayInfo == stealthTankInfo){ + drawInfoBackGround(screen, 637, 344, 129,32,128); + postProcessingThread.theTextRenderer.drawText(639, 344, "Stealth Tank", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 360, "$:600", screen, 245,197,51); + }else if(displayInfo == gunTurretInfo){ + drawInfoBackGround(screen, 637, 344, 129,32,128); + postProcessingThread.theTextRenderer.drawText(639, 344, "Gun Turret", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 360, "$:400", screen, 245,197,51); + drawIcon(screen, 690 + 360*768, 4); + postProcessingThread.theTextRenderer.drawText(706, 360, "-2", screen, 255,0,0); + }else if(displayInfo == repairBuildingInfo){ + drawInfoBackGround(screen, 637, 360, 129,16,128); + postProcessingThread.theTextRenderer.drawText(639, 360, "Repair Structure", screen, 255,255,255); + }else if(displayInfo == missileTurretInfo){ + drawInfoBackGround(screen, 637, 344, 129,32,128); + postProcessingThread.theTextRenderer.drawText(639, 344, "Missile Turret", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 360, "$:750", screen, 245,197,51); + drawIcon(screen, 690 + 360*768, 4); + postProcessingThread.theTextRenderer.drawText(706, 360, "-4", screen, 255,0,0); + }else if(displayInfo == harvesterResearchInfo){ + drawInfoBackGround(screen, 637, 328, 129,48,128); + postProcessingThread.theTextRenderer.drawText(639, 328, "Research harvester", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(640, 344, "movement speed.", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 360, "$:1200", screen, 245,197,51); + }else if(displayInfo == missileTurretResearchInfo){ + drawInfoBackGround(screen, 637, 312, 129,64,128); + postProcessingThread.theTextRenderer.drawText(639, 312, "Research rapidfire", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 328, "ability for the", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 344, "missile turret.", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 360, "$:1500", screen, 245,197,51); + }else if(displayInfo == rapidfireTooltipInfo){ + drawInfoBackGround(screen, 637, 312, 129,64,128); + postProcessingThread.theTextRenderer.drawText(639, 312, "Fire missile more", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 328, "rapidly, but draws", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 344, "addtional power.", screen, 255,255,255); + drawIcon(screen, 639 + 360*768, 4); + postProcessingThread.theTextRenderer.drawText(655, 360, "-3", screen, 255,0,0); + }else if(displayInfo == techCenterInfo){ + drawInfoBackGround(screen, 637, 344, 129,32,128); + postProcessingThread.theTextRenderer.drawText(639, 344, "Tech Center", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 360, "$:1500", screen, 245,197,51); + drawIcon(screen, 690 + 360*768, 4); + postProcessingThread.theTextRenderer.drawText(706, 360, "-8", screen, 255,0,0); + }else if(displayInfo == heavyTankInfo){ + drawInfoBackGround(screen, 637, 344, 129,32,128); + postProcessingThread.theTextRenderer.drawText(639, 344, "Heavy Tank", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 360, "$:1100", screen, 245,197,51); + }else if(displayInfo == lightTankResearchInfo){ + drawInfoBackGround(screen, 637, 328, 129,48,128); + postProcessingThread.theTextRenderer.drawText(639, 328, "Research light", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(640, 344, "tank's fire range", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 360, "$:1500", screen, 245,197,51); + }else if(displayInfo == rocketTankResearchInfo){ + drawInfoBackGround(screen, 637, 312, 129,64,128); + postProcessingThread.theTextRenderer.drawText(639, 312, "Research rocket", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 328, "tank's damage", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 344, "against building", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 360, "$:2000", screen, 245,197,51); + }else if(displayInfo == stealthTankResearchInfo){ + drawInfoBackGround(screen, 637, 312, 129,64,128); + postProcessingThread.theTextRenderer.drawText(639, 312, "Research stealth", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 328, "tank's ability to", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 344, "hit multiple units", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 360, "$:2000", screen, 245,197,51); + }else if(displayInfo == heavyTankResearchInfo){ + drawInfoBackGround(screen, 637, 312, 129,64,128); + postProcessingThread.theTextRenderer.drawText(639, 312, "Research heavy", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 328, "tank's ability to", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 344, "self repair", screen, 255,255,255); + postProcessingThread.theTextRenderer.drawText(639, 360, "$:2500", screen, 245,197,51); + } + + + if((iconTextureIndex == 14 || iconTextureIndex == 17) && text == 32){ + + int d = 0; + if(iconTextureIndex == 17) + d = 768*44; + + int startIndex1 = (int)(mainThread.frameIndex/1.5)%74; + int startIndex2 = ((int)(mainThread.frameIndex/1.5)%74 + 18)%74; + int startIndex3 = ((int)(mainThread.frameIndex/1.5)%74 + 37)%74; + int startIndex4 = ((int)(mainThread.frameIndex/1.5)%74 + 55)%74; + + int markerR = 255; + int markerG = 255; + int markerB =64; + int pixelColor; + int pixelR, pixelG, pixelB; + + for(int j = 0; j < 16; j++){ + int index = autoRepairMark[(startIndex1+j)%74] -d; + float t = 0.9375f - 0.0625f*j; + pixelColor = screen[index]; + pixelR = (pixelColor & 0xff0000) >> 16; + pixelG = (pixelColor & 0xff00) >> 8; + pixelB = (pixelColor & 0xff); + + pixelColor = (int)(pixelR*t + markerR*(1-t)) << 16 | (int)(pixelG*t + markerG*(1-t)) << 8 | (int)(pixelB*t + markerB*(1-t)); + + screen[index] = pixelColor; + screen[index+1] = pixelColor; + screen[index + 768] = pixelColor; + screen[index + 769] = pixelColor; + } + + + for(int j = 0; j < 16; j++){ + int index = autoRepairMark[(startIndex2+j)%74] - d; + float t = 0.9375f - 0.0625f*j; + pixelColor = screen[index]; + pixelR = (pixelColor & 0xff0000) >> 16; + pixelG = (pixelColor & 0xff00) >> 8; + pixelB = (pixelColor & 0xff); + + pixelColor = (int)(pixelR*t + markerR*(1-t)) << 16 | (int)(pixelG*t + markerG*(1-t)) << 8 | (int)(pixelB*t + markerB*(1-t)); + + screen[index] = pixelColor; + screen[index+1] = pixelColor; + screen[index + 768] = pixelColor; + screen[index + 769] = pixelColor; + } + + for(int j = 0; j < 16; j++){ + int index = autoRepairMark[(startIndex3+j)%74] - d; + float t = 0.9375f - 0.0625f*j; + pixelColor = screen[index]; + pixelR = (pixelColor & 0xff0000) >> 16; + pixelG = (pixelColor & 0xff00) >> 8; + pixelB = (pixelColor & 0xff); + + pixelColor = (int)(pixelR*t + markerR*(1-t)) << 16 | (int)(pixelG*t + markerG*(1-t)) << 8 | (int)(pixelB*t + markerB*(1-t)); + + screen[index] = pixelColor; + screen[index+1] = pixelColor; + screen[index + 768] = pixelColor; + screen[index + 769] = pixelColor; + } + + for(int j = 0; j < 16; j++){ + int index = autoRepairMark[(startIndex4+j)%74] - d; + float t = 0.9375f - 0.0625f*j; + pixelColor = screen[index]; + pixelR = (pixelColor & 0xff0000) >> 16; + pixelG = (pixelColor & 0xff00) >> 8; + pixelB = (pixelColor & 0xff); + + pixelColor = (int)(pixelR*t + markerR*(1-t)) << 16 | (int)(pixelG*t + markerG*(1-t)) << 8 | (int)(pixelB*t + markerB*(1-t)); + + screen[index] = pixelColor; + screen[index+1] = pixelColor; + screen[index + 768] = pixelColor; + screen[index + 769] = pixelColor; + } + } + } + } + } + + public void drawInfoBackGround(int[] screen, int xPos, int yPos, int w, int h, int alpha){ + int start = xPos + yPos*768; + if(alpha == 128){ + for(int i = 1; i < w - 1; i++){ + screen[start -768 + i] = (screen[start -768 + i]&0xFEFEFE)>>1; + } + + for(int i = 0; i < h; i++){ + for(int j = 0; j < w; j++){ + screen[start + j + i*768] = (screen[start + j + i*768]&0xFEFEFE)>>1; + } + } + + for(int i = 1; i < w - 1; i++) + screen[start + 768*h + i] = (screen[start + 768*h + i]&0xFEFEFE)>>1; + }else{ + for(int i = 1; i < w - 1; i++){ + int value = screen[start -768 + i]; + screen[start -768 + i] = (((((value&0xff0000) >> 16) * alpha) >> 8) << 16) | (((((value&0xff00) >> 8) * alpha) >> 8) << 8) | (((((value&0xff)) * alpha) >> 8)); + + + } + + for(int i = 0; i < h; i++){ + for(int j = 0; j < w; j++){ + int value = screen[start + j + i*768]; + screen[start + j + i*768] = (((((value&0xff0000) >> 16) * alpha) >> 8) << 16) | (((((value&0xff00) >> 8) * alpha) >> 8) << 8) | (((((value&0xff)) * alpha) >> 8)); + } + } + + for(int i = 1; i < w - 1; i++){ + int value = screen[start + 768*h + i]; + screen[start + 768*h + i] = (((((value&0xff0000) >> 16) * alpha) >> 8) << 16) | (((((value&0xff00) >> 8) * alpha) >> 8) << 8) | (((((value&0xff)) * alpha) >> 8)); + } + } + + } + + public void prepareProgressBitmaps(){ + double theta = Math.PI/120; + for(int i = 0; i < 240; i++){ + + double angle = i*theta; + + for(int j = 0; j < 44*44; j++){ + double x = j%44 -22; + double y = 22 - j/44 ; + if(angle > (Math.PI*2.5 - Math.atan2(y, x))%(Math.PI*2)) + progressBitmaps[i][j] = true; + + } + } + } + + public void drawIconImage(int xPos, int yPos, int[] screen, int[] iconImage){ + int start = xPos + yPos * 768; + for(int i = 0; i < 44; i++){ + for(int j = 0; j < 44; j++){ + screen[start + j + i*768] = iconImage[j + i*44]; + } + } + + } + + public void drawIconImage(int xPos, int yPos, int[] screen, int[] iconImage, int[] iconImages_dark, int progress){ + int start = xPos + yPos * 768; + for(int i = 0; i < 44; i++){ + for(int j = 0; j < 44; j++){ + if(progressBitmaps[progress][j + i*44]) + screen[start + j + i*768] = iconImage[j + i*44]; + else + screen[start + j + i*768] = iconImages_dark[j + i*44]; + } + } + } + + public void drawBackground(int[] screen){ + int start = 381*768 + 637; + for(int i = 0; i< 128; i++){ + for(int j = 0; j < 128; j++){ + screen[start + j + i*768] = 0x666655; + } + } + + } + + public void drawFrame(int[] screen){ + int color1 = 0xa0a0a0; + int color2 = 0xe0e0e0; + + int shift= 634; + + int start = 378*768 + shift; + for(int x = 1; x < 133; x++){ + screen[start + x] = color1; + } + start = 379*768 + shift; + for(int x = 1; x < 133; x++){ + screen[start + x] = color2; + } + start = 380*768 + shift; + for(int x = 2; x < 132; x++){ + screen[start + x] = color1; + } + + start = 422*768 + shift; + for(int x = 1; x < 133; x++){ + screen[start + x] = color1; + } + start = 423*768 + shift; + for(int x = 1; x < 133; x++){ + screen[start + x] = color2; + } + start = 424*768 + shift; + for(int x = 2; x < 132; x++){ + screen[start + x] = color1; + } + + start = 466*768 + shift; + for(int x = 1; x < 133; x++){ + screen[start + x] = color1; + } + start = 467*768 + shift; + for(int x = 1; x < 133; x++){ + screen[start + x] = color2; + } + start = 468*768 + shift; + for(int x = 2; x < 132; x++){ + screen[start + x] = color1; + } + + start = 509*768 + shift; + for(int x = 2; x < 132; x++){ + screen[start + x] = color1; + } + start = 510*768 + shift; + for(int x = 1; x < 133; x++){ + screen[start + x] = color2; + } + start = 511*768 + shift; + for(int x = 0; x < 134; x++){ + screen[start + x] = color1; + } + + + + + + start = 378*768 + 133 + shift; + for(int y = 1; y < 132; y++){ + screen[start + y*768] = color1; + } + + start = 379*768 + 132 + shift; + for(int y = 0; y < 132; y++){ + screen[start + y*768] = color2; + } + + start = 380*768 + 131 + shift; + for(int y = 0; y < 131; y++){ + screen[start + y*768] = color1; + } + + + start = 378*768 + shift; + for(int y = 1; y < 132; y++){ + screen[start + y*768] = color1; + } + + start = 379*768 + 1 + shift; + for(int y = 0; y < 132; y++){ + screen[start + y*768] = color2; + } + + start = 380*768 + 2 + shift; + for(int y = 0; y < 131; y++){ + screen[start + y*768] = color1; + } + + start = 378*768 + 42 + shift; + for(int y = 1; y < 132; y++){ + screen[start + y*768] = color1; + } + + start = 379*768 + 43 + shift; + for(int y = 0; y < 132; y++){ + screen[start + y*768] = color2; + } + + start = 380*768 + 44 + shift; + for(int y = 0; y < 131; y++){ + screen[start + y*768] = color1; + } + + start = 378*768 + 86 + shift; + for(int y = 1; y < 132; y++){ + screen[start + y*768] = color1; + } + + start = 379*768 + 87 + shift; + for(int y = 0; y < 132; y++){ + screen[start + y*768] = color2; + } + + start = 380*768 + 88 + shift; + for(int y = 0; y < 131; y++){ + screen[start + y*768] = color1; + } + } + + + + + public void loadTexture(String imgName, int[] buffer, int width, int height, int[] buffer_dark){ + Image img = null; + try{ + img = ImageIO.read(getClass().getResource(imageFolder + imgName)); + }catch(Exception e){ + e.printStackTrace(); + } + + + PixelGrabber pg = new PixelGrabber(img, 0, 0, width, height, buffer, 0, width); + try { + pg.grabPixels(); + }catch(Exception e){ + e.printStackTrace(); + + } + + for(int i = 0; i < buffer_dark.length; i++){ + buffer_dark[i] = (buffer[i]&0xFEFEFE)>>1; + } + } +} diff --git a/gui/confirmationIcon.java b/gui/confirmationIcon.java new file mode 100644 index 0000000..bcfe49b --- /dev/null +++ b/gui/confirmationIcon.java @@ -0,0 +1,186 @@ +package gui; + +import core.postProcessingThread; +import core.vector; + +public class confirmationIcon { + + public int color; + + public static float[] sin; + public static float[] cos; + + //centre of the icon + public vector centre; + public vector tempCentre; + + public int frameIndex; + + + public confirmationIcon(){ + //Make sin and cos look up tables + sin = new float[361]; + cos = new float[361]; + for(int i = 0; i < 361; i ++){ + sin[i] = (float)Math.sin(Math.PI*i/180); + cos[i] = (float)Math.cos(Math.PI*i/180); + } + + centre = new vector(0,0,0); + tempCentre = new vector(0,0,0); + frameIndex = -1; + } + + public void setActive(float xPos, float zPos, int color){ + centre.set(xPos, -0.5001f, zPos); + this.color = color; + frameIndex = 20; + } + + public void updateAndDraw(){ + if(frameIndex <0) + return; + + vector cameraPosition = postProcessingThread.cameraPosition; + float X = 0,Y = 0, Z = 0, + camX = cameraPosition.x, camY = cameraPosition.y, camZ = cameraPosition.z, + sinXZ = postProcessingThread.sinXZ, + cosXZ = postProcessingThread.cosXZ, + sinYZ = postProcessingThread.sinYZ, + cosYZ = postProcessingThread.cosYZ; + + X = centre.x - camX; + Y = centre.y - camY; + Z = centre.z - camZ; + + //rotating + tempCentre.x = cosXZ*X - sinXZ*Z; + tempCentre.z = sinXZ*X + cosXZ*Z; + + Z = tempCentre.z; + + tempCentre.y = cosYZ*Y - sinYZ*Z; + tempCentre.z = sinYZ*Y + cosYZ*Z; + tempCentre.updateLocation(); + + int[] screen = postProcessingThread.currentScreen; + int x, y; + + float a = 13f; + float b = 11.5f; + + int lastIndex = -1; + int currentIndex; + int t = frameIndex - 10; + + float transparency = 0.7f; + + if(t < 0){ + t = 0; + transparency = (float)frameIndex * transparency/10f; + } + + + int r1,b1,g1, r2,b2,g2, screenColor; + + + //draw transparent ring + for(int i = 0; i < 360; i+=1){ + x = (int)(tempCentre.screenX + (a * (float)(12-t)/10f +0.7f) * cos[i]); + y = (int)(tempCentre.screenY + (b * (float)(12-t)/10f +0.7f)* sin[i]); + + if(x < 0 || x >= 768 || y < 0 || y >= 512) + continue; + + currentIndex = x + y * 768; + + if(currentIndex == lastIndex) + continue; + + screenColor = screen[currentIndex]; + r1 = (int)(((screenColor & 0xff0000) >> 16) * (1f - transparency*0.5f)); + g1 = (int)(((screenColor & 0xff00) >> 8) * (1f - transparency * 0.5f)); + b1 = (int)((screenColor & 0xff) * (1f - transparency * 0.5f)); + + r2 = (int)(((color & 0xff0000) >> 16) * transparency * 0.5f) + r1; + g2 = (int)(((color & 0xff00) >> 8) * transparency * 0.5f) + g1; + b2 = (int)((color & 0xff) * transparency * 0.5f) + b1; + + screen[x + y * 768] = r2 << 16 | g2 << 8 | b2; + + lastIndex = currentIndex; + } + + for(int i = 0; i < 360; i+=1){ + x = (int)(tempCentre.screenX + (a * (float)(12-t)/10f -1.7f) * cos[i]); + y = (int)(tempCentre.screenY + (b * (float)(12-t)/10f -1.7f)* sin[i]); + + if(x < 0 || x >= 768 || y < 0 || y >= 512) + continue; + + currentIndex = x + y * 768; + + if(currentIndex == lastIndex) + continue; + + + + screenColor = screen[currentIndex]; + r1 = (int)(((screenColor & 0xff0000) >> 16) * (1f - transparency*0.5f)); + g1 = (int)(((screenColor & 0xff00) >> 8) * (1f - transparency * 0.5f)); + b1 = (int)((screenColor & 0xff) * (1f - transparency * 0.5f)); + + r2 = (int)(((color & 0xff0000) >> 16) * transparency * 0.5f) + r1; + g2 = (int)(((color & 0xff00) >> 8) * transparency * 0.5f) + g1; + b2 = (int)((color & 0xff) * transparency * 0.5f) + b1; + + screen[x + y * 768] = r2 << 16 | g2 << 8 | b2; + + lastIndex = currentIndex; + } + + + //draw solid ring + for(int i = 0; i < 360; i+=1){ + x = (int)(tempCentre.screenX + (a * (float)(12-t)/10f) * cos[i]); + y = (int)(tempCentre.screenY + (b * (float)(12-t)/10f)* sin[i]); + + if(x < 0 || x >= 768 || y < 0 || y >= 512) + continue; + + screenColor = screen[x + y * 768]; + r1 = (int)(((screenColor & 0xff0000) >> 16) * (1f - transparency)); + g1 = (int)(((screenColor & 0xff00) >> 8) * (1f - transparency)); + b1 = (int)((screenColor & 0xff) * (1f - transparency)); + + r2 = (int)(((color & 0xff0000) >> 16) * transparency) + r1; + g2 = (int)(((color & 0xff00) >> 8) * transparency) + g1; + b2 = (int)((color & 0xff) * transparency) + b1; + + screen[x + y * 768] = r2 << 16 | g2 << 8 | b2; + } + + for(int i = 0; i < 360; i+=1){ + x = (int)(tempCentre.screenX + (a * (float)(12-t)/10f -1) * cos[i]); + y = (int)(tempCentre.screenY + (b * (float)(12-t)/10f- 1)* sin[i]); + + if(x < 0 || x >= 768 || y < 0 || y >= 512) + continue; + screenColor = screen[x + y * 768]; + r1 = (int)(((screenColor & 0xff0000) >> 16) * (1f - transparency)); + g1 = (int)(((screenColor & 0xff00) >> 8) * (1f - transparency)); + b1 = (int)((screenColor & 0xff) * (1f - transparency)); + + r2 = (int)(((color & 0xff0000) >> 16) * transparency) + r1; + g2 = (int)(((color & 0xff00) >> 8) * transparency) + g1; + b2 = (int)((color & 0xff) * transparency) + b1; + + screen[x + y * 768] = r2 << 16 | g2 << 8 | b2; + } + + frameIndex--; + + } + + +} diff --git a/gui/deployGrid.java b/gui/deployGrid.java new file mode 100644 index 0000000..ac0d6de --- /dev/null +++ b/gui/deployGrid.java @@ -0,0 +1,206 @@ +package gui; + +import core.*; +import entity.constructionYard; +import entity.solidObject; + +public class deployGrid { + public polygon3D[] polygons; + public boolean canBeDeployed; + public int[] gridArea; + public vector gridOneCenter; + public vector iDirection, jDirection, kDirection, start; + public vector clickPoint; + public constructionYard cy; + public int gridOneIndex; + public deployGrid(){ + gridArea = new int[9]; + iDirection = new vector(1,0,0); + jDirection = new vector(0,1,0); + kDirection = new vector(0,0,1); + start = new vector(0,0,0); + clickPoint = new vector(0,0,0); + + makeGrid(); + } + + public void makeGrid(){ + polygons = new polygon3D[9]; + + double w = 0; + double h = 0; + + vector[] v = new vector[]{put(-0.1 + w, -0.5, 0.12 + h), put(0.1 + w, -0.5, 0.12 + h), put(0.12 + w, -0.5, 0.1 + h), put(0.12 + w, -0.5, -0.1 + h), put(0.1 + w, -0.5, -0.12 + h), put(-0.1 + w, -0.5, -0.12 + h), put(-0.12 + w, -0.5, -0.1 + h), put(-0.12 + w, -0.5, 0.1 + h)}; + polygons[0] = new polygon3D(v, v[0], v[1], v [3], null, 1f,1f,10); + + w = 0.25; + h = 0; + + v = new vector[]{put(-0.1 + w, -0.5, 0.12 + h), put(0.1 + w, -0.5, 0.12 + h), put(0.12 + w, -0.5, 0.1 + h), put(0.12 + w, -0.5, -0.1 + h), put(0.1 + w, -0.5, -0.12 + h), put(-0.1 + w, -0.5, -0.12 + h), put(-0.12 + w, -0.5, -0.1 + h), put(-0.12 + w, -0.5, 0.1 + h)}; + polygons[1] = new polygon3D(v, v[0], v[1], v [3], null, 1f,1f,10); + + w = 0.5; + h = 0; + + v = new vector[]{put(-0.1 + w, -0.5, 0.12 + h), put(0.1 + w, -0.5, 0.12 + h), put(0.12 + w, -0.5, 0.1 + h), put(0.12 + w, -0.5, -0.1 + h), put(0.1 + w, -0.5, -0.12 + h), put(-0.1 + w, -0.5, -0.12 + h), put(-0.12 + w, -0.5, -0.1 + h), put(-0.12 + w, -0.5, 0.1 + h)}; + polygons[2] = new polygon3D(v, v[0], v[1], v [3], null, 1f,1f,10); + + w = 0; + h = -0.25; + + v = new vector[]{put(-0.1 + w, -0.5, 0.12 + h), put(0.1 + w, -0.5, 0.12 + h), put(0.12 + w, -0.5, 0.1 + h), put(0.12 + w, -0.5, -0.1 + h), put(0.1 + w, -0.5, -0.12 + h), put(-0.1 + w, -0.5, -0.12 + h), put(-0.12 + w, -0.5, -0.1 + h), put(-0.12 + w, -0.5, 0.1 + h)}; + polygons[3] = new polygon3D(v, v[0], v[1], v [3], null, 1f,1f,10); + + w = 0.25; + h = -0.25; + + v = new vector[]{put(-0.1 + w, -0.5, 0.12 + h), put(0.1 + w, -0.5, 0.12 + h), put(0.12 + w, -0.5, 0.1 + h), put(0.12 + w, -0.5, -0.1 + h), put(0.1 + w, -0.5, -0.12 + h), put(-0.1 + w, -0.5, -0.12 + h), put(-0.12 + w, -0.5, -0.1 + h), put(-0.12 + w, -0.5, 0.1 + h)}; + polygons[4] = new polygon3D(v, v[0], v[1], v [3], null, 1f,1f,10); + + w = 0.5; + h = -0.25; + + v = new vector[]{put(-0.1 + w, -0.5, 0.12 + h), put(0.1 + w, -0.5, 0.12 + h), put(0.12 + w, -0.5, 0.1 + h), put(0.12 + w, -0.5, -0.1 + h), put(0.1 + w, -0.5, -0.12 + h), put(-0.1 + w, -0.5, -0.12 + h), put(-0.12 + w, -0.5, -0.1 + h), put(-0.12 + w, -0.5, 0.1 + h)}; + polygons[5] = new polygon3D(v, v[0], v[1], v [3], null, 1f,1f,10); + + w = 0; + h = -0.5; + + v = new vector[]{put(-0.1 + w, -0.5, 0.12 + h), put(0.1 + w, -0.5, 0.12 + h), put(0.12 + w, -0.5, 0.1 + h), put(0.12 + w, -0.5, -0.1 + h), put(0.1 + w, -0.5, -0.12 + h), put(-0.1 + w, -0.5, -0.12 + h), put(-0.12 + w, -0.5, -0.1 + h), put(-0.12 + w, -0.5, 0.1 + h)}; + polygons[6] = new polygon3D(v, v[0], v[1], v [3], null, 1f,1f,10); + + w = 0.25; + h = -0.5; + + v = new vector[]{put(-0.1 + w, -0.5, 0.12 + h), put(0.1 + w, -0.5, 0.12 + h), put(0.12 + w, -0.5, 0.1 + h), put(0.12 + w, -0.5, -0.1 + h), put(0.1 + w, -0.5, -0.12 + h), put(-0.1 + w, -0.5, -0.12 + h), put(-0.12 + w, -0.5, -0.1 + h), put(-0.12 + w, -0.5, 0.1 + h)}; + polygons[7] = new polygon3D(v, v[0], v[1], v [3], null, 1f,1f,10); + + w = 0.5; + h = -0.5; + + v = new vector[]{put(-0.1 + w, -0.5, 0.12 + h), put(0.1 + w, -0.5, 0.12 + h), put(0.12 + w, -0.5, 0.1 + h), put(0.12 + w, -0.5, -0.1 + h), put(0.1 + w, -0.5, -0.12 + h), put(-0.1 + w, -0.5, -0.12 + h), put(-0.12 + w, -0.5, -0.1 + h), put(-0.12 + w, -0.5, 0.1 + h)}; + polygons[8] = new polygon3D(v, v[0], v[1], v [3], null, 1f,1f,10); + + for(int i = 0; i < 9; i++) + polygons[i].color = 31 << 5; + + gridOneCenter = new vector(0,0,0); + } + + public void update(){ + cy = mainThread.pc.selectedConstructionYard; + clickPoint.set(mainThread.my2Dto3DFactory.get3DLocation(mainThread.theAssetManager.Terrain.ground[0], inputHandler.mouse_x, inputHandler.mouse_y)); + + gridOneIndex = (int)(clickPoint.x*4) + (127 - (int)(clickPoint.z*4))*128; + + clickPoint.x = (float)((int)(clickPoint.x*4))/4 + 0.125f; + clickPoint.z = (float)((int)(clickPoint.z*4))/4 + 0.125f; + + float dx = clickPoint.x - gridOneCenter.x; + float dz = clickPoint.z - gridOneCenter.z; + + for(int i = 0; i < 9; i++){ + for(int j = 0; j < 8; j++){ + polygons[i].vertex3D[j].x+=dx; + polygons[i].vertex3D[j].z+=dz; + } + + } + + gridOneCenter.x = clickPoint.x; + gridOneCenter.z = clickPoint.z; + + if(cy != null){ + canBeDeployed = true; + if(cy.powerPlantProgress == 240 || cy.communicationCenterProgress == 240 || cy.techCenterProgress == 240){ + gridArea[0] = 1; if(!checkIfBlockIsFree(gridOneIndex)){ gridArea[0] = 2; canBeDeployed = false;} + gridArea[1] = 1; if(!checkIfBlockIsFree(gridOneIndex+1)){ gridArea[1] = 2; canBeDeployed = false;} + gridArea[2] = 0; + gridArea[3] = 1; if(!checkIfBlockIsFree(gridOneIndex + 128)){ gridArea[3] = 2; canBeDeployed = false;} + gridArea[4] = 1; if(!checkIfBlockIsFree(gridOneIndex + 129)){ gridArea[4] = 2; canBeDeployed = false;} + gridArea[5] = 0; + gridArea[6] = 0; + gridArea[7] = 0; + gridArea[8] = 0; + }else if(cy.refineryProgress == 240 || cy.factoryProgress == 240){ + gridArea[0] = 1; if(!checkIfBlockIsFree(gridOneIndex)){ gridArea[0] = 2; canBeDeployed = false;} + gridArea[1] = 1; if(!checkIfBlockIsFree(gridOneIndex+1)){ gridArea[1] = 2; canBeDeployed = false;} + gridArea[2] = 1; if(!checkIfBlockIsFree(gridOneIndex+2)){ gridArea[2] = 2; canBeDeployed = false;} + gridArea[3] = 1; if(!checkIfBlockIsFree(gridOneIndex + 128)){ gridArea[3] = 2; canBeDeployed = false;} + gridArea[4] = 1; if(!checkIfBlockIsFree(gridOneIndex + 129)){ gridArea[4] = 2; canBeDeployed = false;} + gridArea[5] = 1; if(!checkIfBlockIsFree(gridOneIndex + 130)){ gridArea[5] = 2; canBeDeployed = false;} + gridArea[6] = 1; if(!checkIfBlockIsFree(gridOneIndex + 256)){ gridArea[6] = 2; canBeDeployed = false;} + gridArea[7] = 1; if(!checkIfBlockIsFree(gridOneIndex + 257)){ gridArea[7] = 2; canBeDeployed = false;} + gridArea[8] = 1; if(!checkIfBlockIsFree(gridOneIndex + 258)){ gridArea[8] = 2; canBeDeployed = false;} + }else if(cy.gunTurretProgress == 240 || cy.missileTurretProgress == 240){ + gridArea[0] = 1; if(!checkIfBlockIsFree(gridOneIndex)){ gridArea[0] = 2; canBeDeployed = false;} + gridArea[1] = 0; + gridArea[2] = 0; + gridArea[3] = 0; + gridArea[4] = 0; + gridArea[5] = 0; + gridArea[6] = 0; + gridArea[7] = 0; + gridArea[8] = 0; + } + + + } + } + + public void draw(){ + for(int i = 0; i < 9; i++){ + if(gridArea[i] >= 1){ + polygons[i].update(); + + if(gridArea[i] == 1) + polygons[i].color = 31 << 5; + else + polygons[i].color = 31 << 10; + + polygons[i].draw(); + } + } + + } + + public boolean checkIfBlockIsFree(int index){ + int y = index/128; + int x = index%128; + + if(y > 0 && y < 127 && x > 0 && x < 127){ + solidObject[] tile = mainThread.gridMap.tiles[index]; + for(int j = 0; j < 5; j++){ + if(tile[j] != null){ + return false; + } + } + + constructionYard[] cys = mainThread.theAssetManager.constructionYards; + + for(int i = 0; i < cys.length; i++){ + if(cys[i] != null && cys[i].teamNo == 0){ + float xPos = x * 0.25f + 0.125f; + float yPos = (127 - y)*0.25f + 0.125f; + + float distance = (float) Math.sqrt((cys[i].centre.x - xPos)*(cys[i].centre.x - xPos) + (cys[i].centre.z - yPos)*(cys[i].centre.z - yPos)); + if(distance <= 2.75) + return true; + } + } + } + + return false; + + } + + //create a arbitrary vertex + public vector put(double i, double j, double k){ + vector temp = start.myClone(); + temp.add(iDirection, (float)i); + temp.add(jDirection, (float)j); + temp.add(kDirection, (float)k); + return temp; + } + +} diff --git a/gui/inputHandler.java b/gui/inputHandler.java new file mode 100644 index 0000000..2fbf80a --- /dev/null +++ b/gui/inputHandler.java @@ -0,0 +1,252 @@ +package gui; + +//handles all the logic for user input + +import java.awt.*; + +import core.camera; +import core.geometry; +import core.mainThread; + +public class inputHandler { + + public static int mouse_x, mouse_y,mouse_x0, mouse_x1, mouse_y0, mouse_y1, cameraMovementAngle; + + public static boolean mouseIsInsideScreen, leftKeyPressed, rightKeyPressed, controlKeyPressed, leftMouseButtonPressed, rightMouseButtonPressed, leftMouseButtonReleased, rightMouseButtonReleased, H_pressed,A_pressed, userIsHoldingA; + + public static int numberTyped; + + public static final Rectangle mouseMovementArea = new Rectangle(30,20, 708, 472); + + public static char[] inputBuffer = new char[1024]; + public static char[] keyReleaseBuffer = new char[1024]; + + public static int inputCounter, inputBufferIndex, keyReleaseCounter, keyReleaseBufferIndex; + + public static void processInput(){ + //read input char + int theCounter = inputCounter; + //handle over flow + if(inputBufferIndex > theCounter){ + while(inputBufferIndex < 1024){ + char c = inputBuffer[inputBufferIndex]; + + + if(c == 'h' || c == 'H'){ + H_pressed = true; + } + + if(c == 'a' || c == 'A'){ + A_pressed = true; + } + + if(c >=49 && c <=53){ + numberTyped = c - 48; + } + + + inputBufferIndex++; + } + inputBufferIndex = 0; + } + + while(inputBufferIndex < theCounter){ + char c = inputBuffer[inputBufferIndex]; + + + if(c == 'h' || c == 'H'){ + H_pressed = true; + } + + if(c == 'a' || c == 'A'){ + A_pressed = true; + } + + if(c >=49 && c <=53){ + numberTyped = c - 48; + } + + inputBufferIndex++; + } + + //read released char + theCounter = keyReleaseCounter; + //handle over flow + if(keyReleaseBufferIndex > theCounter){ + while(keyReleaseBufferIndex < 1024){ + char c = keyReleaseBuffer[keyReleaseBufferIndex]; + if(c == 'h' || c == 'H'){ + H_pressed = false; + } + + if(c == 'a' || c == 'A'){ + A_pressed = false; + userIsHoldingA = false; + + } + keyReleaseBufferIndex++; + } + keyReleaseBufferIndex = 0; + } + while(keyReleaseBufferIndex < theCounter){ + char c = keyReleaseBuffer[keyReleaseBufferIndex]; + if(c == 'h' || c == 'H'){ + H_pressed = false; + } + + if(c == 'a' || c == 'A'){ + A_pressed = false; + userIsHoldingA = false; + + } + keyReleaseBufferIndex++; + } + + + //handle input when game is running + if(mainThread.inGame){ + if(!mainThread.pc.isSelectingUnit){ + mouse_x0 = mouse_x; + mouse_y0 = mouse_y; + if(!mouseIsInsideScreen || !mouseMovementArea.contains(mouse_x0, mouse_y0)){ + + if(mainThread.pc.cursorIsInMiniMap() || mainThread.pc.cursorIsInSideBar()){ + if(mouse_x0 < 10) + camera.MOVE_LEFT = true; + if(mouse_x0 > 758) + camera.MOVE_RIGHT = true; + if(mouse_y0 < 20) + camera.MOVE_UP = true; + if(mouse_y0 > 502) + camera.MOVE_DOWN = true; + + }else{ + + if(mouse_x0 < 40) + camera.MOVE_LEFT = true; + if(mouse_x0 > 728) + camera.MOVE_RIGHT = true; + if(mouse_y0 < 40) + camera.MOVE_UP = true; + if(mouse_y0 > 472) + camera.MOVE_DOWN = true; + } + + + if(camera.MOVE_LEFT || camera.MOVE_RIGHT || camera.MOVE_UP || camera.MOVE_DOWN){ + int angle = geometry.findAngle(mouse_x0, mouse_y0, mouse_x1, mouse_y1); + if(angle != 0){ + cameraMovementAngle = angle; + } + + + if(mouse_x0 < 250 && mouse_y0 > 362 && cameraMovementAngle > 105 && cameraMovementAngle < 165){ + camera.MOVE_LEFT = true; + camera.MOVE_DOWN = true; + } + + if(mouse_x0 < 250 && mouse_y0 < 150 && cameraMovementAngle < 75){ + camera.MOVE_LEFT = true; + camera.MOVE_UP = true; + } + + if(mouse_x0 > 518 && mouse_y0 < 150 && cameraMovementAngle > 285){ + camera.MOVE_RIGHT = true; + camera.MOVE_UP = true; + } + + if(mouse_x0 > 518 && mouse_y0 > 362 && cameraMovementAngle < 255 && cameraMovementAngle > 195){ + camera.MOVE_RIGHT = true; + camera.MOVE_DOWN = true; + } + + } + } + + + if(leftKeyPressed){ + camera.TURN_LEFT = true; + } + + if(rightKeyPressed){ + camera.TURN_RIGHT = true; + } + + mouse_x1 = mouse_x0; + mouse_y1 = mouse_y0; + } + + + if(controlKeyPressed){ + mainThread.pc.controlKeyPressed = true; + } + + if(numberTyped != 0){ + mainThread.pc.numberTyped = numberTyped; + + } + + //handles left click + if(leftMouseButtonPressed){ + mainThread.pc.leftMouseButtonPressed = true; + + } + + if(leftMouseButtonReleased){ + mainThread.pc.leftMouseButtonReleased = true; + } + + //handles right click + if(rightMouseButtonPressed){ + mainThread.pc.rightMouseButtonPressed = true; + } + + if(rightMouseButtonReleased){ + mainThread.pc.rightMouseButtonReleased = true; + } + + //handle hotheys + if(H_pressed){ + + mainThread.pc.holdKeyPressed = true; + } + + + //handle hotheys + if(A_pressed){ + + if(!userIsHoldingA){ + mainThread.pc.attackKeyPressed = true; + userIsHoldingA = true; + } + + } + } + + + mouseIsInsideScreen = false; + leftMouseButtonPressed = false; + rightMouseButtonPressed = false; + leftMouseButtonReleased = false; + rightMouseButtonReleased = false; + + A_pressed = false; + numberTyped = 0; + + } + + public static void readCharacter(char c){ + inputBuffer[inputCounter] = c; + inputCounter++; + if(inputCounter == 1024) + inputCounter = 0; + } + + public static void handleKeyRelease(char c){ + keyReleaseBuffer[keyReleaseCounter] = c; + keyReleaseCounter++; + if(keyReleaseCounter == 1024) + keyReleaseCounter = 0; + } + +} diff --git a/gui/playerCommander.java b/gui/playerCommander.java new file mode 100644 index 0000000..7b36417 --- /dev/null +++ b/gui/playerCommander.java @@ -0,0 +1,748 @@ +package gui; + +import java.awt.Rectangle; + +import core.AssetManager; +import core.baseInfo; +import core.camera; +import core.mainThread; +import core.vector; +import entity.constructionYard; +import entity.solidObject; + +//this class interprets player's inputs and turns them into commands that can be issued to game units +public class playerCommander { + + public solidObject[] selectedUnits; + + public solidObject[][] groups; + + public boolean leftMouseButtonPressed, rightMouseButtonPressed, leftMouseButtonReleased, rightMouseButtonReleased, attackKeyPressed, holdKeyPressed, controlKeyPressed; + + public int numberTyped; + + public boolean isSelectingUnit, isMovingViewWindow; + + public int startX, startY, endX, endY; + + public Rectangle area, areaSmall; + + public vector clickPoint; + + public AssetManager theAssetManager; + + public int numberOfSelectedUnits; + + public int doubleClickCountDown; + + public boolean doubleClicked; + + public int doubleNumberPressCountdown; + public int pressedNumber; + public boolean doubleNumberPressed; + public int selectedIndex; + + + public sideBarManager theSideBarManager; + + public boolean isDeployingBuilding; + public constructionYard selectedConstructionYard; + + public baseInfo theBaseInfo; + + public void init(){ + selectedUnits = new solidObject[100]; + groups = new solidObject[5][100]; + area = new Rectangle(); + areaSmall = new Rectangle(); + clickPoint = new vector(0,0,0); + theAssetManager = mainThread.theAssetManager; + theSideBarManager = new sideBarManager(this); + theBaseInfo = new baseInfo(); + + } + + + + + public void update(){ + theBaseInfo.update(); + + if(isDeployingBuilding){ + + if(leftMouseButtonPressed && !cursorIsInMiniMap() && !cursorIsInSideBar() && selectedConstructionYard.dg.canBeDeployed){ + //create a new building + selectedConstructionYard.createBuilding(); + isDeployingBuilding = false; + selectedConstructionYard.needToDrawDeploymentGrid = false; + selectedConstructionYard.finishDeployment(); + selectedConstructionYard = null; + leftMouseButtonPressed = false; + } + + if(rightMouseButtonPressed){ + isDeployingBuilding = false; + selectedConstructionYard.needToDrawDeploymentGrid = false; + selectedConstructionYard = null; + rightMouseButtonPressed = false; + }else{ + if(!cursorIsInMiniMap()){ + theSideBarManager.update(); + leftMouseButtonPressed = false; + isMovingViewWindow = false; + return; + } + } + } + + if(doubleClickCountDown > 0) + doubleClickCountDown--; + if(doubleClickCountDown == 0) + doubleClicked = false; + + if(doubleNumberPressCountdown > 0) + doubleNumberPressCountdown--; + if(doubleNumberPressCountdown == 0){ + pressedNumber = 255; + + } + + + if(numberTyped != 0){ + + if(controlKeyPressed){ + for(int i = 0; i < 100; i ++){ + if(groups[numberTyped-1][i] != null){ + groups[numberTyped-1][i].groupNo = 255; + groups[numberTyped-1][i] = null; + } + } + + for(int i = 0; i < 100; i ++){ + + if(selectedUnits[i] != null){ + if(selectedUnits[i].teamNo == 0){ + groups[numberTyped-1][i] = selectedUnits[i]; + selectedUnits[i].groupNo = numberTyped-1; + + selectedUnits[i].isSelected = true; + removeFromOtherGroup(selectedUnits[i], numberTyped-1); + } + } + } + }else{ + if(numberTyped == pressedNumber){ + doubleNumberPressed = true; + doubleNumberPressCountdown = 30; + + }else{ + doubleNumberPressed = false; + pressedNumber = numberTyped; + doubleNumberPressCountdown = 10; + } + + numberOfSelectedUnits = 0; + for(int i = 0; i < 100; i ++){ + if(selectedUnits[i] != null) + selectedUnits[i].isSelected = false; + selectedUnits[i] = null; + if(groups[numberTyped-1][i] != null) + if(groups[numberTyped-1][i].currentHP > 0){ + selectedUnits[i] = groups[numberTyped-1][i]; + groups[numberTyped-1][i].isSelected = true; + numberOfSelectedUnits++; + } + } + + //center camera to the one of the selected units + if(doubleNumberPressed){ + solidObject selectedUnit = null; + int nullCount = 0; + + for(int j = 0; j < 100; j++){ + if(selectedUnits[(j+selectedIndex)%100] != null){ + selectedUnit = selectedUnits[(j+selectedIndex)%100]; + selectedIndex++; + break; + }else{ + nullCount++; + } + } + + selectedIndex+=nullCount; + + if(selectedUnit != null){ + + camera.position.x = selectedUnit.centre.x - camera.view_Direction.x * 3; + camera.position.z = selectedUnit.centre.z - camera.view_Direction.z * 3; + } + + } + } + } + + + + if(leftMouseButtonPressed){ + if(cursorIsInSideBar()) + theSideBarManager.leftMouseButtonClicked = true; + + + if(attackKeyPressed){ + //if the click lands on empty ground perform "attack move" for all selected unit + //if the click lands on an unit, then attack that unit regardless if it is friend or foe + + boolean performAttack = false; + if(numberOfSelectedUnits > 1){ + performAttack = true; + } + if(numberOfSelectedUnits ==1){ + if(selectedUnits[0] != null) //null pointer happened here once, not sure why + if(selectedUnits[0].teamNo == 0) + performAttack = true; + + } + + if(performAttack){ + + if(cursorIsInMiniMap()){ + clickPoint.set(0.25f*(inputHandler.mouse_x-3), 0, 0.25f*(127-(inputHandler.mouse_y-381))); + attackMoveSelectUnit(clickPoint.x, clickPoint.z); + + }else if(cursorIsInSideBar()){ + theSideBarManager.leftMouseButtonClicked = true; + + }else{ + clickPoint.set(mainThread.my2Dto3DFactory.get3DLocation(theAssetManager.Terrain.ground[0], inputHandler.mouse_x, inputHandler.mouse_y)); + float x = clickPoint.x; + float y = clickPoint.z; + + //if click outside map boundary, move units to the closest valid tile + if(x < 0.25 || x > 31.75 || y < 0.25 || y > 31.75){ + if( x < 0.25) + x = 0.125f; + if(x > 31.75) + x = 31.875f; + if(y < 0.25) + y = 0.125f; + if(y > 31.75) + y = 31.875f; + } + + int xPos = (int)(x*64); + int yPos = (int)(y*64); + int index = xPos/16 + (127-yPos/16)*128; + boolean clickOnEmptyGround = true; + for(int i = 0; i < mainThread.gridMap.tiles[index].length; i++){ + + if(mainThread.gridMap.tiles[index][i] != null){ + + if(mainThread.gridMap.tiles[index][i].boundary2D.contains(xPos, yPos)){ + if(mainThread.gridMap.tiles[index][i].visible_minimap){ + attackUnit(mainThread.gridMap.tiles[index][i]); + clickOnEmptyGround = false; + break; + } + } + } + } + + if(clickOnEmptyGround){ + + attackMoveSelectUnit(x, y); + + } + + + } + } + + + attackKeyPressed = false; + + }else{ + if(cursorIsInMiniMap()){ + isMovingViewWindow = true; + }else{ + + if(doubleClickCountDown == 0) + doubleClickCountDown = 10; + else + doubleClicked = true; + + if(!cursorIsInSideBar()) + isSelectingUnit = true; + startX = inputHandler.mouse_x; + startY = inputHandler.mouse_y; + } + } + + } + + if(isMovingViewWindow){ + camera.position.x = 0.25f*(inputHandler.mouse_x-3) - camera.view_Direction.x * 3; + camera.position.z = 0.25f*(127-(inputHandler.mouse_y-381)) - camera.view_Direction.z * 3; + + + } + + if(isSelectingUnit){ + endX = inputHandler.mouse_x; + endY = inputHandler.mouse_y; + + if(startX < 0) + startX = 0; + if(startX >767) + startX = 767; + if(startY < 0) + startY = 0; + if(startY > 511) + startY = 511; + if(endX > 767) + endX = 767; + if(endX < 0) + endX = 0; + if(endY > 511) + endY = 511; + if(endY < 0) + endY = 0; + + int width = Math.abs(endX - startX); + int height = Math.abs(endY - startY); + int xPos = Math.min(startX, endX); + int yPos = Math.min(startY, endY); + area.setBounds(xPos, yPos,width, height); + } + + if(leftMouseButtonReleased){ + + + if(isMovingViewWindow){ + isMovingViewWindow = false; + } + + + if(isSelectingUnit){ + isSelectingUnit = false; + int width = Math.abs(endX - startX); + int height = Math.abs(endY - startY); + int xPos = Math.min(startX, endX) - 50; + int yPos = Math.min(startY, endY) -20; + int xPos_small = Math.min(startX, endX) - 20; + int yPos_small = Math.min(startY, endY) -20; + + if(width < 20 || height < 20){ + area.setBounds(xPos, yPos, 100, 100); + areaSmall.setBounds(xPos_small, yPos_small, 40,40); + selectUnit(area, areaSmall); + }else + selectMultipleUnits(area); + } + + } + + if(rightMouseButtonPressed){ + attackKeyPressed = false; + + if(cursorIsInMiniMap()){ + clickPoint.set(0.25f*(inputHandler.mouse_x-3), 0, 0.25f*(127-(inputHandler.mouse_y-381))); + }else{ + clickPoint.set(mainThread.my2Dto3DFactory.get3DLocation(theAssetManager.Terrain.ground[0], inputHandler.mouse_x, inputHandler.mouse_y)); + } + + if(!cursorIsInSideBar()){ + maneuverUnit(); + }else{ + theSideBarManager.rightMouseButtonClicked = true; + } + + } + + if(holdKeyPressed){ + holdAllSelectedUnit(); + } + + + //display health bar when mouse cursor hover over a unit + if(!isSelectingUnit){ + startX = inputHandler.mouse_x; + startY = inputHandler.mouse_y; + + + + int xPos = startX - 50; + int yPos = startY -20; + int xPos_small = startX - 30; + int yPos_small = startY -30; + + area.setBounds(xPos, yPos, 100, 100); + areaSmall.setBounds(xPos_small, yPos_small, 60,60); + addDelectUnitToDisplayInfo(area, areaSmall); + + } + + theSideBarManager.update(); + + leftMouseButtonPressed = false; + rightMouseButtonPressed = false; + leftMouseButtonReleased = false; + rightMouseButtonReleased = false; + holdKeyPressed = false; + controlKeyPressed = false; + numberTyped = 0; + } + + + + public boolean cursorIsInMiniMap(){ + return inputHandler.mouse_x >=3 && inputHandler.mouse_x <=131 && inputHandler.mouse_y >= 381 && inputHandler.mouse_y <= 509; + } + + public boolean cursorIsInSideBar(){ + return inputHandler.mouse_x >=637 && inputHandler.mouse_x <=765 && inputHandler.mouse_y >= 381 && inputHandler.mouse_y <= 509; + } + + + + public void removeDestoryedObjectFromSelection(solidObject o){ + for(int i = 0; i < selectedUnits.length; i++){ + if(selectedUnits[i] == o){ + selectedUnits[i] = null; + numberOfSelectedUnits--; + } + + } + } + + public void holdAllSelectedUnit(){ + for(int i = 0; i < selectedUnits.length; i++){ + if(selectedUnits[i] != null){ + if(selectedUnits[i].teamNo == 0){ + selectedUnits[i].hold(); + } + } + } + } + + public void moveSelectedUnit(float x, float y){ + boolean mobileUnitSelected = false; + for(int i = 0; i < selectedUnits.length; i++){ + if(selectedUnits[i] != null){ + if(selectedUnits[i].teamNo == 0 && (selectedUnits[i].type < 100 || selectedUnits[i].type == 105)){ + selectedUnits[i].moveTo(x, y); + selectedUnits[i].currentCommand = solidObject.move; + selectedUnits[i].secondaryCommand = solidObject.StandBy; + mobileUnitSelected = true; + } + } + } + + //draw move confirmation if a mobile unit is given move order + if(mobileUnitSelected){ + theAssetManager.confirmationIconInfo[0] = 1; + theAssetManager.confirmationIconInfo[1] = x; + theAssetManager.confirmationIconInfo[2] = y; + theAssetManager.confirmationIconInfo[3] = 0xbb22; + } + + } + + public void attackMoveSelectUnit(float x, float y){ + boolean mobileUnitSelected = false; + for(int i = 0; i < selectedUnits.length; i++){ + if(selectedUnits[i] != null){ + if(selectedUnits[i].teamNo == 0 && selectedUnits[i].type != 2 && selectedUnits[i].type != 3 && selectedUnits[i].type < 100){ //not harvesters or MCVs or any buildings + selectedUnits[i].attackMoveTo(x, y); + selectedUnits[i].currentCommand = solidObject.attackMove; + selectedUnits[i].secondaryCommand = solidObject.attackMove; + mobileUnitSelected = true; + } + } + } + + //draw attack move confirmation if a mobile unit is given attack move order + if(mobileUnitSelected){ + theAssetManager.confirmationIconInfo[0] = 1; + theAssetManager.confirmationIconInfo[1] = x; + theAssetManager.confirmationIconInfo[2] = y; + theAssetManager.confirmationIconInfo[3] = 0xcc2222; + } + + } + + public void addDelectUnitToDisplayInfo(Rectangle unitArea, Rectangle unitAreaSmall){ + solidObject theSelected = null; + for(int i = 0; i < theAssetManager.visibleUnitCount; i++){ + if(unitArea.contains(theAssetManager.visibleUnit[i].tempCentre.screenX, theAssetManager.visibleUnit[i].tempCentre.screenY)){ + if((theAssetManager.visibleUnit[i].type < 100 || theAssetManager.visibleUnit[i].type >= 199) && !unitAreaSmall.contains(theAssetManager.visibleUnit[i].tempCentre.screenX, theAssetManager.visibleUnit[i].tempCentre.screenY)) + continue; + + if(theAssetManager.visibleUnit[i].type < 100 || theAssetManager.visibleUnit[i].type >= 199){ + theSelected = theAssetManager.visibleUnit[i]; + break; + } + + theSelected = theAssetManager.visibleUnit[i]; + } + } + + if(theSelected != null && !theSelected.isSelected && theSelected.isSelectable){ + mainThread.theAssetManager.selectedUnitsInfo[99][0] = theSelected.level << 16 | theSelected.groupNo << 8 | theSelected.type; + mainThread.theAssetManager.selectedUnitsInfo[99][1] = (int)theSelected.tempCentre.screenX; + mainThread.theAssetManager.selectedUnitsInfo[99][2] = (int)theSelected.tempCentre.screenY; + if(theSelected.type == 199){ + mainThread.theAssetManager.selectedUnitsInfo[99][1] = (int)theSelected.screenX_gui; + mainThread.theAssetManager.selectedUnitsInfo[99][2] = (int)theSelected.screenY_gui; + } + + mainThread.theAssetManager.selectedUnitsInfo[99][3] = (int)theSelected.type; + mainThread.theAssetManager.selectedUnitsInfo[99][4] = theSelected.currentHP; + mainThread.theAssetManager.selectedUnitsInfo[99][5] = theSelected.progressStatus; + }else{ + mainThread.theAssetManager.selectedUnitsInfo[99][0] = -1; + } + } + + public void selectUnit(Rectangle unitArea, Rectangle unitAreaSmall){ + + + solidObject theSelected = null; + + for(int i = 0; i < theAssetManager.visibleUnitCount; i++){ + if(unitArea.contains(theAssetManager.visibleUnit[i].tempCentre.screenX, theAssetManager.visibleUnit[i].tempCentre.screenY)){ + if((theAssetManager.visibleUnit[i].type < 100 || theAssetManager.visibleUnit[i].type >= 199) && !unitAreaSmall.contains(theAssetManager.visibleUnit[i].tempCentre.screenX, theAssetManager.visibleUnit[i].tempCentre.screenY)) + continue; + + if(theAssetManager.visibleUnit[i].type < 100 || theAssetManager.visibleUnit[i].type >= 199){ + theSelected = theAssetManager.visibleUnit[i]; + break; + } + + theSelected = theAssetManager.visibleUnit[i]; + } + } + + if(theSelected != null){ + + if(!controlKeyPressed) + deSelectAll(); + + if(theSelected.isSelected && controlKeyPressed && !doubleClicked){ + deSelect(theSelected); + return; + } + + addToSelection(theSelected); + theSelected.isSelected = true; + + if(doubleClicked){ + int type = theSelected.type; + for(int j = 0; j < theAssetManager.visibleUnitCount; j++){ + if(theAssetManager.visibleUnit[j] != theSelected && theAssetManager.visibleUnit[j].type == type && theAssetManager.visibleUnit[j].teamNo == 0){ + + addToSelection(theAssetManager.visibleUnit[j]); + theAssetManager.visibleUnit[j].isSelected = true; + } + + } + + doubleClicked = false; + doubleClickCountDown = 0; + } + } + + } + + public void selectMultipleUnits(Rectangle area){ + + boolean unitIsSelected = false;; + for(int i = 0; i < theAssetManager.visibleUnitCount; i++){ + if(theAssetManager.visibleUnit[i].teamNo == 0 && area.contains(theAssetManager.visibleUnit[i].tempCentre.screenX, theAssetManager.visibleUnit[i].tempCentre.screenY)){ + if(!unitIsSelected){ + if(!controlKeyPressed) + deSelectAll(); + unitIsSelected = true; + } + addToSelection(theAssetManager.visibleUnit[i]); + theAssetManager.visibleUnit[i].isSelected = true; + } + } + } + + public void addToSelection(solidObject o){ + //dont add gold mine to select units + //if(o.type == 103) + // return; + + if(!o.isSelectable) + return; + + deSelect(o); + for(int i = 0; i < 100; i++){ + if(selectedUnits[i] == null){ + selectedUnits[i] = o; + o.isSelected = true; + if(o.teamNo == 0) + numberOfSelectedUnits++; + break; + } + } + } + + public void deSelect(solidObject o){ + for(int i = 0; i < 100; i++){ + if(selectedUnits[i] == o){ + selectedUnits[i].isSelected = false; + selectedUnits[i] = null; + numberOfSelectedUnits--; + break; + } + } + } + + public void deSelectAll(){ + for(int i = 0; i < 100; i++){ + if(selectedUnits[i] != null){ + selectedUnits[i].isSelected = false; + selectedUnits[i] = null; + } + + + + } + numberOfSelectedUnits = 0; + } + + public void selectGroup(int groupNo){ + for(int i = 0; i < 100; i++){ + selectedUnits[i] = groups[groupNo][i]; + } + } + + public void maneuverUnit(){ + + + float x = clickPoint.x; + float y = clickPoint.z; + + //if click outside map boundary, move units to the closest valid tile + if(x < 0.25 || x > 31.75 || y < 0.25 || y > 31.75){ + if( x < 0.25) + x = 0.125f; + if(x > 31.75) + x = 31.885f; + if(y < 0.25) + y = 0.125f; + if(y > 31.75) + y = 31.885f; + moveSelectedUnit(x,y); + return; + } + + //find out if the click point lands on a friend unit or an enemy unit or empty ground + int xPos = (int)(clickPoint.x*64); + int yPos = (int)(clickPoint.z*64); + int index = xPos/16 + (127-yPos/16)*128; + + for(int i = 0; i < mainThread.gridMap.tiles[index].length; i++){ + if(mainThread.gridMap.tiles[index][i] != null){ + if(mainThread.gridMap.tiles[index][i].boundary2D.contains(xPos, yPos)){ + //handle right click on a gold mine + if(mainThread.gridMap.tiles[index][i].type == 103){ + harvestMine(mainThread.gridMap.tiles[index][i]); + return; + }else if(mainThread.gridMap.tiles[index][i].type == 102 && mainThread.gridMap.tiles[index][i].teamNo == 0){ + returnToRefinery(mainThread.gridMap.tiles[index][i]); + + return; + }else if(mainThread.gridMap.tiles[index][i].teamNo != 0 && mainThread.gridMap.tiles[index][i].visible_minimap && !cursorIsInMiniMap()){ + //the enemy is only clickable if its visible in minimap + attackUnit(mainThread.gridMap.tiles[index][i]); + return; + } + + } + } + } + + moveSelectedUnit(x,y); + + } + + public void attackUnit(solidObject o){ + if(o.isCloaked && o.teamNo != 0) + return; + + boolean combatUnitSelected = false; + for(int i = 0; i < selectedUnits.length; i++){ + if(selectedUnits[i] != null && selectedUnits[i].teamNo != -1){ // make sure it won't target gold mine + if(selectedUnits[i].teamNo == 0 && selectedUnits[i] != o && selectedUnits[i].type != 2 && selectedUnits[i].type != 3 && (selectedUnits[i].type < 100 || selectedUnits[i].type >=199)){ //can't attack self + selectedUnits[i].attack(o); + if(numberOfSelectedUnits <= 4) + selectedUnits[i].currentCommand = solidObject.attackCautiously; + else + selectedUnits[i].currentCommand = solidObject.attackInNumbers; + selectedUnits[i].secondaryCommand = solidObject.StandBy; + + combatUnitSelected = true; + } + } + } + + //draw attack confirmation if a combat unit is given attack order + if(combatUnitSelected){ + theAssetManager.confirmationIconInfo[0] = 1; + theAssetManager.confirmationIconInfo[1] = o.centre.x; + theAssetManager.confirmationIconInfo[2] = o.centre.z; + theAssetManager.confirmationIconInfo[3] = 0xcc2222; + } + + } + + public void harvestMine(solidObject o){ + for(int i = 0; i < selectedUnits.length; i++){ + if(selectedUnits[i] != null){ + if(selectedUnits[i].teamNo == 0 && (selectedUnits[i].type == 2 || selectedUnits[i].type == 105)){ //must be a harvester/factory to perform such a move + selectedUnits[i].harvest(o); + theAssetManager.confirmationIconInfo[0] = 1; + theAssetManager.confirmationIconInfo[1] = o.centre.x; + theAssetManager.confirmationIconInfo[2] = o.centre.z; + theAssetManager.confirmationIconInfo[3] = 0xbbbb00; + + } + } + } + } + + public void returnToRefinery(solidObject o){ + for(int i = 0; i < selectedUnits.length; i++){ + if(selectedUnits[i] != null){ + if(selectedUnits[i].teamNo == 0 && selectedUnits[i].type == 2){ //must be a harvester to perform such a move + selectedUnits[i].returnToRefinery(o); + theAssetManager.confirmationIconInfo[0] = 1; + theAssetManager.confirmationIconInfo[1] = o.centre.x; + theAssetManager.confirmationIconInfo[2] = o.centre.z; + theAssetManager.confirmationIconInfo[3] = 0xbbbb00; + } + } + } + } + + + public void removeFromOtherGroup(solidObject o, int groupNumber){ + for(int i = 0; i < groups.length; i++){ + if(i != groupNumber){ + for(int j = 0; j < groups[i].length; j++){ + if(groups[i][j] == o){ + groups[i][j] = null; + break; + } + } + } + } + } + + +} + + diff --git a/gui/sideBarManager.java b/gui/sideBarManager.java new file mode 100644 index 0000000..520ba61 --- /dev/null +++ b/gui/sideBarManager.java @@ -0,0 +1,842 @@ +package gui; + +import core.mainThread; +import entity.*; + +//this class handles player's interaction with the sidebar +public class sideBarManager { + + public playerCommander pc; + public boolean rightMouseButtonClicked; + public boolean leftMouseButtonClicked; + + public boolean cursorInBlock0; + public boolean cursorInBlock1; + public boolean cursorInBlock2; + public boolean cursorInBlock3; + public boolean cursorInBlock4; + public boolean cursorInBlock5; + public boolean cursorInBlock6; + public boolean cursorInBlock7; + public boolean cursorInBlock8; + + public boolean onlyFactorySelected; + + public boolean factoryRallyOnSameGoldMine; + + public int[] sideBarInfo; + public int[] sideBarInfo2; + + + public sideBarManager(playerCommander pc){ + this.pc = pc; + sideBarInfo = new int[9]; + sideBarInfo2 = new int[9]; + + for(int i = 0; i < 9; i ++){ + sideBarInfo[i] = -1; + sideBarInfo2[i] = -1; + } + + } + + public void update(){ + //reset sideBarInfo + for(int i = 0; i < 9; i++) + sideBarInfo[i] = -1; + + //check selected units; + solidObject[] selectedUnits = pc.selectedUnits; + solidObject selectedObject = null; + + + + int mouseX = inputHandler.mouse_x; + int mouseY = inputHandler.mouse_y; + + + int x1 = 635; int y1 = 381; + int x2 = 677; int y2 = 425; + int x3 = 722; int y3 = 468; + int x4 = 766; int y4 = 509; + + + if(mouseX > x1 && mouseX < x2 && mouseY > y1 && mouseY < y2){ + cursorInBlock0 = true; + }else if(mouseX > x2 && mouseX < x3 && mouseY > y1 && mouseY < y2){ + cursorInBlock1 = true; + }else if(mouseX > x3 && mouseX < x4 && mouseY > y1 && mouseY < y2){ + cursorInBlock2 = true; + }else if(mouseX > x1 && mouseX < x2 && mouseY > y2 && mouseY < y3){ + cursorInBlock3 = true; + }else if(mouseX > x2 && mouseX < x3 && mouseY > y2 && mouseY < y3){ + cursorInBlock4 = true; + }else if(mouseX > x3 && mouseX < x4 && mouseY > y2 && mouseY < y3){ + cursorInBlock5 = true; + }else if(mouseX > x1 && mouseX < x2 && mouseY > y3 && mouseY < y4){ + cursorInBlock6 = true; + }else if(mouseX > x2 && mouseX < x3 && mouseY > y3 && mouseY < y4){ + cursorInBlock7 = true; + }else if(mouseX > x3 && mouseX < x4 && mouseY > y3 && mouseY < y4){ + cursorInBlock8 = true; + } + + + + + //side bar will be interactive only if the selected units are the same type + for(int i = 0; i < selectedUnits.length;i++){ + if(selectedUnits[i] != null && selectedUnits[i].teamNo == 0){ + if(selectedObject == null){ + selectedObject = selectedUnits[i]; + }else{ + if(selectedObject.type != selectedUnits[i].type){ + selectedObject = null; + break; + } + } + } + + if(selectedUnits[i] != null && selectedUnits[i].teamNo != 0){ + selectedObject = null; + break; + } + + } + + //check if any building is selected + boolean buildingSelected = false; + onlyFactorySelected = false; + for(int i = 0; i < selectedUnits.length;i++){ + if(selectedUnits[i] != null&& selectedUnits[i].teamNo == 0){ + if(selectedUnits[i].type > 100 && selectedUnits[i].type != 103){ + buildingSelected = true; + }else{ + buildingSelected = false; + } + } + } + + + //give the player option to repair, if only building(s) are selected + if(buildingSelected){ + + if(cursorInBlock8 && leftMouseButtonClicked){ + for(int i = 0; i < selectedUnits.length;i++) + if(selectedUnits[i] != null&& selectedUnits[i].teamNo == 0) + if(selectedUnits[i].type > 100 && selectedUnits[i].type != 103) + selectedUnits[i].isRepairing = true; + } + + if(cursorInBlock8 && rightMouseButtonClicked){ + for(int i = 0; i < selectedUnits.length;i++) + if(selectedUnits[i] != null&& selectedUnits[i].teamNo == 0) + if(selectedUnits[i].type > 100 && selectedUnits[i].type != 103) + selectedUnits[i].isRepairing = false; + } + + + int displayInfo = 0; + if(cursorInBlock8){ + displayInfo = 13; + } + + boolean showAutoRepairMark = true; + for(int i = 0; i < selectedUnits.length;i++) + if(selectedUnits[i] != null&& selectedUnits[i].teamNo == 0) + if(selectedUnits[i].type > 100 && selectedUnits[i].type != 103 && selectedUnits[i].isRepairing == false) + showAutoRepairMark = false; + + + + if(showAutoRepairMark) + sideBarInfo[8] = displayInfo << 24 | 14 << 16 | 255 << 8 | 32; + else + sideBarInfo[8] = displayInfo << 24 | 14 << 16 | 255 << 8 | 16; + } + + + if(selectedObject != null){ + //handle construction Vehicle side bar interaction + if(selectedObject.type == 3){ + boolean constructionVehicleCanBeDeployed = false; + + for(int i = 0; i < selectedUnits.length;i++){ + if(selectedUnits[i] != null){ + + constructionVehicle cv = (constructionVehicle)selectedUnits[i]; + if(cv.canBeDeployed()){ + + constructionVehicleCanBeDeployed = true; + if(cursorInBlock0 && leftMouseButtonClicked){ + + cv.expand(); + + } + } + } + } + + int displayInfo = 0; + if(cursorInBlock0){ + displayInfo = 2; + } + + + if(constructionVehicleCanBeDeployed){ + // display info texture progress text + sideBarInfo[0] = displayInfo << 24 | 0 << 16 | 240 << 8 | 0; + }else{ + sideBarInfo[0] = displayInfo << 24 | 0 << 16 | 0 << 8 | 0; + } + } + + + //handle factory side bar interaction + if(selectedObject.type == 105){ + onlyFactorySelected = true; + + factoryRallyOnSameGoldMine = true; + boolean firstFactory = true; + goldMine o = null; + for(int i = 0; i < selectedUnits.length;i++){ + if(selectedUnits[i] != null){ + factory f = (factory)(selectedUnits[i]); + if(firstFactory){ + o = f.targetGoldMine; + firstFactory = false; + }else{ + if(o != f.targetGoldMine) + factoryRallyOnSameGoldMine = false; + break; + } + } + } + + //can interact with one than 1 factory at a time + if(mainThread.pc.numberOfSelectedUnits != 0){ + factory f = null; + for(int i = 0; i < selectedUnits.length;i++){ + if(selectedUnits[i] != null){ + f = (factory)selectedUnits[i]; + + //handle light tank building progress and display info + if(f.canBuildLightTank){ + + //start building + if(cursorInBlock0 && leftMouseButtonClicked){ + f.buildLightTank(); + } + + //cancel buidling + if(cursorInBlock0 && rightMouseButtonClicked){ + + f.cancelItemFromProductionQueue(f.lightTankType); + } + + + + //display info + int displayInfo = 0; + if(cursorInBlock0){ + displayInfo = 5; + } + + sideBarInfo[0] = displayInfo << 24 | 6 << 16 | f.lightTankProgress << 8 | (f.numOfLightTankOnQueue + 100); + + } + + //handle rocket tank building progress and display info + if(f.canBuildRocketTank){ + //start building + if(cursorInBlock1 && leftMouseButtonClicked){ + f.buildRocketTank(); + } + + //cancel buidling + if(cursorInBlock1 && rightMouseButtonClicked){ + + f.cancelItemFromProductionQueue(f.rocketTankType); + } + + //display info + int displayInfo = 0; + if(cursorInBlock1){ + displayInfo = 6; + } + + sideBarInfo[1] = displayInfo << 24 | 7 << 16 | f.rocketTankProgress << 8 | (f.numOfRocketTankOnQueue + 100); + + } + + //handle harvester building progress and display info + if(f.canBuildHarvester){ + //start building + if(cursorInBlock2 && leftMouseButtonClicked){ + f.buildHarvester(); + } + + //cancel buidling + if(cursorInBlock2 && rightMouseButtonClicked){ + f.cancelItemFromProductionQueue(f.harvesterType); + } + + //display info + int displayInfo = 0; + if(cursorInBlock2){ + displayInfo = 7; + } + + sideBarInfo[2] = displayInfo << 24 | 8 << 16 | f.harvesterProgress << 8 | (f.numOfHarvesterOnQueue + 100); + } + + //handle drone building progress and display info + if(f.canBuildDrone){ + //start building + if(cursorInBlock3 && leftMouseButtonClicked){ + f.buildDrone(); + } + + //cancel buidling + if(cursorInBlock3 && rightMouseButtonClicked){ + f.cancelItemFromProductionQueue(f.droneType); + } + + //display info + int displayInfo = 0; + if(cursorInBlock3){ + displayInfo = 8; + } + + if(f.numOfDrones == 3){ + sideBarInfo[3] = displayInfo << 24 | 9 << 16 | 0 << 8 | (f.numOfDroneOnQueue + 100); + }else{ + sideBarInfo[3] = displayInfo << 24 | 9 << 16 | f.droneProgress << 8 | (f.numOfDroneOnQueue + 100); + } + } + + //handle MCV building progress and display info + if(f.canBuildMCV){ + + //start building + if(cursorInBlock5 && leftMouseButtonClicked){ + f.buildMCV(); + } + + //cancel buidling + if(cursorInBlock5 && rightMouseButtonClicked){ + f.cancelItemFromProductionQueue(f.MCVType); + } + + + //display info + int displayInfo = 0; + if(cursorInBlock5){ + displayInfo = 10; + } + + sideBarInfo[5] = displayInfo << 24 | 11 << 16 | f.MCVProgress << 8 | (f.numOfMCVOnQueue + 100); + + } + + //handle stealth building progress and display info + if(f.canBuildStealthTank){ + //start building + if(cursorInBlock4 && leftMouseButtonClicked){ + f.buildStealthTank(); + } + + //cancel buidling + if(cursorInBlock4 && rightMouseButtonClicked){ + f.cancelItemFromProductionQueue(f.stealthTankType); + } + + //display info + int displayInfo = 0; + if(cursorInBlock4){ + displayInfo = 11; + } + + sideBarInfo[4] = displayInfo << 24 | 12 << 16 | f.stealthTankProgress << 8 | (f.numOfStealthTankOnQueue + 100); + } + + //handle heavy tank building progress and display info + if(f.canBuildHeavyTank){ + //start building + if(cursorInBlock6 && leftMouseButtonClicked){ + + f.buildHeavyTank(); + } + + //cancel buidling + if(cursorInBlock6 && rightMouseButtonClicked){ + f.cancelItemFromProductionQueue(f.heavyTankType); + } + + //display info + int displayInfo = 0; + if(cursorInBlock6){ + displayInfo = 19; + } + + sideBarInfo[6] = displayInfo << 24 | 19 << 16 | f.heavyTankProgress << 8 | (f.numOfHeavyTankOnQueue + 100); + + } + + } + } + } + } + + + //handle missile turret side bar interaction + if(selectedObject.type == 199){ + if(communicationCenter.rapidfireResearched_player){ + + if(cursorInBlock5 && leftMouseButtonClicked){ + for(int i = 0; i < selectedUnits.length;i++) + if(selectedUnits[i] != null&& selectedUnits[i].teamNo == 0) + if(selectedUnits[i].type == 199){ + missileTurret o = (missileTurret)selectedUnits[i]; + if(o.overCharge == false){ + o.overCharge = true; + mainThread.pc.theBaseInfo.numberOfOverChargedMissileTurret++; + } + } + } + + if(cursorInBlock5 && rightMouseButtonClicked){ + for(int i = 0; i < selectedUnits.length;i++) + if(selectedUnits[i] != null&& selectedUnits[i].teamNo == 0) + if(selectedUnits[i].type == 199){ + missileTurret o = (missileTurret)selectedUnits[i]; + if(o.overCharge == true){ + o.overCharge = false; + mainThread.pc.theBaseInfo.numberOfOverChargedMissileTurret--; + } + } + } + + + //display info + int displayInfo = 0; + if(cursorInBlock5){ + displayInfo = 17; + } + + boolean showRapidfireMark = true; + for(int i = 0; i < selectedUnits.length;i++){ + if(selectedUnits[i] != null&& selectedUnits[i].teamNo == 0){ + if(selectedUnits[i].type == 199){ + missileTurret o = (missileTurret)selectedUnits[i]; + if(!o.overCharge) + showRapidfireMark = false; + } + } + } + + if(showRapidfireMark) + sideBarInfo[5] = displayInfo << 24 | 17 << 16 | 255 << 8 | 32; + else + sideBarInfo[5] = displayInfo << 24 | 17 << 16 | 255 << 8 | 16; + } + } + + //handle communication center side bar interaction + if(selectedObject.type == 106){ + + //handle harvester speed research + if(!communicationCenter.harvesterSpeedResearched_player){ + //start researching + if(cursorInBlock0 && leftMouseButtonClicked && communicationCenter.harvesterSpeedResearchProgress_player == 255){ + communicationCenter.researchHarvesterSpeed(0); + } + + //cancel researching + if(cursorInBlock0 && rightMouseButtonClicked && communicationCenter.harvesterSpeedResearchProgress_player != 255 && communicationCenter.harvesterSpeedResearchProgress_player != 254){ + communicationCenter.cancelResearch(0); + + } + + //display info + int displayInfo = 0; + if(cursorInBlock0){ + displayInfo = 15; + } + + sideBarInfo[0] = displayInfo << 24 | 16 << 16 | communicationCenter.harvesterSpeedResearchProgress_player << 8 | 0; + } + + //handle rapid fire research + if(!communicationCenter.rapidfireResearched_player){ + //start researching + if(cursorInBlock1 && leftMouseButtonClicked && communicationCenter.rapidfireResearchProgress_player == 255){ + communicationCenter.researchRapidfire(0); + } + + //cancel researching + if(cursorInBlock1 && rightMouseButtonClicked && communicationCenter.rapidfireResearchProgress_player != 255 && communicationCenter.rapidfireResearchProgress_player != 254){ + communicationCenter.cancelResearch(0); + + } + + //display info + int displayInfo = 0; + if(cursorInBlock1){ + displayInfo = 16; + } + + sideBarInfo[1] = displayInfo << 24 | 17 << 16 | communicationCenter.rapidfireResearchProgress_player << 8 | 0; + } + + } + + //handle tech center side bar interaction + if(selectedObject.type == 107){ + + //handle light tank range research + if(!techCenter.lightTankResearched_player){ + if(cursorInBlock0 && leftMouseButtonClicked && techCenter.lightTankResearchProgress_player == 255){ + techCenter.researchLightTank(0); + } + + //cancel researching + if(cursorInBlock0 && rightMouseButtonClicked && techCenter.lightTankResearchProgress_player != 255 && techCenter.lightTankResearchProgress_player != 254){ + techCenter.cancelResearch(0); + } + + //display info + int displayInfo = 0; + if(cursorInBlock0){ + displayInfo = 20; + } + sideBarInfo[0] = displayInfo << 24 | 20 << 16 | techCenter.lightTankResearchProgress_player << 8 | 0; + } + + //handle rocket tank damage research + if(!techCenter.rocketTankResearched_player){ + if(cursorInBlock1 && leftMouseButtonClicked && techCenter.rocketTankResearchProgress_player == 255){ + + techCenter.researchRocketTank(0); + } + + //cancel researching + if(cursorInBlock1 && rightMouseButtonClicked && techCenter.rocketTankResearchProgress_player != 255 && techCenter.rocketTankResearchProgress_player != 254){ + techCenter.cancelResearch(0); + } + + //display info + int displayInfo = 0; + if(cursorInBlock1){ + displayInfo = 21; + } + + sideBarInfo[1] = displayInfo << 24 | 21 << 16 | techCenter.rocketTankResearchProgress_player << 8 | 0; + } + + //handle stealth multishot research + if(!techCenter.stealthTankResearched_player){ + if(cursorInBlock2 && leftMouseButtonClicked && techCenter.stealthTankResearchProgress_player == 255){ + + techCenter.researchStealthTank(0); + } + + //cancel researching + if(cursorInBlock2 && rightMouseButtonClicked && techCenter.stealthTankResearchProgress_player != 255 && techCenter.stealthTankResearchProgress_player != 254){ + techCenter.cancelResearch(0); + } + + //display info + int displayInfo = 0; + if(cursorInBlock2){ + displayInfo = 22; + } + + sideBarInfo[2] = displayInfo << 24 | 22 << 16 | techCenter.stealthTankResearchProgress_player << 8 | 0; + } + + //handle heavy tank self repair research + if(!techCenter.heavyTankResearched_player){ + if(cursorInBlock3 && leftMouseButtonClicked && techCenter.heavyTankResearchProgress_player == 255){ + + techCenter.researchHeavyTank(0); + } + + //cancel researching + if(cursorInBlock3 && rightMouseButtonClicked && techCenter.heavyTankResearchProgress_player != 255 && techCenter.heavyTankResearchProgress_player != 254){ + techCenter.cancelResearch(0); + } + + //display info + int displayInfo = 0; + if(cursorInBlock3){ + displayInfo = 23; + } + + sideBarInfo[3] = displayInfo << 24 | 23 << 16 | techCenter.heavyTankResearchProgress_player << 8 | 0; + } + + } + + + //handle construction yard side bar interaction + if(selectedObject.type == 104){ + + //can only interact with one construction yard at a time + if(mainThread.pc.numberOfSelectedUnits == 1){ + + constructionYard cy = null; + for(int i = 0; i < selectedUnits.length;i++){ + if(selectedUnits[i] != null){ + cy = (constructionYard)selectedUnits[i]; + break; + } + } + + //handle power plant building progress and display info + if(cy.canBuildPowerPlant){ + //start building + if(cursorInBlock0 && leftMouseButtonClicked && cy.powerPlantProgress == 255 && !mainThread.pc.isDeployingBuilding){ + cy.buildPowerPlant(); + } + + if(cursorInBlock0 && leftMouseButtonClicked && cy.powerPlantProgress == 240){ + cy.needToDrawDeploymentGrid = true; + mainThread.pc.isDeployingBuilding = true; + mainThread.pc.selectedConstructionYard = cy; + } + + //cancel buidling + if(cursorInBlock0 && rightMouseButtonClicked && cy.powerPlantProgress != 255 && cy.powerPlantProgress != 254){ + mainThread.pc.isDeployingBuilding = false; + mainThread.pc.selectedConstructionYard = null; + cy.needToDrawDeploymentGrid = false; + cy.cancelBuilding(); + } + + //display info + int displayInfo = 0; + if(cursorInBlock0){ + displayInfo = 1; + } + + sideBarInfo[0] = displayInfo << 24 | 1 << 16 | cy.powerPlantProgress << 8 | (cy.powerPlantProgress/240 + cy.powerPlantProgress/240 * cy.powerPlantProgress%240); + + + } + + //handle refinery building progress and display info + if(cy.canBuildRefinery){ + //start building + if(cursorInBlock1 && leftMouseButtonClicked && cy.refineryProgress == 255 && !mainThread.pc.isDeployingBuilding){ + cy.buildRefinery(); + } + + if(cursorInBlock1 && leftMouseButtonClicked && cy.refineryProgress == 240){ + cy.needToDrawDeploymentGrid = true; + mainThread.pc.isDeployingBuilding = true; + mainThread.pc.selectedConstructionYard = cy; + } + + //cancel buidling + if(cursorInBlock1 && rightMouseButtonClicked && cy.refineryProgress != 255 && cy.refineryProgress != 254){ + mainThread.pc.isDeployingBuilding = false; + mainThread.pc.selectedConstructionYard = null; + cy.needToDrawDeploymentGrid = false; + cy.cancelBuilding(); + } + + //display info + int displayInfo = 0; + if(cursorInBlock1){ + displayInfo = 3; + } + + sideBarInfo[1] = displayInfo << 24 | 2 << 16 | cy.refineryProgress << 8 | (cy.refineryProgress/240 + cy.refineryProgress/240 * cy.refineryProgress%240); + } + + //handle factory building progress and display info + if(cy.canBuildFactory){ + //start building + if(cursorInBlock2 && leftMouseButtonClicked && cy.factoryProgress == 255 && !mainThread.pc.isDeployingBuilding){ + cy.buildFactory(); + } + + if(cursorInBlock2 && leftMouseButtonClicked && cy.factoryProgress == 240){ + cy.needToDrawDeploymentGrid = true; + mainThread.pc.isDeployingBuilding = true; + mainThread.pc.selectedConstructionYard = cy; + } + + //cancel buidling + if(cursorInBlock2 && rightMouseButtonClicked && cy.factoryProgress != 255 && cy.factoryProgress != 254){ + mainThread.pc.isDeployingBuilding = false; + mainThread.pc.selectedConstructionYard = null; + cy.needToDrawDeploymentGrid = false; + cy.cancelBuilding(); + } + + //display info + int displayInfo = 0; + if(cursorInBlock2){ + displayInfo = 4; + } + + sideBarInfo[2] = displayInfo << 24 | 5 << 16 | cy.factoryProgress << 8 | (cy.factoryProgress/240 + cy.factoryProgress/240 * cy.factoryProgress%240); + + } + + //handle communication center building progress and display info + if(cy.canBuildCommunicationCenter){ + //start building + if(cursorInBlock3 && leftMouseButtonClicked && cy.communicationCenterProgress == 255 && !mainThread.pc.isDeployingBuilding){ + cy.buildCommunicationCentre(); + } + + if(cursorInBlock3 && leftMouseButtonClicked && cy.communicationCenterProgress == 240){ + cy.needToDrawDeploymentGrid = true; + mainThread.pc.isDeployingBuilding = true; + mainThread.pc.selectedConstructionYard = cy; + } + + //cancel buidling + if(cursorInBlock3 && rightMouseButtonClicked && cy.communicationCenterProgress != 255 && cy.communicationCenterProgress != 254){ + mainThread.pc.isDeployingBuilding = false; + mainThread.pc.selectedConstructionYard = null; + cy.needToDrawDeploymentGrid = false; + cy.cancelBuilding(); + } + + + //display info + int displayInfo = 0; + if(cursorInBlock3){ + displayInfo = 9; + } + + sideBarInfo[3] = displayInfo << 24 | 10 << 16 | cy.communicationCenterProgress << 8 | (cy.communicationCenterProgress/240 + cy.communicationCenterProgress/240 * cy.communicationCenterProgress%240); + } + + //handle turret building process and display info + if(cy.canBuildGunTurret){ + //start building + if(cursorInBlock4 && leftMouseButtonClicked && cy.gunTurretProgress == 255 && !mainThread.pc.isDeployingBuilding){ + cy.buildGunTurret(); + + } + + if(cursorInBlock4 && leftMouseButtonClicked && cy.gunTurretProgress == 240){ + cy.needToDrawDeploymentGrid = true; + mainThread.pc.isDeployingBuilding = true; + mainThread.pc.selectedConstructionYard = cy; + } + + //cancel buidling + if(cursorInBlock4 && rightMouseButtonClicked && cy.gunTurretProgress != 255 && cy.gunTurretProgress != 254){ + mainThread.pc.isDeployingBuilding = false; + mainThread.pc.selectedConstructionYard = null; + cy.needToDrawDeploymentGrid = false; + cy.cancelBuilding(); + } + + //display info + int displayInfo = 0; + if(cursorInBlock4){ + displayInfo = 12; + } + + sideBarInfo[4] = displayInfo << 24 | 13 << 16 | cy.gunTurretProgress << 8 | (cy.gunTurretProgress/240 + cy.gunTurretProgress/240 * cy.gunTurretProgress%240); + } + + //handle missile turret building process and display info + if(cy.canBuildMissileTurret){ + //start building + if(cursorInBlock5 && leftMouseButtonClicked && cy.missileTurretProgress == 255 && !mainThread.pc.isDeployingBuilding){ + cy.buildMissileTurret(); + + } + + if(cursorInBlock5 && leftMouseButtonClicked && cy.missileTurretProgress == 240){ + cy.needToDrawDeploymentGrid = true; + mainThread.pc.isDeployingBuilding = true; + mainThread.pc.selectedConstructionYard = cy; + } + + //cancel buidling + if(cursorInBlock5 && rightMouseButtonClicked && cy.missileTurretProgress != 255 && cy.missileTurretProgress != 254){ + mainThread.pc.isDeployingBuilding = false; + mainThread.pc.selectedConstructionYard = null; + cy.needToDrawDeploymentGrid = false; + cy.cancelBuilding(); + } + + //display info + int displayInfo = 0; + if(cursorInBlock5){ + displayInfo = 14; + } + + sideBarInfo[5] = displayInfo << 24 | 15 << 16 | cy.missileTurretProgress << 8 | (cy.missileTurretProgress/240 + cy.missileTurretProgress/240 * cy.missileTurretProgress%240); + } + + //handle tech center building process and display info + if(cy.canBuildTechCenter){ + //start building + if(cursorInBlock6 && leftMouseButtonClicked && cy.techCenterProgress == 255 && !mainThread.pc.isDeployingBuilding){ + cy.buildTechCenter(); + + } + + if(cursorInBlock6 && leftMouseButtonClicked && cy.techCenterProgress == 240){ + cy.needToDrawDeploymentGrid = true; + mainThread.pc.isDeployingBuilding = true; + mainThread.pc.selectedConstructionYard = cy; + } + + //cancel buidling + if(cursorInBlock6 && rightMouseButtonClicked && cy.techCenterProgress != 255 && cy.techCenterProgress != 254){ + mainThread.pc.isDeployingBuilding = false; + mainThread.pc.selectedConstructionYard = null; + cy.needToDrawDeploymentGrid = false; + cy.cancelBuilding(); + } + + //display info + int displayInfo = 0; + if(cursorInBlock6){ + displayInfo = 18; + } + + sideBarInfo[6] = displayInfo << 24 | 18 << 16 | cy.techCenterProgress << 8 | (cy.techCenterProgress/240 + cy.techCenterProgress/240 * cy.techCenterProgress%240); + } + + + } + } + } + + + + rightMouseButtonClicked = false; + leftMouseButtonClicked = false; + + cursorInBlock0 = false; + cursorInBlock1 = false; + cursorInBlock2 = false; + cursorInBlock3 = false; + cursorInBlock4 = false; + cursorInBlock5 = false; + cursorInBlock6 = false; + cursorInBlock7 = false; + cursorInBlock8 = false; + + } + + public void swapResources(){ + int[] info; + info = sideBarInfo; + sideBarInfo = sideBarInfo2; + sideBarInfo2 = info; + } + +} diff --git a/images/1.jpg b/images/1.jpg new file mode 100644 index 0000000..0c002bd Binary files /dev/null and b/images/1.jpg differ diff --git a/images/10.jpg b/images/10.jpg new file mode 100644 index 0000000..18c9e9d Binary files /dev/null and b/images/10.jpg differ diff --git a/images/11.jpg b/images/11.jpg new file mode 100644 index 0000000..4d1286f Binary files /dev/null and b/images/11.jpg differ diff --git a/images/12.jpg b/images/12.jpg new file mode 100644 index 0000000..6a95923 Binary files /dev/null and b/images/12.jpg differ diff --git a/images/13.jpg b/images/13.jpg new file mode 100644 index 0000000..7f4b257 Binary files /dev/null and b/images/13.jpg differ diff --git a/images/14.jpg b/images/14.jpg new file mode 100644 index 0000000..c5f2aa1 Binary files /dev/null and b/images/14.jpg differ diff --git a/images/15.jpg b/images/15.jpg new file mode 100644 index 0000000..dc9176c Binary files /dev/null and b/images/15.jpg differ diff --git a/images/16.jpg b/images/16.jpg new file mode 100644 index 0000000..57eadf0 Binary files /dev/null and b/images/16.jpg differ diff --git a/images/17.jpg b/images/17.jpg new file mode 100644 index 0000000..ec9687c Binary files /dev/null and b/images/17.jpg differ diff --git a/images/18.jpg b/images/18.jpg new file mode 100644 index 0000000..05292aa Binary files /dev/null and b/images/18.jpg differ diff --git a/images/19.jpg b/images/19.jpg new file mode 100644 index 0000000..fe845dc Binary files /dev/null and b/images/19.jpg differ diff --git a/images/2.jpg b/images/2.jpg new file mode 100644 index 0000000..a53215c Binary files /dev/null and b/images/2.jpg differ diff --git a/images/20.jpg b/images/20.jpg new file mode 100644 index 0000000..a805ad7 Binary files /dev/null and b/images/20.jpg differ diff --git a/images/21.jpg b/images/21.jpg new file mode 100644 index 0000000..a2b9eea Binary files /dev/null and b/images/21.jpg differ diff --git a/images/22.jpg b/images/22.jpg new file mode 100644 index 0000000..d77d123 Binary files /dev/null and b/images/22.jpg differ diff --git a/images/23.jpg b/images/23.jpg new file mode 100644 index 0000000..04edc53 Binary files /dev/null and b/images/23.jpg differ diff --git a/images/24.jpg b/images/24.jpg new file mode 100644 index 0000000..af4fbde Binary files /dev/null and b/images/24.jpg differ diff --git a/images/25.jpg b/images/25.jpg new file mode 100644 index 0000000..a83db3f Binary files /dev/null and b/images/25.jpg differ diff --git a/images/26.jpg b/images/26.jpg new file mode 100644 index 0000000..8418ac8 Binary files /dev/null and b/images/26.jpg differ diff --git a/images/27.jpg b/images/27.jpg new file mode 100644 index 0000000..568b7d2 Binary files /dev/null and b/images/27.jpg differ diff --git a/images/28.jpg b/images/28.jpg new file mode 100644 index 0000000..99b4937 Binary files /dev/null and b/images/28.jpg differ diff --git a/images/29.jpg b/images/29.jpg new file mode 100644 index 0000000..746a03c Binary files /dev/null and b/images/29.jpg differ diff --git a/images/3.jpg b/images/3.jpg new file mode 100644 index 0000000..ca00359 Binary files /dev/null and b/images/3.jpg differ diff --git a/images/30.jpg b/images/30.jpg new file mode 100644 index 0000000..cc3d0d0 Binary files /dev/null and b/images/30.jpg differ diff --git a/images/31.jpg b/images/31.jpg new file mode 100644 index 0000000..a72ab07 Binary files /dev/null and b/images/31.jpg differ diff --git a/images/32.jpg b/images/32.jpg new file mode 100644 index 0000000..4139ba0 Binary files /dev/null and b/images/32.jpg differ diff --git a/images/33.jpg b/images/33.jpg new file mode 100644 index 0000000..557d886 Binary files /dev/null and b/images/33.jpg differ diff --git a/images/34.jpg b/images/34.jpg new file mode 100644 index 0000000..aef85cd Binary files /dev/null and b/images/34.jpg differ diff --git a/images/35.jpg b/images/35.jpg new file mode 100644 index 0000000..2ff1042 Binary files /dev/null and b/images/35.jpg differ diff --git a/images/36.jpg b/images/36.jpg new file mode 100644 index 0000000..8496d00 Binary files /dev/null and b/images/36.jpg differ diff --git a/images/37.jpg b/images/37.jpg new file mode 100644 index 0000000..2daedc7 Binary files /dev/null and b/images/37.jpg differ diff --git a/images/38.jpg b/images/38.jpg new file mode 100644 index 0000000..7775323 Binary files /dev/null and b/images/38.jpg differ diff --git a/images/39.jpg b/images/39.jpg new file mode 100644 index 0000000..7e1af91 Binary files /dev/null and b/images/39.jpg differ diff --git a/images/4.jpg b/images/4.jpg new file mode 100644 index 0000000..9ef39eb Binary files /dev/null and b/images/4.jpg differ diff --git a/images/40.jpg b/images/40.jpg new file mode 100644 index 0000000..bebc92a Binary files /dev/null and b/images/40.jpg differ diff --git a/images/41.jpg b/images/41.jpg new file mode 100644 index 0000000..9087f29 Binary files /dev/null and b/images/41.jpg differ diff --git a/images/42.jpg b/images/42.jpg new file mode 100644 index 0000000..4a500e7 Binary files /dev/null and b/images/42.jpg differ diff --git a/images/43.jpg b/images/43.jpg new file mode 100644 index 0000000..1444437 Binary files /dev/null and b/images/43.jpg differ diff --git a/images/44.jpg b/images/44.jpg new file mode 100644 index 0000000..2ffabca Binary files /dev/null and b/images/44.jpg differ diff --git a/images/45.jpg b/images/45.jpg new file mode 100644 index 0000000..5995de6 Binary files /dev/null and b/images/45.jpg differ diff --git a/images/46.jpg b/images/46.jpg new file mode 100644 index 0000000..ff0550b Binary files /dev/null and b/images/46.jpg differ diff --git a/images/47.jpg b/images/47.jpg new file mode 100644 index 0000000..ea2ee1f Binary files /dev/null and b/images/47.jpg differ diff --git a/images/48.jpg b/images/48.jpg new file mode 100644 index 0000000..4127fa5 Binary files /dev/null and b/images/48.jpg differ diff --git a/images/49.jpg b/images/49.jpg new file mode 100644 index 0000000..797e01e Binary files /dev/null and b/images/49.jpg differ diff --git a/images/5.jpg b/images/5.jpg new file mode 100644 index 0000000..5318212 Binary files /dev/null and b/images/5.jpg differ diff --git a/images/50.jpg b/images/50.jpg new file mode 100644 index 0000000..b5040ee Binary files /dev/null and b/images/50.jpg differ diff --git a/images/51.jpg b/images/51.jpg new file mode 100644 index 0000000..ac6318a Binary files /dev/null and b/images/51.jpg differ diff --git a/images/52.jpg b/images/52.jpg new file mode 100644 index 0000000..f836ab7 Binary files /dev/null and b/images/52.jpg differ diff --git a/images/53.jpg b/images/53.jpg new file mode 100644 index 0000000..c3607f6 Binary files /dev/null and b/images/53.jpg differ diff --git a/images/54.jpg b/images/54.jpg new file mode 100644 index 0000000..3192dd4 Binary files /dev/null and b/images/54.jpg differ diff --git a/images/55.jpg b/images/55.jpg new file mode 100644 index 0000000..c9dc6be Binary files /dev/null and b/images/55.jpg differ diff --git a/images/56.jpg b/images/56.jpg new file mode 100644 index 0000000..1890344 Binary files /dev/null and b/images/56.jpg differ diff --git a/images/57.jpg b/images/57.jpg new file mode 100644 index 0000000..c1deee6 Binary files /dev/null and b/images/57.jpg differ diff --git a/images/58.jpg b/images/58.jpg new file mode 100644 index 0000000..7fb6c67 Binary files /dev/null and b/images/58.jpg differ diff --git a/images/59.jpg b/images/59.jpg new file mode 100644 index 0000000..95594fd Binary files /dev/null and b/images/59.jpg differ diff --git a/images/6.jpg b/images/6.jpg new file mode 100644 index 0000000..1b46325 Binary files /dev/null and b/images/6.jpg differ diff --git a/images/60.jpg b/images/60.jpg new file mode 100644 index 0000000..7ae4643 Binary files /dev/null and b/images/60.jpg differ diff --git a/images/61.jpg b/images/61.jpg new file mode 100644 index 0000000..fb234cf Binary files /dev/null and b/images/61.jpg differ diff --git a/images/62.jpg b/images/62.jpg new file mode 100644 index 0000000..376a172 Binary files /dev/null and b/images/62.jpg differ diff --git a/images/63.jpg b/images/63.jpg new file mode 100644 index 0000000..daa1db7 Binary files /dev/null and b/images/63.jpg differ diff --git a/images/64.jpg b/images/64.jpg new file mode 100644 index 0000000..8364e5a Binary files /dev/null and b/images/64.jpg differ diff --git a/images/65.jpg b/images/65.jpg new file mode 100644 index 0000000..b9538ee Binary files /dev/null and b/images/65.jpg differ diff --git a/images/66.jpg b/images/66.jpg new file mode 100644 index 0000000..470f8f3 Binary files /dev/null and b/images/66.jpg differ diff --git a/images/67.jpg b/images/67.jpg new file mode 100644 index 0000000..73ddcf1 Binary files /dev/null and b/images/67.jpg differ diff --git a/images/68.jpg b/images/68.jpg new file mode 100644 index 0000000..273b55a Binary files /dev/null and b/images/68.jpg differ diff --git a/images/69.jpg b/images/69.jpg new file mode 100644 index 0000000..cb4ea98 Binary files /dev/null and b/images/69.jpg differ diff --git a/images/7.jpg b/images/7.jpg new file mode 100644 index 0000000..27661fe Binary files /dev/null and b/images/7.jpg differ diff --git a/images/70.jpg b/images/70.jpg new file mode 100644 index 0000000..03f28e3 Binary files /dev/null and b/images/70.jpg differ diff --git a/images/71.jpg b/images/71.jpg new file mode 100644 index 0000000..af874ea Binary files /dev/null and b/images/71.jpg differ diff --git a/images/72.jpg b/images/72.jpg new file mode 100644 index 0000000..8a55ec3 Binary files /dev/null and b/images/72.jpg differ diff --git a/images/73.jpg b/images/73.jpg new file mode 100644 index 0000000..e1d2eb0 Binary files /dev/null and b/images/73.jpg differ diff --git a/images/74.jpg b/images/74.jpg new file mode 100644 index 0000000..1ae2bf5 Binary files /dev/null and b/images/74.jpg differ diff --git a/images/75.jpg b/images/75.jpg new file mode 100644 index 0000000..7c9ec54 Binary files /dev/null and b/images/75.jpg differ diff --git a/images/76.jpg b/images/76.jpg new file mode 100644 index 0000000..ed809be Binary files /dev/null and b/images/76.jpg differ diff --git a/images/77.jpg b/images/77.jpg new file mode 100644 index 0000000..4a9e519 Binary files /dev/null and b/images/77.jpg differ diff --git a/images/78.jpg b/images/78.jpg new file mode 100644 index 0000000..3567ca5 Binary files /dev/null and b/images/78.jpg differ diff --git a/images/79.jpg b/images/79.jpg new file mode 100644 index 0000000..cf79e79 Binary files /dev/null and b/images/79.jpg differ diff --git a/images/8.jpg b/images/8.jpg new file mode 100644 index 0000000..0eb5994 Binary files /dev/null and b/images/8.jpg differ diff --git a/images/80.jpg b/images/80.jpg new file mode 100644 index 0000000..5ffa5f1 Binary files /dev/null and b/images/80.jpg differ diff --git a/images/81.jpg b/images/81.jpg new file mode 100644 index 0000000..67af9cc Binary files /dev/null and b/images/81.jpg differ diff --git a/images/82.jpg b/images/82.jpg new file mode 100644 index 0000000..704ca4c Binary files /dev/null and b/images/82.jpg differ diff --git a/images/83.jpg b/images/83.jpg new file mode 100644 index 0000000..79d07aa Binary files /dev/null and b/images/83.jpg differ diff --git a/images/84.jpg b/images/84.jpg new file mode 100644 index 0000000..47584dc Binary files /dev/null and b/images/84.jpg differ diff --git a/images/85.jpg b/images/85.jpg new file mode 100644 index 0000000..0d490c1 Binary files /dev/null and b/images/85.jpg differ diff --git a/images/86.jpg b/images/86.jpg new file mode 100644 index 0000000..f435a2f Binary files /dev/null and b/images/86.jpg differ diff --git a/images/87.jpg b/images/87.jpg new file mode 100644 index 0000000..ad72174 Binary files /dev/null and b/images/87.jpg differ diff --git a/images/88.jpg b/images/88.jpg new file mode 100644 index 0000000..8b151a3 Binary files /dev/null and b/images/88.jpg differ diff --git a/images/89.jpg b/images/89.jpg new file mode 100644 index 0000000..38c6c5b Binary files /dev/null and b/images/89.jpg differ diff --git a/images/9.jpg b/images/9.jpg new file mode 100644 index 0000000..a68b44c Binary files /dev/null and b/images/9.jpg differ diff --git a/images/90.jpg b/images/90.jpg new file mode 100644 index 0000000..612368d Binary files /dev/null and b/images/90.jpg differ diff --git a/images/font.jpg b/images/font.jpg new file mode 100644 index 0000000..5f402b4 Binary files /dev/null and b/images/font.jpg differ diff --git a/main.java b/main.java new file mode 100644 index 0000000..7e6fcf9 --- /dev/null +++ b/main.java @@ -0,0 +1,9 @@ +import core.mainThread; + +public class main { + + public static void main(String[] args){ + new mainThread(); + } + +} diff --git a/particles/.gitignore b/particles/.gitignore new file mode 100644 index 0000000..134002e --- /dev/null +++ b/particles/.gitignore @@ -0,0 +1,5 @@ +/bullet.class +/explosion.class +/helix.class +/rocket.class +/smokeParticle.class diff --git a/particles/bullet.java b/particles/bullet.java new file mode 100644 index 0000000..a7e5226 --- /dev/null +++ b/particles/bullet.java @@ -0,0 +1,199 @@ +package particles; + +import core.*; +import entity.solidObject; + +public class bullet { + + public vector centre; + + public solidObject target; + + public int damage; + + public int angle; + + public boolean isInAction; + + public vector iDirection, jDirection, kDirection; + + public vector movement; + + public float distanceToTarget; + + public float speed; + + public polygon3D[] polygons; + + public static vector[][] baseGeometry; + + public solidObject attacker; + + public static int[] tiles3x3 = new int[]{-129, -128, -127, -1, 0, 1, 127, 128, 129}; + + public bullet(){ + centre = new vector(0,0,0); + iDirection = new vector(1,0,0); + jDirection = new vector(0,1,0); + kDirection = new vector(0,0,1); + makePolygons(); + movement = new vector(1,0,0); + speed = 0.2f; + } + + public void setActive(int angle, int damage, solidObject target, vector centre, solidObject attacker){ + isInAction = true; + this.angle = 360 - angle; + this.damage = damage; + this.target = target; + this.centre.set(centre); + this.attacker = attacker; + + + iDirection.set(1,0,0); + iDirection.rotate_XZ(this.angle); + kDirection.set(0,0,1); + kDirection.rotate_XZ(this.angle); + + for(int i = 0; i < 5; i ++){ + for(int j = 0; j < 4; j ++){ + change(polygons[i].vertex3D[j], baseGeometry[i][j]); + } + } + + + movement.set(0,0,1); + movement.rotate_XZ(this.angle); + movement.scale(speed); + + distanceToTarget = (float)Math.sqrt((target.centre.x - centre.x) * (target.centre.x - centre.x) + (target.centre.z - centre.z) * (target.centre.z - centre.z)); + } + + + + public void makePolygons(){ + polygons = new polygon3D[5]; + vector[] v; + for(int i = 0; i < 5; i++){ + v = new vector[]{new vector(0, 0, 0), new vector(0, 0, 0), new vector(0, 0, 0), new vector(0, 0, 0)}; + polygons[i] = new polygon3D(v, v[0], v[1], v[3], null, 1f,1f,0); + polygons[i].color = 7 + (7 << 5) + (8 << 10); + polygons[i].diffuse_I = 127; + } + + if(baseGeometry == null){ + float l = 0.003f; + float h = 0.003f; + float w = 0.02f; + baseGeometry = new vector[5][]; + baseGeometry[0] = new vector[]{new vector(l, h, w), new vector(-l, h, w), new vector(-l, -h, w), new vector(l, -h, w)}; + baseGeometry[1] = new vector[]{new vector(l, h, -w), new vector(l, h, w), new vector(l, -h, w), new vector(l, -h, -w)}; + baseGeometry[2] = new vector[]{new vector(-l, h, -w), new vector(l, h, -w), new vector(l, -h, -w), new vector(-l, -h, -w)}; + baseGeometry[3] = new vector[]{new vector(-l, h, w), new vector(-l, h, -w), new vector(-l, -h, -w), new vector(-l, -h, w)}; + baseGeometry[4] = new vector[]{new vector(-l, h, w), new vector(l, h, w), new vector(l, h, -w), new vector(-l, h, -w)}; + } + + + + } + + public void updateAndDraw(){ + if(!isInAction) + return; + + + distanceToTarget -= speed; + if(distanceToTarget < 0){ + + isInAction = false; + movement.unit(); + movement.scale(speed + distanceToTarget); + target.currentHP -=damage; + target.underAttackCountDown = 120; + target.attacker = attacker; + + int xPos = (int)(target.centre.x*64); + int yPos = (int)(target.centre.z*64); + int start = xPos/16 + (127 - yPos/16)*128; + int targetTeamNo = target.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].teamNo!= attacker.teamNo && tile[j].attackStatus != solidObject.isAttacking && tile[j].currentCommand != solidObject.move && tile[j].isCloaked == false + && tile[j].currentCommand != solidObject.attackCautiously && tile[j].currentCommand != solidObject.attackInNumbers){ + if(tile[j].type < 100){ + tile[j].attack(attacker); + tile[j].currentCommand = solidObject.attackInNumbers; + } + } + + /*if(tile[j].teamNo == teamNo && tile[j].currentCommand == solidObject.StandBy && attacker.teamNo != teamNo && tile[j].isCloaked == false){ + if(tile[j].type < 100){ + tile[j].attack(attacker); + tile[j].currentCommand = solidObject.attackInNumbers; + } + }else if(tile[j].teamNo == teamNo && tile[j].secondaryCommand == solidObject.attackMove && attacker.teamNo != teamNo && tile[j].isCloaked == false){ + if(tile[j].attackStatus != solidObject.isAttacking || (tile[j].attackStatus == solidObject.isAttacking && tile[j].targetObject != null && tile[j].targetObject.type < 199 && tile[j].targetObject.type > 7)){ + tile[j].attack(attacker); + tile[j].currentCommand = solidObject.attackInNumbers; + } + }*/ + + } + } + } + + + } + + + centre.add(movement); + + for(int i = 0; i < 5; i ++){ + for(int j = 0; j < 4; j++){ + polygons[i].vertex3D[j].add(movement); + } + } + + for(int i = 0; i < 5; i ++){ + polygons[i].update(); + polygons[i].draw(); + } + + if(distanceToTarget < 0){ + //spawn an explosion at the end of the bullet life + float[] tempFloat = mainThread.theAssetManager.explosionInfo[mainThread.theAssetManager.explosionCount]; + tempFloat[0] = centre.x; + if(target.type > 100 && target.type < 200){ + tempFloat[1] = centre.y + 0.2f; + }else{ + tempFloat[1] = centre.y; + } + tempFloat[2] = centre.z; + tempFloat[3] = 1.5f; + + tempFloat[4] = 1; + tempFloat[5] = 0; + tempFloat[6] = 6 + (gameData.getRandom()%4); + tempFloat[7] = target.height; + mainThread.theAssetManager.explosionCount++; + } + + } + + + + + public void change(vector v, vector baseVector){ + v.set(centre); + v.add(iDirection, baseVector.x); + v.add(jDirection, baseVector.y); + v.add(kDirection, baseVector.z); + } +} diff --git a/particles/explosion.java b/particles/explosion.java new file mode 100644 index 0000000..70ebdd8 --- /dev/null +++ b/particles/explosion.java @@ -0,0 +1,257 @@ +package particles; + +import core.mainThread; +import core.postProcessingThread; +import core.vector; + +public class explosion { + //size of the explosion + public float size; + + //which explosion sprite to use + public int spriteIndex; + + //current frame Index; + public int frameIndex; + + //type of explosion + public int type; + + //life time + public int lifeTime; + public int animationSpeed; + + + //centre of explosion + public vector centre; + public vector tempCentre; + + public boolean isInAction; + + public float explosionHeight; + + public int auraIndex; + + public static int zTop = 4490089; + public static int zBot = 7127877; + public static int zDelta = (zBot - zTop)/511; + + public int xStart, yStart; + + + public explosion(){ + centre = new vector(0,0,0); + tempCentre = new vector(0,0,0); + } + + public void setActive(float x, float y, float z, float size, int animationSpeed, int type, int spriteIndex, float explosionHeight){ + isInAction = true; + + this.size = size; + this.animationSpeed = animationSpeed; + this.spriteIndex = spriteIndex; + frameIndex = 0; + auraIndex = 0; + if(size >= 2){ + lifeTime = 16 + 3; //cause a little bit delay + this.centre.set(x,y,z); + }else{ + lifeTime = 16; + if(size < 1) + this.centre.set(x,y,z); + else + this.centre.set(x+(float)Math.random()*0.1f -0.05f,y,z+(float)Math.random()*0.1f - 0.05f); + } + this.explosionHeight = (explosionHeight - centre.y) *300000; + xStart = 0; + yStart = 0; + + } + + public void updateAndDrawExplosionAura(){ + if(!isInAction || lifeTime > 16) + return; + + //update centre in camera coordinate + vector cameraPosition = postProcessingThread.cameraPosition; + float X = 0,Y = 0, Z = 0, + camX = cameraPosition.x, camY = cameraPosition.y, camZ = cameraPosition.z, + sinXZ = postProcessingThread.sinXZ, + cosXZ = postProcessingThread.cosXZ, + sinYZ = postProcessingThread.sinYZ, + cosYZ = postProcessingThread.cosYZ; + + + + + //draw explosion aura sprite if the explosion is big enough + if(size >= 1){ + X = centre.x - camX; + Y = -0.5f - camY; + Z = centre.z - camZ; + + //rotating + tempCentre.x = cosXZ*X - sinXZ*Z; + tempCentre.z = sinXZ*X + cosXZ*Z; + + Z = tempCentre.z; + + tempCentre.y = cosYZ*Y - sinYZ*Z; + tempCentre.z = sinYZ*Y + cosYZ*Z; + tempCentre.updateLocation(); + + + short[] sprite = mainThread.textures[1].explosionAura[frameIndex]; + float ratioX = size*4f/tempCentre.z; + float ratioY = size*3.6f/tempCentre.z; + int xPos = (int)tempCentre.screenX; + int yPos = (int)tempCentre.screenY; + int originalWidth = 128; + int width = 128 - frameIndex*10; + int height = 128 - frameIndex*10; + xStart +=5; + yStart +=5; + + int depth; + + int[] zbuffer = postProcessingThread.currentZbuffer; + byte[] smoothedShadowBitmap = postProcessingThread.smoothedShadowBitmap; + + //find the size ratio between a sprite pixel and screen pixel + float ratioInverseX = 1f/ratioX; + float ratioInverseY = 1f/ratioY; + + width = (int)(ratioX*width); + height = (int)(ratioY*height); + + + //only draw the part of the sprite that is inside the screen + //define boundary + int xTop = xPos - width/2; + int yTop = yPos - height/2; + int xBot = xPos + width/2; + int yBot = yPos + height/2; + + //draw sprite + int screenIndex = 0; + int SpriteValue = 0; + + for(int i = yTop, y = yStart; i < yBot; i++, y++){ + if(i < 0 || i >=512) + continue; + + depth = zTop + i*zDelta; + int ratioInverseY_Times_Y_Times_originalWidth = (int)(ratioInverseY*y)*originalWidth; + + for(int j = xTop, x = xStart; j < xBot; j++, x++){ + + + if(j < 0 || j >= 768) + continue; + screenIndex = j + i*768; + + + if(zbuffer[screenIndex] - depth > 30000) + continue; + + SpriteValue = sprite[((int)(ratioInverseX*x) + ratioInverseY_Times_Y_Times_originalWidth)& 0x3fff] ; + + if(SpriteValue > smoothedShadowBitmap[screenIndex]) + smoothedShadowBitmap[screenIndex] = (byte)SpriteValue; + + } + } + } + + X = centre.x - camX; + Y = centre.y - camY; + Z = centre.z - camZ; + + //rotating + tempCentre.x = cosXZ*X - sinXZ*Z; + tempCentre.z = sinXZ*X + cosXZ*Z; + + Z = tempCentre.z; + + tempCentre.y = cosYZ*Y - sinYZ*Z; + tempCentre.z = sinYZ*Y + cosYZ*Z; + tempCentre.updateLocation(); + + } + + + + //draw exlopsion sprite + public void drawExplosionSprite(){ + if(!isInAction) + return; + + + if(lifeTime <=16){ + int[] sprite = mainThread.textures[spriteIndex].explosions[frameIndex]; + float ratio = size*2/tempCentre.z; + int xPos = (int)tempCentre.screenX; + int yPos = (int)tempCentre.screenY; + int width = 64; + int height = 64; + int depth = (int)(0x1000000/tempCentre.z + explosionHeight); + + int[] screen = postProcessingThread.currentScreen; + int[] zbuffer = postProcessingThread.currentZbuffer; + int originalWidth = width; + + //find the size ratio between a sprite pixel and screen pixel + float ratioInverse = 1f/ratio; + + width = (int)(ratio*width); + height = (int)(ratio*height); + + //only draw the part of the sprite that is inside the screen + //define boundary + int xTop = xPos - width/2; + int yTop = yPos - height/2; + int xBot = xPos + width/2; + int yBot = yPos + height/2; + + //draw sprite + int screenIndex = 0; + int SpriteValue = 0; + int screenValue = 0; + int MASK7Bit = 0xFEFEFF; + int overflow = 0; + int pixel = 0; + + + for(int i = yTop, y = 0; i < yBot; i++, y++){ + if(i < 0 || i >=512) + continue; + int ratioInverseY = (int)(ratioInverse*y); + for(int j = xTop, x = 0; j < xBot; j++, x++){ + if(j < 0 || j >= 768) + continue; + screenIndex = j + i*768; + if(zbuffer[screenIndex] >= depth) + continue; + + SpriteValue = sprite[(int)(ratioInverse*x) + ratioInverseY*originalWidth]; + if(SpriteValue != 0) + screenValue = (screen[screenIndex]&0xFEFEFE)>>1; + else + continue; + + pixel=(SpriteValue&MASK7Bit)+(screenValue&MASK7Bit); + overflow=pixel&0x1010100; + overflow=overflow-(overflow>>8); + screen[screenIndex] = overflow|pixel; + + } + } + frameIndex+=animationSpeed; + } + + + lifeTime-=animationSpeed; + if(lifeTime <= 0) + isInAction = false; + } +} diff --git a/particles/helix.java b/particles/helix.java new file mode 100644 index 0000000..875c84e --- /dev/null +++ b/particles/helix.java @@ -0,0 +1,180 @@ +package particles; + +import core.camera; +import core.gameData; +import core.postProcessingThread; +import core.vector; + +//a partical system that resemble a section a railgun trail +public class helix { + //particles + public vector[] particles; + + //direction of particles + public vector[] directions; + + //color of particles + public int[] colors; + + public static int ALPHA=0xFF000000; + + public static vector temp1, temp2, iDirection, jDirection, kDirection; + + public vector centre; + + public boolean isInAction; + + public int lifeSpan; + + public helix(){ + if(temp1 == null){ + temp1 = new vector(0,0,0); + temp2 = new vector(0,0,0); + + iDirection = new vector(1,0,0); + iDirection = new vector(0,1,0); + kDirection = new vector(0,0,1); + } + + centre = new vector(0,0,0); + particles = new vector[20]; + directions = new vector[20]; + + for(int i = 0; i < 20; i ++){ + particles[i] = new vector(0,0,0); + directions[i] = new vector(0,0,0); + } + + colors = new int[20]; + } + + public void setActive(float x, float y, float z, int angle){ + + centre.set(x,y,z); + + angle+=360; + angle%=360; + angle=360 - angle; + + isInAction = true; + + lifeSpan = 40; + + int zAxisRotation = 0; + + temp1.set(centre); + temp2.set(kDirection); + temp2.rotate_XZ(angle); + temp2.scale(0.05f); + temp1.subtract(temp2); + temp2.scale(0.1f); + for(int i = 0; i < particles.length; i++){ + directions[i].set(iDirection); + directions[i].rotate_XY(zAxisRotation); + directions[i].rotate_XZ(angle); + directions[i].scale(0.01f); + particles[i].set(temp1); + particles[i].add(directions[i]); + directions[i].scale(0.06f); + colors[i] = ((int)(58 - 20*gameData.sin[zAxisRotation]*0.9) << 16)| ((int)(130 - 40*gameData.sin[zAxisRotation]*0.9) << 8)| (int)(185 - 40*gameData.sin[zAxisRotation]*0.9); + + zAxisRotation+=18; + temp1.add(temp2); + + + } + + + } + + public void updateAndDraw(){ + if(!isInAction) + return; + + + int[] screen = postProcessingThread.currentScreen; + + //animate particles + for(int i = 0; i < particles.length; i++) + particles[i].add(directions[i]); + + + //find centre in camera coordinate + temp1.set(centre); + temp1.subtract(camera.position); + temp1.rotate_XZ(camera.XZ_angle); + temp1.rotate_YZ(camera.YZ_angle); + temp1.updateLocation(); + + boolean outsideScreen = temp1.screenX < -10 || temp1.screenX > 778 || temp1.screenY < -10 || temp1.screenY > 522; + + if(!outsideScreen){ + + + int position = 0; + int color = 0; + int r = 0; int b = 0; int g = 0; + int alpha = 0; + + //find the size of the particle + double size = 1/temp1.z; + + int spriteIndex = 0; + if(size < 0.3){ + spriteIndex = 1; + }else if(size < 0.35 ){ + spriteIndex = 1; + }else if(size < 0.4){ + spriteIndex = 2; + }else if(size < 0.45){ + spriteIndex = 3; + }else if(size < 0.5){ + spriteIndex = 4; + }else if(size < 0.55){ + spriteIndex = 4; + }else if(size <= 0.6){ + spriteIndex = 4; + } + + + for(int i = 19; i >=0; i--){ + temp1.set(particles[i]); + temp1.subtract(camera.position); + temp1.rotate_XZ(camera.XZ_angle); + temp1.rotate_YZ(camera.YZ_angle); + temp1.updateLocation(); + + + if(temp1.screenX >= 2 && temp1.screenX < 766 && temp1.screenY >=2 && temp1.screenY < 510){ + int centre = (int)temp1.screenX + ((int)temp1.screenY)*768; + + alpha = 100; + alpha = alpha - alpha*lifeSpan/40+ 155; + + for(int j = 0; j < gameData.size[spriteIndex].length; j++){ + position = centre + gameData.size[spriteIndex][j]; + + int bkgrd =screen[position]; + + color = colors[i]; + + + r=(alpha*(((bkgrd>>16)&255)-((color>>16)&255))>>8)+((color>>16)&255); + g=(alpha*(((bkgrd>>8)&255)-((color>>8)&255))>>8)+((color>>8)&255); + b=(alpha*((bkgrd&255)-(color&255))>>8)+(color&255); + + screen[position]= ALPHA|(r<<16)|(g<<8)|b; + + + } + } + } + } + + lifeSpan--; + if(lifeSpan <= 0) + isInAction = false; + + } + +} diff --git a/particles/rocket.java b/particles/rocket.java new file mode 100644 index 0000000..55fe248 --- /dev/null +++ b/particles/rocket.java @@ -0,0 +1,334 @@ +package particles; + +import core.camera; +import core.gameData; +import core.geometry; +import core.mainThread; +import core.polygon3D; +import core.vector; +import entity.solidObject; + +public class rocket { + public vector centre; + + public solidObject target; + + public int damage; + + public int angle; + + public boolean isInAction; + + public vector iDirection, jDirection, kDirection; + + public vector movement; + + public float distanceToTarget; + + public float height; + + public float speed; + + public float distanceTravelled; + + public polygon3D[] polygons; + + public static polygon3D[] polygonsClone; + + public solidObject attacker; + + public boolean visible; + + public static vector tempCentre; + + public static int[] tiles3x3 = new int[]{-129, -128, -127, -1, 0, 1, 127, 128, 129}; + + public rocket(){ + centre = new vector(0,0,0); + iDirection = new vector(1,0,0); + jDirection = new vector(0,1,0); + kDirection = new vector(0,0,1); + makePolygons(); + movement = new vector(0,0,1); + if(tempCentre == null) + tempCentre = new vector(0,0,0); + } + + public void setActive(int angle, int damage, solidObject target, vector centre, solidObject attacker){ + isInAction = true; + this.angle = 360 - angle; + this.damage = damage; + this.target = target; + this.centre.set(centre); + this.attacker = attacker; + distanceTravelled = 0; + speed = 0.005f; + reconstructPolygons(); + + } + + public void reconstructPolygons(){ + for(int i = 0; i < polygons.length; i++){ + if(polygons[i].textureFitPolygon == false){ + + polygons[i].origin.set(polygonsClone[i].origin); + polygons[i].origin.rotate_XZ(this.angle); + polygons[i].origin.add(centre); + + + polygons[i].bottomEnd.set(polygonsClone[i].bottomEnd); + polygons[i].bottomEnd.rotate_XZ(this.angle); + polygons[i].bottomEnd.add(centre); + + + polygons[i].rightEnd.set(polygonsClone[i].rightEnd); + polygons[i].rightEnd.rotate_XZ(this.angle); + polygons[i].rightEnd.add(centre); + + } + + for(int j = 0; j < polygons[i].vertex3D.length; j++){ + polygons[i].vertex3D[j].set(polygonsClone[i].vertex3D[j]); + polygons[i].vertex3D[j].rotate_XZ(this.angle); + polygons[i].vertex3D[j].add(centre); + } + } + } + + public void update(){ + if(!isInAction) + return; + + distanceToTarget = (float)Math.sqrt((target.centre.x - centre.x) * (target.centre.x - centre.x) + (target.centre.z - centre.z) * (target.centre.z - centre.z)); + if(distanceToTarget <= 0.06){ + + //spawn an explosion at the end of the rocket life + float[] tempFloat = mainThread.theAssetManager.explosionInfo[mainThread.theAssetManager.explosionCount]; + tempFloat[0] = centre.x; + if(target.type > 100 && target.type != 200){ + + tempFloat[1] = centre.y + 0.1f; + + }else{ + + tempFloat[1] = centre.y - 0.05f; + } + + tempFloat[2] = centre.z; + tempFloat[3] = 1.5f; + tempFloat[4] = 1; + tempFloat[5] = 0; + tempFloat[6] = 6 + (gameData.getRandom()%4); + tempFloat[7] = target.height; + mainThread.theAssetManager.explosionCount++; + isInAction = false; + + + target.currentHP -=damage; + target.underAttackCountDown = 120; + target.attacker = attacker; + + + int xPos = (int)(target.centre.x*64); + int yPos = (int)(target.centre.z*64); + int start = xPos/16 + (127 - yPos/16)*128; + int targetTeamNo = target.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].teamNo != attacker.teamNo && tile[j].currentCommand != solidObject.move && tile[j].attackStatus != solidObject.isAttacking && tile[j].isCloaked == false + && tile[j].currentCommand != solidObject.attackCautiously && tile[j].currentCommand != solidObject.attackInNumbers){ + if(tile[j].type < 100){ + tile[j].attack(attacker); + tile[j].currentCommand = solidObject.attackInNumbers; + } + } + + } + } + } + + return; + } + + if((target.type < 100 || target.type ==200) && attacker.type == 199){ + float h = 0.08f; + if(target.type ==200) + h = -0.12f; + if(centre.y + h > target.centre.y ){ + centre.y -=0.014f; + } + } + + + + + + + if(speed < 0.1) + speed*=1.4f; + + distanceTravelled+=speed; + + + //spawn tail particle + if(distanceTravelled > 0.08f){ + distanceTravelled = 0; + if(mainThread.theAssetManager.smokeEmmiterCount < 100){ + float[] tempFloat = mainThread.theAssetManager.smokeEmmiterList[mainThread.theAssetManager.smokeEmmiterCount]; + + + + tempFloat[0] = centre.x + (float)Math.random()*0.04f -0.02f; + tempFloat[1] = centre.y; + tempFloat[2] = centre.z + (float)Math.random()*0.04f - 0.02f; + tempFloat[3] = 1f; + tempFloat[4] = 2; + tempFloat[5] = 11; + tempFloat[6] = this.height; + + mainThread.theAssetManager.smokeEmmiterCount++; + } + } + + angle = 360 - geometry.findAngle(centre.x, centre.z, target.centre.x, target.centre.z); + + movement.set(0,0,1); + movement.rotate_XZ(angle); + centre.add(movement, speed); + + reconstructPolygons(); + + //update center in camera coordinate + tempCentre.set(centre); + tempCentre.subtract(camera.position); + tempCentre.rotate_XZ(camera.XZ_angle); + tempCentre.rotate_YZ(camera.YZ_angle); + tempCentre.updateLocation(); + + visible = true; + if(tempCentre.screenX < -100 || tempCentre.screenX > 856 || tempCentre.screenY < -100 || tempCentre.screenY > 612){ + visible = false; + } + + if(visible) + for(int i = 0; i < polygons.length; i++){ + polygons[i].update_lightspace(); + } + + + + } + + public void draw(){ + if(!isInAction || !visible) + return; + + for(int i = 0; i < polygons.length; i ++){ + polygons[i].update(); + polygons[i].findNormal(); + polygons[i].findDiffuse(); + polygons[i].draw(); + } + } + + + + public void makePolygons(){ + int size = 12; + float radius = 0.005f; + float length = 0.03f; + + polygons = new polygon3D[size*2]; + + double theta = Math.PI/(size/2); + + vector[] v1 = new vector[size]; + vector[] v2 = new vector[size]; + + for(int i = 0; i < size; i++){ + v2[i] = put(radius*Math.cos(i*theta), radius*Math.sin(i*theta), length); + } + + for(int i = 0; i < size; i++){ + v1[i] = put(radius*Math.cos(i*theta), radius*Math.sin(i*theta), -length); + } + + + for(int i = 0; i < size; i ++){ + polygons[i] = new polygon3D(new vector[]{v1[i],v1[(i+1)%size],v2[(i+1)%size],v2[i]}, v1[i],v1[(i+1)%size], v2[i], mainThread.textures[68], 1,1,1); + polygons[i].color = 25 + (25 << 5) + (25 << 10); + } + + + + + for(int i = 0; i < size; i++){ + v2[i] = put(0*Math.cos(i*theta), 0*Math.sin(i*theta), 0.05); + } + + for(int i = 0; i < size; i++){ + v1[i] = put(radius*Math.cos(i*theta), radius*Math.sin(i*theta), 0.03); + } + + + for(int i = 0; i < size; i ++){ + polygons[i + size] = new polygon3D(new vector[]{v1[i],v1[(i+1)%size],v2[(i+1)%size],v2[i]}, v1[i],v1[(i+1)%size], v2[i], mainThread.textures[69], 1,1,1); + polygons[i + size].color = 0 + (0 << 5) + (25 << 10); + } + + + + + if(polygonsClone == null){ + polygonsClone = new polygon3D[size * 2]; + + for(int i = 0; i < size; i++){ + v2[i] = put(radius*Math.cos(i*theta), radius*Math.sin(i*theta), length); + } + + for(int i = 0; i < size; i++){ + v1[i] = put(radius*Math.cos(i*theta), radius*Math.sin(i*theta), -length); + } + + + for(int i = 0; i < size; i ++){ + polygonsClone[i] = new polygon3D(new vector[]{v1[i],v1[(i+1)%size],v2[(i+1)%size],v2[i]}, v1[i],v1[(i+1)%size], v2[i], null, 1,1,0); + polygonsClone[i].color = 16 + (16 << 5) + (16 << 10); + } + + for(int i = 0; i < size; i++){ + v2[i] = put(0*Math.cos(i*theta), 0*Math.sin(i*theta), 0.05); + } + + for(int i = 0; i < size; i++){ + v1[i] = put(radius*Math.cos(i*theta), radius*Math.sin(i*theta), 0.03); + } + + + for(int i = 0; i < size; i ++){ + polygonsClone[i + size] = new polygon3D(new vector[]{v1[i],v1[(i+1)%size],v2[(i+1)%size],v2[i]}, v1[i],v1[(i+1)%size], v2[i], null, 1,1,0); + polygonsClone[i + size].color = 0 + (0 << 5) + (25 << 10); + } + + } + + } + + //create a arbitrary vertex + public vector put(double i, double j, double k){ + vector temp = new vector(0,0,0); + temp.add(iDirection, (float)i); + temp.add(jDirection, (float)j); + temp.add(kDirection, (float)k); + return temp; + } + + + +} diff --git a/particles/smokeParticle.java b/particles/smokeParticle.java new file mode 100644 index 0000000..989afda --- /dev/null +++ b/particles/smokeParticle.java @@ -0,0 +1,317 @@ +package particles; + +import core.mainThread; +import core.postProcessingThread; +import core.vector; + +public class smokeParticle { + //size of the smoke particle + public float size; + + //which sprite to use + public int spriteIndex; + + //current frame Index; + public int frameIndex; + + //life time + public int lifeTime; + public int animationSpeed; + + //centre of the smoke particle + public vector centre; + public vector tempCentre; + + public boolean isInAction; + public float smokeHeight; + + public static int[] screen; + public static int[] zbuffer; + + + public smokeParticle(){ + centre = new vector(0,0,0); + tempCentre = new vector(0,0,0); + } + + + public void setActive(float x, float y, float z, float size, int animationSpeed, int spriteIndex, float smokeHeight){ + isInAction = true; + + this.size = size; + this.animationSpeed = animationSpeed; + this.spriteIndex = spriteIndex; + frameIndex = 0; + + lifeTime = 80; + if(size == 1f) + lifeTime = 64; + + this.centre.set(x,y,z); + + this.smokeHeight = (smokeHeight - centre.y) *300000; + } + + public void updateAndDraw(){ + if(!isInAction) + return; + + smokeParticle.screen = postProcessingThread.currentScreen; + smokeParticle.zbuffer = postProcessingThread.currentZbuffer; + + if(size ==1.5){ + centre.y += 0.0035f; + }else if(size == 0.7f){ + centre.y += 0.005f; + }else if(size == 0.9f){ + centre.y += 0.0025f; + }else if(size == 0.8f){ + centre.y -= 0.006f; + } + + //update centre in camera coordinate + vector cameraPosition = postProcessingThread.cameraPosition; + float X = 0,Y = 0, Z = 0, + camX = cameraPosition.x, camY = cameraPosition.y, camZ = cameraPosition.z, + sinXZ = postProcessingThread.sinXZ, + cosXZ = postProcessingThread.cosXZ, + sinYZ = postProcessingThread.sinYZ, + cosYZ = postProcessingThread.cosYZ; + + X = centre.x - camX; + Y = centre.y - camY; + Z = centre.z - camZ; + + //rotating + tempCentre.x = cosXZ*X - sinXZ*Z; + tempCentre.z = sinXZ*X + cosXZ*Z; + + Z = tempCentre.z; + + tempCentre.y = cosYZ*Y - sinYZ*Z; + tempCentre.z = sinYZ*Y + cosYZ*Z; + tempCentre.updateLocation(); + + + + int xPos = (int)tempCentre.screenX; + int yPos = (int)tempCentre.screenY; + + if(xPos > 900 || xPos < -132 || yPos > 644 || yPos < -132){ + frameIndex+=animationSpeed; + lifeTime-=animationSpeed; + if(lifeTime <= 0) + isInAction = false; + return; + } + + int[] sprite = mainThread.textures[spriteIndex].smoke[frameIndex/2]; + + + float ratio = size*2/tempCentre.z; + + + int width = 64; + int height = 64; + int depth = (int)(0x1000000/tempCentre.z + smokeHeight); + + + int originalWidth = width; + + //find the size ratio between a sprite pixel and screen pixel + float ratioInverse = 1f/ratio; + + width = (int)(ratio*width); + height = (int)(ratio*height); + + //only draw the part of the sprite that is inside the screen + //define boundary + int xTop = xPos - width/2; + int yTop = yPos - height/4*3; + int xBot = xPos + width/2; + int yBot = yPos + height/4; + + + + //draw sprite + int screenIndex = 0; + int SpriteValue = 0; + int screenValue = 0; + int r,g,b; + + //power plant smoke particle + if(size == 1.5){ + for(int i = yTop, y = 0; i < yBot; i++, y++){ + if(i < 0 || i >=512) + continue; + int ratioInverseY = (int)(ratioInverse*y); + for(int j = xTop, x = 0; j < xBot; j++, x++){ + + SpriteValue = sprite[(int)(ratioInverse*x) + ratioInverseY*originalWidth] & 255; + + if(SpriteValue == 0) + continue; + + if(j < 0 || j >= 768) + continue; + screenIndex = j + i*768; + if(zbuffer[screenIndex] >= depth) + continue; + screenValue = screen[screenIndex]; + + + r = ((((screenValue & 0xff0000)>>16)*(256 - SpriteValue))>>8) + SpriteValue; + g = ((((screenValue &0xff00)>>8)*(256 - SpriteValue))>>8) + SpriteValue; + b = (((screenValue & 0xff)*(256 - SpriteValue))>>8) + SpriteValue; + + + screen[screenIndex] = (r<<16)|(g<<8)|b; + + } + } + }else + + //fire smoke particle + if(size == 0.7f){ + for(int i = yTop, y = 0; i < yBot; i++, y++){ + if(i < 0 || i >=512) + continue; + int ratioInverseY = (int)(ratioInverse*y); + for(int j = xTop, x = 0; j < xBot; j++, x++){ + + SpriteValue = sprite[(int)(ratioInverse*x) + ratioInverseY*originalWidth] & 255; + + if(SpriteValue == 0) + continue; + + if(j < 0 || j >= 768) + continue; + screenIndex = j + i*768; + if(zbuffer[screenIndex] >= depth) + continue; + screenValue = screen[screenIndex]; + + + r = ((((screenValue & 0xff0000)>>16)*(256 - SpriteValue))>>8) ; + g = ((((screenValue &0xff00)>>8)*(256 - SpriteValue))>>8); + b = (((screenValue & 0xff)*(256 - SpriteValue))>>8); + + + screen[screenIndex] = (r<<16)|(g<<8)|b; + + } + } + }else + + //rocket tail particle + if(size == 1f){ + if(yTop >= 0 && yBot < 512 && xTop >= 0 && xBot < 768){ + for(int i = yTop, y = 0; i < yBot; i++, y++){ + + + int ratioInverseY = (int)(ratioInverse*y) * originalWidth; + float ratioInverseX = 0; + + screenIndex = xTop + i*768; + + for(int j = xTop; j < xBot; j++, screenIndex++, ratioInverseX+=ratioInverse){ + + SpriteValue = sprite[(int)(ratioInverseX) + ratioInverseY]; + + if(SpriteValue == 0) + continue; + + SpriteValue = 256 - ((SpriteValue * lifeTime) >> 6); + + + //if(zbuffer[screenIndex] >= depth) + // continue; + screenValue = screen[screenIndex]; + + r = ((((screenValue & 0xff0000)>>16)*SpriteValue)>>8) ; + g = ((((screenValue & 0xff00)>>8)*SpriteValue)>>8); + b = (((screenValue & 0xff)*SpriteValue)>>8); + + screen[screenIndex] = (r<<16)|(g<<8)|b; + + } + } + } + }else + + //refinery smoke particle + if(size == 0.9f){ + for(int i = yTop, y = 0; i < yBot; i++, y++){ + if(i < 0 || i >=512) + continue; + int ratioInverseY = (int)(ratioInverse*y); + for(int j = xTop, x = 0; j < xBot; j++, x++){ + + SpriteValue = sprite[(int)(ratioInverse*x) + ratioInverseY*originalWidth] & 255; + + if(SpriteValue == 0) + continue; + + if(j < 0 || j >= 768) + continue; + screenIndex = j + i*768; + if(zbuffer[screenIndex] >= depth) + continue; + screenValue = screen[screenIndex]; + + + r = ((((screenValue & 0xff0000)>>16)*(256 - SpriteValue))>>8) + (SpriteValue/4); + g = ((((screenValue &0xff00)>>8)*(256 - SpriteValue))>>8) + (SpriteValue/6); + b = (((screenValue & 0xff)*(256 - SpriteValue))>>8) + (SpriteValue/6); + + + screen[screenIndex] = (r<<16)|(g<<8)|b; + + } + } + } else + + if(size == 0.8f){ + for(int i = yTop, y = 0; i < yBot; i++, y++){ + if(i < 0 || i >=512) + continue; + int ratioInverseY = (int)(ratioInverse*y); + for(int j = xTop, x = 0; j < xBot; j++, x++){ + + SpriteValue = sprite[(int)(ratioInverse*x) + ratioInverseY*originalWidth] & 255; + + if(SpriteValue == 0) + continue; + + if(j < 0 || j >= 768) + continue; + screenIndex = j + i*768; + if(zbuffer[screenIndex] >= depth) + continue; + screenValue = screen[screenIndex]; + + + r = ((((screenValue & 0xff0000)>>16)*(256 - SpriteValue))>>8) + SpriteValue; + g = ((((screenValue &0xff00)>>8)*(256 - SpriteValue))>>8) + SpriteValue; + b = (((screenValue & 0xff)*(256 - SpriteValue))>>8) + SpriteValue; + + + screen[screenIndex] = (r<<16)|(g<<8)|b; + + } + } + } + + + + + + frameIndex+=animationSpeed; + lifeTime-=animationSpeed; + if(lifeTime <= 0) + isInAction = false; + + } + + +}