package main;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;
import javax.imageio.ImageIO;

import gamegui.Animation;

public class Creature implements Comparable<Creature> {

  public int passive;
  public int thorns;
  public int confused;
  public int sand;

  protected String name;
  protected CreatureType type;
  protected Model model;
  protected int level;
  protected Point loc;
  protected int[] attributes;  
  protected int hitpoints;
  protected int manapoints;
  protected int maxHitpoints;
  protected int maxManapoints;
  protected int experience;
  protected EquippedWeapon weapon;
  protected EquippedWeapon spell;

  private Point target;
  private Creature enemyTarget;
  private int speed;
  private long lastMoved;
  private long lastAttacked;
  private LinkedList<ItemDrop> drops;
  private LinkedList<EffectTimer> effectTimers;
  private boolean disabled;
  private SpawnPoint spawnPoint;
  private boolean dying;

  public Creature() {
    this.name = "";
    this.loc = new Point(0, 0);
    this.target = this.loc;
    this.attributes = new int[4];
    this.experience = 0;
    this.weapon = null;
    this.spell = null;
    this.drops = new LinkedList<ItemDrop>();
    this.effectTimers = new LinkedList<EffectTimer>();
    this.disabled = false;
    this.spawnPoint = null;
    this.passive = 0;
    this.thorns = 0;
    this.confused = 0;
    this.sand = 0;
    this.dying = false;
  }

  public Creature(String name, CreatureType type) {
    this.name = name;
    this.type = type;
    this.loc = new Point(0, 0);
    this.target = this.loc;
    this.attributes = new int[4];
    this.experience = 0;
    this.weapon = null;
    this.spell = null;
    this.drops = new LinkedList<ItemDrop>();
    this.effectTimers = new LinkedList<EffectTimer>();
    this.disabled = false;
    this.spawnPoint = null;
    this.passive = 0;
    this.thorns = 0;
    this.confused = 0;
    this.sand = 0;
    this.dying = false;
  }

  public Creature(Creature cr) {
    this.name = cr.name;
    this.type = cr.type;
    this.model = new Model(cr.model);
    this.level = cr.level;
    this.loc = new Point(cr.loc);
    this.target = cr.target;
    this.speed = cr.speed;
    this.lastMoved = cr.lastMoved;
    this.lastAttacked = cr.lastAttacked;
    this.attributes = (int[])cr.attributes.clone();
    this.hitpoints = cr.hitpoints;
    this.manapoints = cr.manapoints;
    this.maxHitpoints = cr.maxHitpoints;
    this.maxManapoints = cr.maxManapoints;
    this.experience = cr.experience;
    this.weapon = cr.weapon.copy((Point)null);
    if (cr.spell != null)
      this.spell = cr.spell.copy((Point)null); 
    this.drops = cr.drops;
    this.effectTimers = new LinkedList<EffectTimer>(cr.effectTimers);
    this.disabled = cr.disabled;
    this.spawnPoint = null;
    this.passive = cr.passive;
    this.thorns = cr.thorns;
    this.confused = cr.confused;
    this.sand = cr.sand;
    this.dying = cr.dying;
  }

  public Creature copy() {
    return new Creature(this);
  }

  public void setDying(boolean dying) {
    if (!this.model.hasDeath())
      return; 
    if (dying) {
      this.model.setAction(Action.Dying);
    } else {
      this.model.getAnimation(Direction.West, Action.Dying).reset();
    }
    this.dying = dying;
  }

  public boolean isDying() {
    return this.dying;
  }

  public void checkTimedEffects() {
    Iterator<EffectTimer> iter = this.effectTimers.iterator();
    while (iter.hasNext()) {
      EffectTimer cur = iter.next();
      if (cur.expired()) {
        cur.getEffect().cancelEffect(this);
        iter.remove();
      }
    }
  }

  public void addEffect(TimedEffect e) {
    this.effectTimers.add(new EffectTimer(e, e.getDuration()));
  }

