package rts.core.engine.layers.entities; import java.awt.Point; import java.util.ArrayList; import org.newdawn.slick.GameContainer; import org.newdawn.slick.SlickException; import org.newdawn.slick.util.pathfinding.Mover; import org.newdawn.slick.util.pathfinding.Path; import rts.core.engine.Engine; import rts.core.engine.GameSound; import rts.core.engine.Utils; import rts.core.engine.layers.entities.effects.MoveToLocation; import rts.core.network.ig_udp_containers.EntityState; import rts.utils.Timer; public abstract class MoveableEntity extends ActiveEntity implements Mover { public static final int EARTH_ONLY = 0; public static final int WATER_ONLY = 1; public static final int EVERYWHERE = 2; public static final int INACTIVE = 0; public static final int DEFENSIVE = 1; public static final int AGGRESSIVE = 2; private static final int MAX_SEEK_ATTEMPT = 5; private static final int TIME_BEFORE_SEEK = 1250; private int pathNumber; private int targetX; private int targetY; private int attempt; private boolean changePath; private boolean seekPath; private ActiveEntity target; private Timer seekTimer; private ArrayList<Point> locations; protected Path path; protected int moveType; protected int behavior; protected float speed; protected boolean locationCorrect; public MoveableEntity(Engine engine, int minTecLevel, int layer, int type, int maxLife, int view, int playerId, int teamId, int networkId) { super(engine, minTecLevel, layer, type, maxLife, view, playerId, teamId, networkId); this.behavior = DEFENSIVE; this.seekTimer = new Timer(TIME_BEFORE_SEEK); this.locations = new ArrayList<Point>(); this.locationCorrect = true; } protected abstract void destroy(); protected abstract void fireOnTarget(ActiveEntity target); protected abstract boolean specialTarget(ActiveEntity target); protected abstract boolean canGoToTransport(ActiveEntity target); // single unit calls this @Override public void target(ActiveEntity target, int mx, int my) { if (visible) { if (!canGoToTransport(target)) { if (!specialTarget(target)) { if (target.getTeamId() != engine.getPlayer().getTeamId()) { if (engine.getMap().isEntityBlocked(mx, my)) { Point p = Utils.getCloserPoint(engine.getMap(), this, mx, my); mx = p.x; my = p.y; } if (EData.BULLET_POWER[type][target.getType()] != 0) { checkTarget(target, mx, my); } else { this.move(mx * engine.getTileW(), my * engine.getTileH()); } GameSound.moverAttack(); } } else GameSound.moverMove(); } } } private void checkTarget(ActiveEntity target, int mx, int my) { if (!(Utils.getDistanceBetween(x, y, target.getX(), target.getY()) < (view - 1) * engine.getTileW())) { this.move(mx * engine.getTileW(), my * engine.getTileH()); if (path != null) this.target = target; } else { this.target = target; } } // Must check new positions to block/unblock map @Override public void setState(EntityState state) { int oldX = (int) (x / engine.getTileW()); int oldY = (int) (y / engine.getTileH()); // Get the new position super.setState(state); if (oldX != ((int) (x / engine.getTileW())) || oldY != ((int) (y / engine.getTileH()))) { locations.remove(new Point(oldX, oldY)); engine.getMap().removeEntityLocation(this, oldX, oldY); } // Fire if (state.fire && (state.targetX != -1 || state.targetY != -1)) { ActiveEntity ae = engine.getEntityAt(this, state.targetX, state.targetY); if (ae != null) { fireOnTarget(ae); } } } @Override public void updateEntity(GameContainer container, int delta) throws SlickException { // By default not shooting and reset target state if not alive state.fire = false; state.targetX = -1; state.targetY = -1; if (target != null && (!target.isAlive() || !target.isVisible())) { target = null; } if (path != null) { updatePath(delta); } else { if (seekPath) { seekTimer.update(delta); if (seekTimer.isTimeComplete()) { if (attempt == MAX_SEEK_ATTEMPT) { seekPath = false; attempt = 0; } else { seekPath(); attempt++; } seekTimer.resetTime(); } } // A CAUSE DE PLUSIEURS ENTITES CERTAINES CASES // SONT LIBRES VOIR SYNCHRO ACCES MAP addLocation((int) x / engine.getTileW(), (int) y / engine.getTileH()); if (target != null) { checkTargetState(); } else { if (engine.isPlayerEntity(playerId)) { if (behavior == DEFENSIVE) { ActiveEntity ent = engine.getFirstEnemyEntity(this, view); if (ent != null) { direction = Utils.findDirection(x / engine.getTileW(), y / engine.getTileH(), (int) ent.getX() / engine.getTileW(), (int) ent .getY() / engine.getTileH()); if (!(ent instanceof IBigEntity)) { if (EData.BULLET_POWER[type][ent.getType()] != 0) { fireOnTarget(ent); state.fire = true; state.targetX = ent.getX(); state.targetY = ent.getY(); } } } } else { if (behavior == AGGRESSIVE && target == null) { ActiveEntity ent = engine.getFirstEnemyEntity(this, view); if (ent != null) { Point p = Utils.getCloserPoint(engine.getMap(), this, (int) ent.getX() / engine.getTileW(), (int) ent.getY() / engine.getTileH()); target(ent, p.x, p.y); } } } } } } } private void addLocation(int x, int y) { Point p = new Point(x, y); if (!locations.contains(p)) { engine.getMap().addEntityLocation(this, true, x, y); locations.add(new Point(x, y)); } } private boolean closeFromTarget() { int tx; int ty; if (target instanceof IBigEntity) { tx = (int) ((IBigEntity) target).getRealX() / engine.getTileW(); ty = (int) ((IBigEntity) target).getRealY() / engine.getTileH(); } else { tx = (int) target.getX() / engine.getTileW(); ty = (int) target.getY() / engine.getTileH(); } if (Utils.getDistanceBetween(x, y, tx * engine.getTileW(), ty * engine.getTileH()) < (view - 1) * engine.getTileW()) { direction = Utils.findDirection(x / engine.getTileW(), y / engine.getTileH(), tx, ty); fireOnTarget(target); state.fire = true; state.targetX = target.getX(); state.targetY = target.getY(); return true; } return false; } private void checkTargetState() { if (target.isAlive()) { if (!closeFromTarget()) { Point p = Utils.getCloserPoint(engine.getMap(), this, (int) target.getX() / engine.getTileW(), (int) target.getY() / engine.getTileH()); if (!engine.getMap().blocked(this, p.x, p.y)) { targetX = p.x * engine.getTileW(); targetY = p.y * engine.getTileH(); seekPath(); } } } else { target = null; } } private void updatePath(int delta) { if (path.getLength() > pathNumber) { float cx = x / engine.getTileW(); float cy = y / engine.getTileH(); int nx = path.getStep(pathNumber).getX(); int ny = path.getStep(pathNumber).getY(); if ((cx < nx + 0.1f && cx > nx - 0.1f) && (cy < ny + 0.1f && cy > ny - 0.1f)) { this.x = nx * engine.getTileW(); this.y = ny * engine.getTileH(); locationCorrect = true; // On lib�re la case pr�c�dente engine.getMap().removeEntityLocation(this, path.getStep(pathNumber - 1).getX(), path.getStep(pathNumber - 1).getY()); locations.remove(new Point(path.getStep(pathNumber - 1).getX(), path.getStep(pathNumber - 1).getY())); // On s'assure que la case suivante est toujours accessible if (path.getLength() > pathNumber + 1) { if (engine.getMap().blocked(this, path.getStep(pathNumber + 1).getX(), path.getStep(pathNumber + 1).getY())) { changePath = true; } } if (changePath) { seekPath(); changePath = false; } else { pathNumber++; checkFowFromView(); if (target != null && closeFromTarget()) { seekPath = false; path = null; } else { if (path.getLength() > pathNumber) { addLocation(path.getStep(pathNumber).getX(), path.getStep(pathNumber).getY()); } else { seekPath = false; path = null; } } } } else { locationCorrect = false; // Find Direction direction = Utils.findDirection(cx, cy, nx, ny); this.x += speed * delta * Utils.DIRECTIONS[direction][0]; this.y += speed * delta * Utils.DIRECTIONS[direction][1]; } } } public void move(int mx, int my) { // Before moving check that the current move is finish targetX = mx; targetY = my; seekPath = true; if (path == null) { seekPath(); } else changePath = true; } private void seekPath() { path = engine.getPathFinder().findPath(this, (int) (x / engine.getTileW()), (int) (y / engine.getTileH()), (targetX / engine.getTileW()), (targetY / engine.getTileH())); this.pathNumber = 1; if (path != null) { seekPath = false; attempt = 0; if (path.getLength() > pathNumber) { addLocation(path.getStep(pathNumber).getX(), path.getStep(pathNumber).getY()); } } } public void moveFromPlayerAction(int mx, int my) { if (selected && playerId == engine.getPlayer().getId()) { target = null; engine.addEntity(new MoveToLocation(engine, mx, my)); move(mx, my); } } @Override public void remove() { if (visible) { for (int i = 0; i < locations.size(); i++) { engine.getMap().removeEntityLocation(this, locations.get(i).x, locations.get(i).y); } destroy(); } engine.getMap().removeEntityLocation(this, (int) x / engine.getTileW(), (int) y / engine.getTileH()); engine.removeEntity(this); } public int getMoveType() { return moveType; } public void setBehavior(int behavior) { this.behavior = behavior; } public boolean isStopped() { return path == null; } }