package rts.core.engine.layers.entities.buildings; import java.awt.Point; import java.util.ArrayList; import java.util.Random; import org.newdawn.slick.Animation; import org.newdawn.slick.Color; import org.newdawn.slick.GameContainer; import org.newdawn.slick.Graphics; import org.newdawn.slick.SlickException; import org.newdawn.slick.SpriteSheet; import org.newdawn.slick.gui.GUIContext; import rts.core.engine.Engine; import rts.core.engine.GameSound; import rts.core.engine.Utils; import rts.core.engine.layers.Layer; import rts.core.engine.layers.entities.ActiveEntity; import rts.core.engine.layers.entities.EData; import rts.core.engine.layers.entities.IBigEntity; import rts.core.network.ig_udp_containers.EntityState; import rts.utils.Colors; import rts.utils.MoveUpEffect; import rts.utils.ResourceManager; import rts.utils.Timer; public abstract class Building extends ActiveEntity implements IBigEntity { private static final int DEFAULT_DISTANCE_MAX_BETWEEN_BUILDINGS = 100; protected static final Color FADE_RED = new Color(255, 0, 0, 100); protected static final Color FADE_BLUE = new Color(0, 0, 255, 100); private Animation flameAnimation; private Point flameOne; private Point flameTwo; private Point flameThree; private Timer repairTimer; private Timer showRepairTimer; private boolean block; private boolean repair; // For building with a different behaviour protected boolean validLocation; protected int distanceMaxBetweenBuilding; public Building(Engine engine, int type, boolean block, int playerId, int teamId, int networkId) { super(engine, EData.TEC_LEVEL[type], Layer.FIRST_EFFECT, type, EData.MAX_LIFE[type], EData.VIEW[type], playerId, teamId, networkId); this.distanceMaxBetweenBuilding = DEFAULT_DISTANCE_MAX_BETWEEN_BUILDINGS; this.color = Colors.getColor(engine.getPlayer(playerId).getColor()); this.block = block; flameAnimation = new Animation(); SpriteSheet ss = ResourceManager.getSpriteSheet("flame"); for (int i = 0; i < 5; i++) { flameAnimation.addFrame(ss.getSprite(i, 0), 100); } flameOne = new Point(); flameTwo = new Point(); flameThree = new Point(); repairTimer = new Timer(500); showRepairTimer = new Timer(500); } protected abstract void renderBuilding(GameContainer container, Graphics g) throws SlickException; protected abstract void removeBuilding(); @Override public void renderEntity(GameContainer container, Graphics g) throws SlickException { renderBuilding(container, g); if (weak || dying) { g.drawAnimation(flameAnimation, flameOne.x - 10, flameOne.y - 35); g.drawAnimation(flameAnimation, flameTwo.x - 10, flameTwo.y - 35); g.drawAnimation(flameAnimation, flameThree.x - 10, flameThree.y - 35); } if (repair && showRepairTimer.isTimeComplete()) { engine.addEntity(new MoveUpEffect(engine, x + (width / 2) - 4, y - 15, "-$", new Color(255, 215, 0, 255), 50)); showRepairTimer.resetTime(); } } @Override public void renderOnMiniMap(Graphics g, float x, float y, float tw, float th) { g.setColor(color); g.fillRect(x, y, (width / 20) * tw, (height / 20) * th); } public void renderLocationOnMap(GUIContext container, Graphics g) { x = engine.getMouseX(); y = engine.getMouseY(); int lx = (int) (x / engine.getTileW()); int ly = (int) (y / engine.getTileH()); // Get closer bulding ArrayList<Building> buildings = engine.getPlayerBuilding(); Building closer = null; float dist = 0; if (!buildings.isEmpty()) { dist = Utils.getDistanceBetween(getRealX(), getRealY(), buildings.get(0).getRealX(), buildings.get(0).getRealY()); for (int i = 0; i < buildings.size(); i++) { float nd = Utils.getDistanceBetween(getRealX(), getRealY(), buildings.get(i).getRealX(), buildings.get(i).getRealY()); if (nd <= dist) { dist = nd; closer = buildings.get(i); } } } g.translate(engine.getXScrollDecal(), engine.getYScrollDecal()); if (closer != null) { validLocation = true; for (int i = 0; i < width / 20; i++) { for (int j = 0; j < height / 20; j++) { int x = (lx + i); int y = (ly + j); checkValidLocation(g, closer, x, y); g.fillRect(x * 20, y * 20, 20, 20); } } } else { validLocation = false; g.setColor(FADE_RED); for (int i = 0; i < width / 20; i++) { for (int j = 0; j < height / 20; j++) { g.fillRect((lx + i) * 20, (ly + j) * 20, 20, 20); } } } g.translate(-engine.getXScrollDecal(), -engine.getYScrollDecal()); } public void repair() { if (this.isAlive() && this.visible) { repair = !repair; if (repair) GameSound.repair(); } } public void sell() { if (this.isAlive() && this.visible) { GameSound.buildingSold(); this.remove(); this.engine.addEntity(new MoveUpEffect(engine, x, y - 10, "+" + (EData.PRICE[type] / 2) + " $", new Color(255, 215, 0, 255), 50)); engine.getPlayer().addMoney((EData.PRICE[type] / 2)); } } public boolean isValidLocation(int mx, int my) { return validLocation; } // TRUNG NGUYEN // THIS CHECK IS A CERTAIN x, y LOCATION IS A VALID SPOT // it is modeled after checkValidLocation // does not need graphics and does not need to check for realX, realY public boolean checkValidPlacement(int x, int y) { if (engine.getMap().isEntityOccupy(x, y) || engine.getMap().isBlocked(x, y) || engine.getMap().isWater(x, y)) { return false; } return true; } protected void checkValidLocation(Graphics g, Building closer, int x, int y) { if (engine.getMap().isEntityOccupy(x, y) || engine.getMap().isBlocked(x, y) || engine.getMap().isWater(x, y) || (Utils.getDistanceBetween(x * engine.getTileW(), y * engine.getTileH(), closer.getRealX(), closer.getRealY()) > distanceMaxBetweenBuilding)) { g.setColor(FADE_RED); validLocation = false; } else { g.setColor(FADE_BLUE); } } public void updateEntity(GameContainer container, int delta) throws SlickException { repairTimer.update(delta); showRepairTimer.update(delta); if (repair && repairTimer.isTimeComplete()) { if (this.life < this.maxLife) { if (engine.getPlayer().removeMoney(5)) { this.addLife(1); } } else { repair = false; } repairTimer.resetTime(); } } @Override public void setLocation(float x, float y) { super.setLocation(x, y); checkFowFromView(); Random r = new Random(); flameOne.x = (int) (x + 5 + r.nextInt(width - 5)); flameOne.y = (int) (y + 5 + r.nextInt(height - 5)); flameTwo.x = (int) (x + 5 + r.nextInt(width - 5)); flameTwo.y = (int) (y + 5 + r.nextInt(height - 5)); flameThree.x = (int) (x + 5 + r.nextInt(width - 5)); flameThree.y = (int) (y + 5 + r.nextInt(height - 5)); int lx = (int) (x / engine.getTileW()); int ly = (int) (y / engine.getTileH()); for (int i = 0; i < width / 20; i++) { for (int j = 0; j < height / 20; j++) { engine.getMap().addEntityLocation(this, block, lx + i, ly + j); } } } @Override public void remove() { int lx = (int) (x / engine.getTileW()); int ly = (int) (y / engine.getTileH()); for (int i = 0; i < width / 20; i++) { for (int j = 0; j < height / 20; j++) { engine.getMap().removeEntityLocation(this, lx + i, ly + j); } } removeBuilding(); if (engine.isPlayerEntity(playerId)) engine.getGui().removeEntityFromBuildingList(type); } @Override public void setState(EntityState state) { if (state.life < this.life && engine.isPlayerEntity(playerId)) { GameSound.ourBaseIsUnderAttack(); } super.setState(state); } @Override public int getTargetCursor(ActiveEntity target, int mx, int my) { return 0; } @Override public void target(ActiveEntity target, int mx, int my) { engine.deselectAllEntities(); target.selected(); } @Override public float getRealX() { return x + (width / 2); } @Override public float getRealY() { return y + (height / 2); } @Override public boolean fogOnUnit() { return false; } public void setColor(Color color) { this.color = color; } }