  public Point move() {
    Point newLoc;
    double dist = (this.speed * (System.currentTimeMillis() - this.lastMoved) / 1000L);
    if (this.lastMoved == 0L) {
      dist = 0.0D;
    }
    if (this.enemyTarget != null) {
      this.target = this.enemyTarget.loc;
    }
    this.lastMoved = System.currentTimeMillis();
    if (Point.dist(this.loc, this.target) <= dist) {
      newLoc = this.target;
      if (this.model.getAction() != Action.Attacking) {
        this.model.setAction(Action.Standing);
      }
    } else {
      if (this.model.getAction() != Action.Attacking) {
        this.model.setAction(Action.Walking);
      }
      int xDif = (int)(Point.xDif(this.loc, this.target) * dist / Point.dist(this.loc, this.target));
      int yDif = (int)(Point.yDif(this.loc, this.target) * dist / Point.dist(this.loc, this.target));
      newLoc = new Point(this.loc.getX(), this.loc.getXMin() + xDif, this.loc.getY(), this.loc.getYMin() + yDif);
      newLoc.setX(newLoc.getX() + newLoc.getXMin() / 100);
      newLoc.setXMin(newLoc.getXMin() % 100);
      newLoc.setY(newLoc.getY() + newLoc.getYMin() / 100);
      newLoc.setYMin(newLoc.getYMin() % 100);
      if (newLoc.getXMin() < 0) {
        newLoc.setX(newLoc.getX() - 1);
        newLoc.setXMin(newLoc.getXMin() + 100);
      } else if (newLoc.getYMin() < 0) {
        newLoc.setY(newLoc.getY() - 1);
        newLoc.setYMin(newLoc.getYMin() + 100);
      }
      this.model.setDirection(calcDirection());
    }
    return newLoc;
  }

  private Direction calcDirection() {
    Direction dir;
    int xDif2 = Point.xDif(this.loc, this.target);
    int yDif2 = Point.yDif(this.target, this.loc);
    double angle = 1.5707963267948966D;
    if (xDif2 == 0) {
      if (yDif2 != 0) {
        angle *= Math.abs(yDif2 / yDif2);
      }
    } else {
      angle = Math.atan(yDif2 / xDif2);
    }
    if (angle >= 0.7853981633974483D) {
      dir = Direction.North;
    } else if (-0.7853981633974483D <= angle && angle <= 0.7853981633974483D) {
      dir = Direction.East;
    } else {
      dir = Direction.South;
    }
    if (xDif2 < 0)
      switch (dir) {
        case North:
          dir = Direction.South;
          break;
        case South:
          dir = Direction.North;
          break;
        case East:
          dir = Direction.West;
          break;
      } 
    return dir;
  }

  public Projectile attack(Creature enemy, AttackType attType) {
    Weapon weap = selectWeapon(attType);
    if (System.currentTimeMillis() - this.lastAttacked >= (weap.getAttackSpeed() * 100) && !this.disabled) {
      this.lastAttacked = System.currentTimeMillis();
      Point oldTarget = this.target;
      this.target = enemy.getLoc();
      this.model.setDirection(calcDirection());
      this.target = oldTarget;
      if (attType != AttackType.Spell) {
        this.model.setAction(Action.Attacking);
        this.model.getAnimation(this.model.getDirection(), this.model.getAction()).reset();
      }
      if (weap.getType() == ItemType.RangedWeapon || weap.getType() == ItemType.Spell) {
        Point loc = new Point(this.loc);
        loc.setY(loc.getY() - 55);
        return weap.spawnProjectile(loc, enemy.getLoc());
      }
      weap.applyContactEffects(enemy);
    }
    return null;
  }

  public Projectile attack(Point targ, AttackType attType) {
    Weapon weap = selectWeapon(attType);
    if ((System.currentTimeMillis() - this.lastAttacked) / 100L >= weap.getAttackSpeed() && !this.disabled) {
      this.lastAttacked = System.currentTimeMillis();
      Point oldTarget = this.target;
      this.target = targ;
      this.model.setDirection(calcDirection());
      this.target = oldTarget;
      if (attType != AttackType.Spell) {
        this.model.setAction(Action.Attacking);
        this.model.getAnimation(this.model.getDirection(), this.model.getAction()).reset();
      }
      if (weap.getType() == ItemType.RangedWeapon || weap.getType() == ItemType.Spell) {
        Point loc = new Point(this.loc);
        loc.setY(loc.getY() - 30);
        return weap.spawnProjectile(loc, targ);
      }
    }
    return null;
  }

