package main; import java.awt.FontMetrics; import java.awt.Font; import java.awt.Graphics; import java.util.Iterator; import astar.AStarSearch; import collision.Bound; import java.awt.Color; import utils.DynamicImage; import java.awt.Point; import java.util.LinkedList; import java.awt.geom.Point2D; public class Creature extends MapObject { String name; private Model model; private Point2D.Double exactLoc; LinkedList path; Creature enemyTarget; int speed; long lastMoved; long lastAttacked; boolean attacked; int xOffset; int yOffset; public int strikeFrame; boolean dead; private int damage; int minRange; int startRange; int maxRange; int hitpoints; int manapoints; int maxHitpoints; int maxManapoints; int[] stats; public int id; private static int lastId; public static DynamicImage hpBar; static { Creature.lastId = 0; } public Creature(final String name, final int xOffset, final int yOffset) { super(0, 0, 0); this.name = name; this.model = null; this.loc = new Point(0, 0); (this.exactLoc = new Point2D.Double()).setLocation(this.loc); this.path = null; this.speed = 50; this.attacked = false; this.xOffset = xOffset; this.yOffset = yOffset; this.strikeFrame = -1; this.damage = 0; this.minRange = 0; this.startRange = 0; this.maxRange = 0; final boolean b = false; this.hitpoints = (b ? 1 : 0); this.maxHitpoints = (b ? 1 : 0); final boolean b2 = false; this.manapoints = (b2 ? 1 : 0); this.maxManapoints = (b2 ? 1 : 0); (this.stats = new int[8])[StatType.Strength.ordinal()] = 0; this.stats[StatType.Dexterity.ordinal()] = 0; this.stats[StatType.Constitution.ordinal()] = 0; this.stats[StatType.Intelligence.ordinal()] = 0; this.stats[StatType.Fire.ordinal()] = 0; this.stats[StatType.Ice.ordinal()] = 0; this.stats[StatType.Wind.ordinal()] = 0; this.stats[StatType.Fire.ordinal()] = 0; this.dead = false; this.id = Creature.lastId; ++Creature.lastId; } protected Creature(final Creature cr) { super(cr, 0, 0, 0); this.name = cr.name; this.model = new Model(cr.model); this.path = null; this.speed = cr.speed; this.attacked = false; this.xOffset = cr.xOffset; this.yOffset = cr.yOffset; this.strikeFrame = cr.strikeFrame; this.damage = cr.damage; this.minRange = cr.minRange; this.startRange = cr.startRange; this.maxRange = cr.maxRange; final int maxHitpoints = cr.maxHitpoints; this.hitpoints = maxHitpoints; this.maxHitpoints = maxHitpoints; final int maxHitpoints2 = cr.maxHitpoints; this.manapoints = maxHitpoints2; this.maxManapoints = maxHitpoints2; this.stats = new int[cr.stats.length]; for (int x = 0; x < cr.stats.length; ++x) { this.stats[x] = cr.stats[x]; } this.dead = false; this.id = cr.id; } public Creature copy(final Point newLoc) { final Creature newCr = new Creature(this); newCr.initLoc(newLoc); return newCr; } protected void initLoc(final Point newLoc) { this.loc = newLoc; (this.exactLoc = new Point2D.Double()).setLocation(this.loc); } public Model getModel() { return this.model; } public void loadModel(final String folder, final Color bgColor, final Color shadowColor, final int[] numFramesArr) { this.model = new Model(folder, bgColor, shadowColor, numFramesArr); } public void setModel(final Model model) { this.model = model; } public void setStats(final int strength, final int dexterity, final int constitution, final int intelligence) { this.stats[StatType.Strength.ordinal()] = strength; this.stats[StatType.Dexterity.ordinal()] = dexterity; this.stats[StatType.Constitution.ordinal()] = constitution; this.stats[StatType.Intelligence.ordinal()] = intelligence; this.propagateStatChanges(); this.hitpoints = this.maxHitpoints; this.manapoints = this.maxManapoints; } public void setAttack(final int damage, final int minRange, final int startRange, final int maxRange) { this.damage = damage; this.minRange = minRange; this.startRange = startRange; this.maxRange = maxRange; } public void propagateStatChanges() { this.maxHitpoints = this.stats[StatType.Constitution.ordinal()] * 5; this.maxManapoints = this.stats[StatType.Intelligence.ordinal()] * 5; } public void setWalkSpeed(final int speed) { this.speed = speed; } @Override public double getSortZ() { if (this.dead) { return super.getSortZ() + 0.5; } return super.getSortZ() + 1.0; } public int getDamage() { return this.damage; } public void takeDamage(final int damage) { this.hitpoints -= damage; } public boolean readyToAttack() { final boolean ans = this.model.action == Action.Attacking && this.model.getCurrentAnimation().getCurrentFrame() == this.strikeFrame; if (this.attacked) { this.attacked = ans; return false; } return this.attacked = ans; } public void AI_move(final Player player, final Map map) { } public void AI_react(final Map map) { } public void startAttack(final Creature enemy) { final Direction dir = calcDirection(this.exactLoc, enemy.exactLoc); if (dir != null) { this.model.direction = dir; } this.model.action = Action.Attacking; } public void attack(final Creature enemy) { this.enemyTarget.takeDamage(this.getDamage()); if (this.enemyTarget.hitpoints <= 0) { this.enemyTarget.die(); this.enemyTarget = null; this.path = null; } } public void setLoc(final Point loc) { this.loc.setLocation(loc); this.exactLoc.setLocation(loc); } public void die() { this.hitpoints = 0; this.path = null; this.model.action = Action.Dying; this.setBound(null); this.dead = true; } public void setEnemyTarget(final Creature cr, final Map map) { this.enemyTarget = cr; if (this.enemyTarget != null) { this.setTarget(new Point(cr.loc), map); } } public void setTarget(final Point p, final Map map) { this.path = AStarSearch.findPath(this.loc, p, map.asMap); if (this.path != null) { this.path.removeFirst(); } } public void move(final LinkedList nearbyObjects, final Map map) { if (this.lastMoved == 0L) { this.lastMoved = System.nanoTime(); return; } if (this.dead) { return; } final double dist = this.speed * (System.nanoTime() - this.lastMoved) / 1.0E9; final Point2D.Double newLoc = new Point2D.Double(); final Point oldLoc = this.loc; double xDif = 0.0; double yDif = 0.0; this.lastMoved = System.nanoTime(); this.AI_react(map); if ((this.model.action == Action.Attacking || this.model.action == Action.BeenHit) && this.model.getCurrentAnimation().reachedEnd()) { this.model.getCurrentAnimation().reset(); this.model.action = Action.Standing; this.enemyTarget = null; this.path = null; } if (this.model.action == Action.Attacking || this.model.action == Action.BeenHit) { return; } Point target = null; if (this.path == null) { if (this.model.action == Action.Walking || this.model.action == Action.Running) { this.model.getCurrentAnimation().reset(); this.model.action = Action.Standing; } return; } target = this.path.getFirst(); if (this.exactLoc.distance(target) <= dist) { newLoc.setLocation(target); this.path.removeFirst(); if (this.path.size() == 0) { this.path = null; } } else { xDif = (target.x - this.exactLoc.x) * dist / this.exactLoc.distance(target); yDif = (target.y - this.exactLoc.y) * dist / this.exactLoc.distance(target); newLoc.setLocation(this.exactLoc.x + xDif, this.exactLoc.y + yDif); if ((xDif != 0.0 || yDif != 0.0) && this.model.action != Action.Walking) { this.model.getCurrentAnimation().reset(); this.model.action = Action.Walking; } } final Direction dir = calcDirection(this.exactLoc, newLoc); if (dir != null && target != null && this.model.direction != dir) { this.model.getCurrentAnimation().reset(); this.model.direction = dir; } (this.loc = new Point(0, 0)).setLocation(newLoc); for (final MapObject obj : nearbyObjects) { if (this != obj && obj.intersects(this) && Creature.class.isAssignableFrom(obj.getClass())) { if (!Creature.class.isAssignableFrom(obj.getClass()) || ((Creature)obj).path == null) { this.model.getCurrentAnimation().reset(); this.model.action = Action.Standing; } this.AI_react(map); this.loc = oldLoc; this.path = null; return; } } (this.loc = oldLoc).setLocation(newLoc); this.exactLoc.setLocation(newLoc); } private static Direction calcDirection(final Point2D.Double p1, final Point2D.Double p2) { final double xDif = p2.x - p1.x; final double yDif = p1.y - p2.y; double angle = Math.atan(yDif / xDif) * 180.0 / 3.141592653589793; if (Double.isNaN(angle)) { return null; } if (xDif < 0.0) { angle += 180.0; } else if (yDif < 0.0) { angle += 360.0; } if (337.5 < angle || angle <= 22.5) { return Direction.East; } if (22.5 < angle && angle <= 67.5) { return Direction.NorthEast; } if (67.5 < angle && angle <= 112.5) { return Direction.North; } if (112.5 < angle && angle <= 157.5) { return Direction.NorthWest; } if (157.5 < angle && angle <= 202.25) { return Direction.West; } if (202.5 < angle && angle <= 247.5) { return Direction.SouthWest; } if (247.5 < angle && angle <= 292.5) { return Direction.South; } if (292.5 < angle && angle <= 337.5) { return Direction.SouthEast; } return null; } @Override public void draw(final Graphics g, final int playerX, final int playerY) { this.model.draw(g, this.loc.x + playerX + this.xOffset, this.loc.y + playerY + this.yOffset); final int x = -40 + this.loc.x + playerX + this.xOffset; final int y = -10 - this.model.getHeight() + this.loc.y + playerY + this.yOffset; Creature.hpBar.draw(g, x, y, x + 80 * this.hitpoints / this.maxHitpoints, y + 10, 0, 0, 80 * this.hitpoints / this.maxHitpoints, 10); if (!this.dead) { g.setColor(Color.black); final Font font12 = new Font("Arial", 0, 12); final FontMetrics metrics = g.getFontMetrics(font12); g.setFont(font12); g.drawString(this.name, this.loc.x + playerX + this.xOffset - metrics.stringWidth(this.name) / 2, -this.model.getHeight() + this.loc.y + playerY + this.yOffset); } } }