  private Weapon selectWeapon(AttackType attType) {
    switch (attType) {
      case Weapon:
        return this.weapon;
      case Spell:
        return this.spell;
    }
    return this.weapon;
  }

  public void addDrop(ItemDrop item) {
    this.drops.add(item);
  }

  public LinkedList<ItemDrop> getDrops() {
    return this.drops;
  }

  public LinkedList<Item> spawnDrops() {
    LinkedList<Item> newDrops = new LinkedList<Item>();
    Iterator<ItemDrop> iter = this.drops.iterator();
    Random gen = new Random();
    while (iter.hasNext()) {
      ItemDrop cur = iter.next();
      if (gen.nextDouble() <= cur.getDropChance()) {
        newDrops.add(cur.getItem());
      }
    }
    return newDrops;
  }

  public void draw(Graphics g, int playerX, int playerY) {
    if (this.passive > 0) {
      g.drawImage(LostHavenRPG.passiveAura, 375 + this.loc.getX() - playerX, 300 - this.model.getHeight() + this.loc.getY() - playerY, null);
    }
    if (this.thorns > 0) {
      g.drawImage(LostHavenRPG.thornsAura, 375 + this.loc.getX() - playerX, 300 - this.model.getHeight() + this.loc.getY() - playerY, null);
    }
    this.model.draw(g, 400 + this.loc.getX() - playerX, 300 + this.loc.getY() - playerY);
    if (this.confused > 0) {
      g.drawImage(LostHavenRPG.confuseAura, 375 + this.loc.getX() - playerX, 300 - this.model.getHeight() + this.loc.getY() - playerY, null);
    }
    if (this.sand > 0) {
      g.drawImage(LostHavenRPG.sandAura, 375 + this.loc.getX() - playerX, 300 - this.model.getHeight() + this.loc.getY() - playerY, null);
    }
    g.setColor(Color.red);
    g.fillRect(360 + this.loc.getX() - playerX, 290 - this.model.getHeight() + this.loc.getY() - playerY, 80 * this.hitpoints / this.maxHitpoints, 10);
    g.setColor(Color.black);
    Font font12 = new Font("Arial", 0, 12);
    FontMetrics metrics = g.getFontMetrics(font12);
    g.setFont(font12);
    g.drawString(this.name, 400 + this.loc.getX() - playerX - metrics.stringWidth(this.name) / 2, 300 - this.model.getHeight() + this.loc.getY() - playerY);
  }

  public void save(PrintWriter out) {
    out.println(this.type);
    if (this.spawnPoint == null) {
      out.println(-1);
    } else {
      out.println(this.spawnPoint.idNum);
    }
    out.println(String.valueOf(this.loc.getX()) + "," + this.loc.getY());
    out.println(this.model.getDirection());
    out.println(this.model.getAction());
    out.println(this.hitpoints);
    out.println(this.manapoints);
    out.println(this.passive);
    out.println(this.thorns);
    out.println(this.confused);
    out.println(this.sand);
    if (this.weapon == null) {
      out.println("None");
    } else {
      out.println(this.weapon.getName());
    }
  }

  public static Creature loadTemplate(BufferedReader in) {
    Creature cr = new Creature();
    BufferedImage[] imgProj = new BufferedImage[8];
    try {
      cr.name = in.readLine();
      cr.type = CreatureType.valueOf(cr.name);
      if (cr.type == CreatureType.Player) {
        cr = Player.loadTemplate(in);
      }
      cr.setSpeed(Integer.parseInt(in.readLine()));
      cr.setAttribute(Attribute.Strength, Integer.parseInt(in.readLine()));
      cr.setAttribute(Attribute.Dexterity, Integer.parseInt(in.readLine()));
      cr.setAttribute(Attribute.Constitution, Integer.parseInt(in.readLine()));
      cr.setAttribute(Attribute.Wisdom, Integer.parseInt(in.readLine()));
      ItemType wType = ItemType.valueOf(in.readLine());
      if (wType == ItemType.RangedWeapon) {
        imgProj = LostHavenRPG.imgBow;
      } else if (wType == ItemType.Spell) {
        imgProj[0] = ImageIO.read(cr.getClass().getResource("/images/" + cr.type.toString() + "/proj.png"));
        imgProj[1] = ImageIO.read(cr.getClass().getResource("/images/" + cr.type.toString() + "/proj.png"));
        imgProj[2] = ImageIO.read(cr.getClass().getResource("/images/" + cr.type.toString() + "/proj.png"));
        imgProj[3] = ImageIO.read(cr.getClass().getResource("/images/" + cr.type.toString() + "/proj.png"));
        imgProj[4] = ImageIO.read(cr.getClass().getResource("/images/" + cr.type.toString() + "/proj.png"));
        imgProj[5] = ImageIO.read(cr.getClass().getResource("/images/" + cr.type.toString() + "/proj.png"));
        imgProj[6] = ImageIO.read(cr.getClass().getResource("/images/" + cr.type.toString() + "/proj.png"));
        imgProj[7] = ImageIO.read(cr.getClass().getResource("/images/" + cr.type.toString() + "/proj.png"));
      }
      cr.model = cr.loadModel(cr.type.toString());
      cr.setWeapon(new Weapon("None", wType, "Dagger.png", imgProj, 10, Integer.parseInt(in.readLine()), Integer.parseInt(in.readLine())));
      cr.setExperience(Integer.parseInt(in.readLine()));
    } catch (IOException ioe) {
      ioe.printStackTrace();
    }
    return cr;
  }

  public Model loadModel(String folder) {
    boolean noAnims = false;
    Animation anmStandN = new Animation("north", 0, 0, 40, 60, 300, true);
    Animation anmStandS = new Animation("south", 0, 0, 40, 60, 300, true);
    Animation anmStandE = new Animation("east", 0, 0, 40, 60, 300, true);
    Animation anmStandW = new Animation("west", 0, 0, 40, 60, 300, true);
    Animation anmWalkN = new Animation("north", 0, 0, 40, 60, 300, true);
    Animation anmWalkS = new Animation("south", 0, 0, 40, 60, 300, true);
    Animation anmWalkE = new Animation("east", 0, 0, 40, 60, 300, true);
    Animation anmWalkW = new Animation("west", 0, 0, 40, 60, 300, true);
    Animation anmAttackN = new Animation("north", 0, 0, 40, 60, 500, false);
    Animation anmAttackS = new Animation("south", 0, 0, 40, 60, 500, false);
    Animation anmAttackE = new Animation("east", 0, 0, 40, 60, 500, false);
    Animation anmAttackW = new Animation("west", 0, 0, 40, 60, 500, false);
    Animation anmDeath = new Animation("west", 0, 0, 40, 60, 1000, false);
    BufferedImage walkN = null;
    BufferedImage walkS = null;
    BufferedImage walkE = null;
    BufferedImage walkW = null;
    boolean hasDeathAnim = (getClass().getResource("/images/" + folder + "/Death1.png") != null);
    try {
      if (getClass().getResource("/images/" + folder + "/WalkN.png") != null) {
        walkN = ImageIO.read(getClass().getResource("/images/" + folder + "/WalkN.png"));
        anmWalkN.addFrame(walkN);
        walkS = ImageIO.read(getClass().getResource("/images/" + folder + "/WalkS.png"));
        anmWalkS.addFrame(walkS);
        walkE = ImageIO.read(getClass().getResource("/images/" + folder + "/WalkE.png"));
        anmWalkE.addFrame(walkE);
        walkW = ImageIO.read(getClass().getResource("/images/" + folder + "/WalkW.png"));
        anmWalkW.addFrame(walkW);
      } else if (getClass().getResource("/images/" + folder + "/WalkN1.png") != null) {
        walkN = ImageIO.read(getClass().getResource("/images/" + folder + "/WalkN1.png"));
        anmWalkN.addFrame(walkN);
        anmWalkN.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/WalkN2.png")));
        walkS = ImageIO.read(getClass().getResource("/images/" + folder + "/WalkS1.png"));
        anmWalkS.addFrame(walkS);
        anmWalkS.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/WalkS2.png")));
        walkE = ImageIO.read(getClass().getResource("/images/" + folder + "/WalkE1.png"));
        anmWalkE.addFrame(walkE);
        anmWalkE.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/WalkE2.png")));
        walkW = ImageIO.read(getClass().getResource("/images/" + folder + "/WalkW1.png"));
        anmWalkW.addFrame(walkW);
        anmWalkW.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/WalkW2.png")));
      } else {
        noAnims = true;
        anmStandN.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/" + folder + ".png")));
        anmStandS.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/" + folder + ".png")));
        anmStandE.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/" + folder + ".png")));
        anmStandW.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/" + folder + ".png")));
        anmWalkN.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/" + folder + ".png")));
        anmWalkN.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/" + folder + ".png")));
        anmWalkS.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/" + folder + ".png")));
        anmWalkS.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/" + folder + ".png")));
        anmWalkE.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/" + folder + ".png")));
        anmWalkE.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/" + folder + ".png")));
        anmWalkW.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/" + folder + ".png")));
        anmWalkW.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/" + folder + ".png")));
        anmAttackN.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/" + folder + ".png")));
        anmAttackS.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/" + folder + ".png")));
        anmAttackE.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/" + folder + ".png")));
        anmAttackW.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/" + folder + ".png")));
      }
      if (!noAnims) {
        BufferedImage standN, standS, standE, standW;
        if (getClass().getResource("/images/" + folder + "/StandN.png") == null) {
          standN = walkN;
          standS = walkS;
          standE = walkE;
          standW = walkW;
        } else {
          standN = ImageIO.read(getClass().getResource("/images/" + folder + "/StandN.png"));
          standS = ImageIO.read(getClass().getResource("/images/" + folder + "/StandS.png"));
          standE = ImageIO.read(getClass().getResource("/images/" + folder + "/StandE.png"));
          standW = ImageIO.read(getClass().getResource("/images/" + folder + "/StandW.png"));
          anmWalkN = new Animation("north", 0, 0, 40, 60, 150, true);
          anmWalkS = new Animation("south", 0, 0, 40, 60, 150, true);
          anmWalkE = new Animation("east", 0, 0, 40, 60, 150, true);
          anmWalkW = new Animation("west", 0, 0, 40, 60, 150, true);
          anmWalkN.addFrame(walkN);
          anmWalkN.addFrame(standN);
          anmWalkN.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/WalkN2.png")));
          anmWalkN.addFrame(standN);
          anmWalkS.addFrame(walkS);
          anmWalkS.addFrame(standS);
          anmWalkS.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/WalkS2.png")));
          anmWalkS.addFrame(standS);
          anmWalkE.addFrame(walkE);
          anmWalkE.addFrame(standE);
          anmWalkE.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/WalkE2.png")));
          anmWalkE.addFrame(standE);
          anmWalkW.addFrame(walkW);
          anmWalkW.addFrame(standW);
          anmWalkW.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/WalkW2.png")));
          anmWalkW.addFrame(standW);
        } 
        anmStandN.addFrame(standN);
        anmStandS.addFrame(standS);
        anmStandE.addFrame(standE);
        anmStandW.addFrame(standW);
        if (getClass().getResource("/images/" + folder + "/AttackN.png") != null) {
          anmAttackN.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/AttackN.png")));
          anmAttackN.addFrame(standN);
          anmAttackS.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/AttackS.png")));
          anmAttackS.addFrame(standS);
          anmAttackE.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/AttackE.png")));
          anmAttackE.addFrame(standE);
          anmAttackW.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/AttackW.png")));
          anmAttackW.addFrame(standW);
        } else if (getClass().getResource("/images/" + folder + "/AttackN1.png") != null) {
          anmAttackN.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/AttackN1.png")));
          anmAttackN.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/AttackN2.png")));
          anmAttackS.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/AttackS1.png")));
          anmAttackS.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/AttackS2.png")));
          anmAttackE.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/AttackE1.png")));
          anmAttackE.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/AttackE2.png")));
          anmAttackW.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/AttackW1.png")));
          anmAttackW.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/AttackW2.png")));
        } else {
          anmAttackN.addFrame(standN);
          anmAttackS.addFrame(standS);
          anmAttackE.addFrame(standE);
          anmAttackW.addFrame(standW);
        } 
        if (hasDeathAnim) {
          anmDeath.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/Death1.png")));
          anmDeath.addFrame(ImageIO.read(getClass().getResource("/images/" + folder + "/Death2.png")));
        } 
      }
    } catch (IOException ioe) {
      ioe.printStackTrace();
    }
    Model model = new Model(hasDeathAnim);
    model.addAnimation(Direction.North, Action.Standing, anmStandN);
    model.addAnimation(Direction.South, Action.Standing, anmStandS);
    model.addAnimation(Direction.East, Action.Standing, anmStandE);
    model.addAnimation(Direction.West, Action.Standing, anmStandW);
    model.addAnimation(Direction.North, Action.Walking, anmWalkN);
    model.addAnimation(Direction.South, Action.Walking, anmWalkS);
    model.addAnimation(Direction.East, Action.Walking, anmWalkE);
    model.addAnimation(Direction.West, Action.Walking, anmWalkW);
    model.addAnimation(Direction.North, Action.Attacking, anmAttackN);
    model.addAnimation(Direction.South, Action.Attacking, anmAttackS);
    model.addAnimation(Direction.East, Action.Attacking, anmAttackE);
    model.addAnimation(Direction.West, Action.Attacking, anmAttackW);
    if (hasDeathAnim) {
      model.addAnimation(Direction.West, Action.Dying, anmDeath);
    }
    return model;
  }

  public void load(BufferedReader in) {
    try {
      this.spawnPoint = LostHavenRPG.getSpawnPoint(Integer.parseInt(in.readLine()));
      if (this.spawnPoint != null) {
        this.spawnPoint.numSpawns++;
      } 
      String strLoc = in.readLine();
      getLoc().setX(Integer.valueOf(strLoc.substring(0, strLoc.indexOf(","))).intValue());
      getLoc().setY(Integer.valueOf(strLoc.substring(strLoc.indexOf(",") + 1)).intValue());
      getModel().setDirection(Direction.valueOf(in.readLine()));
      getModel().setAction(Action.valueOf(in.readLine()));
      setHitpoints(Integer.valueOf(in.readLine()).intValue());
      setManapoints(Integer.valueOf(in.readLine()).intValue());
      this.passive = Integer.valueOf(in.readLine()).intValue();
      this.thorns = Integer.valueOf(in.readLine()).intValue();
      this.confused = Integer.valueOf(in.readLine()).intValue();
      this.sand = Integer.valueOf(in.readLine()).intValue();
      String strWeapon = in.readLine();
      if (!strWeapon.equals("None")) {
        setWeapon((Weapon)LostHavenRPG.items.get(strWeapon));
      }
    } catch (IOException ioe) {
      ioe.printStackTrace();
    }
  }

  protected int attributeIndex(Attribute attribute) {
    switch (attribute) {
      case Strength:
        return 0;
      case Dexterity:
        return 1;
      case Constitution:
        return 2;
      case Wisdom:
        return 3;
    }
    return -1;
  }

  public int getAttribute(Attribute attribute) {
    return this.attributes[attributeIndex(attribute)];
  }

  public void setAttribute(Attribute attribute, int num) {
    this.attributes[attributeIndex(attribute)] = num;
    updateStats();
  }

  private void updateStats() {
    this.hitpoints = 2 * this.attributes[2];
    this.maxHitpoints = 2 * this.attributes[2];
    this.manapoints = 2 * this.attributes[3];
    this.maxManapoints = 2 * this.attributes[3];
  }

  public Creature getEnemyTarget() {
    return this.enemyTarget;
  }

  public int getExperience() {
    return this.experience;
  }

  public int getHitpoints() {
    return this.hitpoints;
  }

  public Model getModel() {
    return this.model;
  }

  public long getLastAttacked() {
    return this.lastAttacked;
  }

  public long getLastMoved() {
    return this.lastMoved;
  }

  public int getLevel() {
    return this.level;
  }

  public Point getLoc() {
    return this.loc;
  }

  public int getManapoints() {
    return this.manapoints;
  }

  public int getMaxHitpoints() {
    return this.maxHitpoints;
  }

  public int getMaxManapoints() {
    return this.maxManapoints;
  }

  public String getName() {
    return this.name;
  }

  public int getSpeed() {
    return this.speed;
  }

  public Point getTarget() {
    return this.target;
  }

  public CreatureType getType() {
    return this.type;
  }

  public EquippedWeapon getWeapon() {
    return this.weapon;
  }

  public EquippedWeapon getSpell() {
    return this.spell;
  }

  public void setEnemyTarget(Creature enemyTarget) {
    this.enemyTarget = enemyTarget;
  }

  public void setExperience(int experience) {
    this.experience = experience;
  }

  public void setHitpoints(int hitpoints) {
    if (hitpoints > 0) {
      this.hitpoints = hitpoints;
    } else {
      this.hitpoints = 0;
    }
  }

  public void setModel(Model model) {
    this.model = model;
  }

  public void setLastAttacked(long lastAttacked) {
    this.lastAttacked = lastAttacked;
  }

  public void setLastMoved(long lastMoved) {
    this.lastMoved = lastMoved;
  }

  public void setLevel(int level) {
    this.level = level;
  }

  public void setLoc(Point loc) {
    this.loc = loc;
  }

  public void setManapoints(int manapoints) {
    if (manapoints > 0) {
      this.manapoints = manapoints;
    } else {
      this.manapoints = 0;
    }
  }

  public void setMaxHitpoints(int maxHitpoints) {
    this.maxHitpoints = maxHitpoints;
  }

  public void setMaxManapoints(int maxManapoints) {
    this.maxManapoints = maxManapoints;
  }

  public void setName(String name) {
    this.name = name;
  }

  public void setSpeed(int speed) {
    this.speed = speed;
  }

  public void setTarget(Point target) {
    this.target = target;
  }

  public void setType(CreatureType type) {
    this.type = type;
  }

  public void setWeapon(Weapon weapon) {
    this.weapon = new EquippedWeapon(this, weapon);
    this.weapon.update();
    (this.model.getAnimation(Direction.North, Action.Attacking)).drawInterval = (this.weapon.getAttackSpeed() * 100 / (this.model.getAnimation(Direction.North, Action.Attacking)).frames.size());
    (this.model.getAnimation(Direction.South, Action.Attacking)).drawInterval = (this.weapon.getAttackSpeed() * 100 / (this.model.getAnimation(Direction.South, Action.Attacking)).frames.size());
    (this.model.getAnimation(Direction.East, Action.Attacking)).drawInterval = (this.weapon.getAttackSpeed() * 100 / (this.model.getAnimation(Direction.East, Action.Attacking)).frames.size());
    (this.model.getAnimation(Direction.West, Action.Attacking)).drawInterval = (this.weapon.getAttackSpeed() * 100 / (this.model.getAnimation(Direction.West, Action.Attacking)).frames.size());
  }

  public void setSpell(Weapon spell) {
    this.spell = new EquippedWeapon(this, spell);
    this.spell.update();
  }

  public SpawnPoint getSpawnPoint() {
    return this.spawnPoint;
  }

  public void setSpawnPoint(SpawnPoint sp) {
    this.spawnPoint = sp;
  }

  public boolean farFromSpawnPoint() {
    if (this.spawnPoint == null)
      return false; 
    return (Point.dist(this.spawnPoint.getLoc(), this.loc) > 800.0D);
  }

  public boolean closerToSpawnPoint(Point newLoc) {
    if (this.spawnPoint == null)
      return false; 
    return (Point.dist(this.spawnPoint.getLoc(), this.loc) >= Point.dist(this.spawnPoint.getLoc(), newLoc));
  }

  public void disable() {
    this.disabled = true;
  }

  public void enable() {
    this.disabled = false;
  }

  public String toString() {
    return this.name;
  }

  public int compareTo(Creature c) {
    return 0;
  }
}
