class Enemy extends Object {
  float hp, maxHp;
  int flinch;
  String state;
  boolean active;
  int power;
  
  Enemy (int x, int y){
    this.x = x;
    this.y = y;
    active = true;
    flinch = 0;
    power = 1;
  }
  void update(){
    super.update();
  }
  void renderHealthBar(){
    fill(0);
    rect (0,0,100,10);
    fill (255,0,0);
    rect (0,0,100 * hp/maxHp,10);
  }
  void render(){
    if (hp < maxHp) renderHealthBar();
  }
  void takeDamage(float d){
    SE.trigger(SE.damageEnemy);
    hp -=d;
    if (hp < 0) hp = 0;
  }
}


//====================== GHOST =========================


class Ghost extends Enemy {
  int ignoringTime = 150;
  int actionTimer;
  int noticingCooldown;
  
  int facingDirection = 1;
  int takingDamage;
  float speed1, speed2, angle;
  
  float z, vz;
  
  Ghost(int x, int y){
    super(x,y);
    hp = 1;
    state = "idle";
    speed1 = 2.5;
    speed2 = 2.5;
    power = 1;
    
    spriteOffsetX = -ghostIdle[0].width/2;
    spriteOffsetY = -70;
    
    hitBox = new HitBox (-22, -15, 44, 30);
  }
  
  void update(){
    facingDirection = (cos(angle) > 0 ? 1 : -1); //resolver
    
    if (takingDamage > 0) {
      x -= facingDirection * 5;
      takingDamage --;
      if (takingDamage == 0 && hp <= 0){
        active = false;
      }
    }
    else switch (state){
      case "idle":
        actionTimer--;
        noticingCooldown--;
        
        if(noticingCooldown < 0 && dist(x,y,player.x,player.y) < noticing_distance){
          state = "jumping";
          vz = -6;
        }
        else if (actionTimer <=0) {
          state = "walking";
          actionTimer = int(random(100,200));
          angle = atan2(level.getRandomX(20) - y, level.getRandomY(20) - x);
          //angle = random(0, TWO_PI);
        }
        break;
      case "walking":
        actionTimer--;
        noticingCooldown--;
        
        x+=cos(angle)*speed1;
        y+=sin(angle)*speed1;
        
        if(noticingCooldown < 0 && dist(x,y,player.x,player.y) < noticing_distance){
          state = "jumping";
          vz = -6;
        }
        else if (actionTimer <=0 || collided) {
          state = "idle";
          actionTimer = int(random(100,200));
        }
        break;
      case "jumping":
        z += vz;
        vz += 0.6;
        if(z > 0){
          z = 0;
          state = "chasing";
          actionTimer = 100;
        }
        break; 
      case "chasing":
        angle = atan2(player.y - y, player.x - x);
        x+=cos(angle)*speed2;
        y+=sin(angle)*speed2;
        actionTimer--;
        if (actionTimer < 0 && dist(x,y,player.x,player.y) > 100){
          state = "idle";
          actionTimer = int(random(100,200));
          noticingCooldown = ignoringTime;
        }
        break;
    }
    if (flinch > 0){
      flinch--;
    }
    super.update();
  }
  
  void takeDamage(float d){
    super.takeDamage(d);
    takingDamage = 10;
    flinch = enemyFlinchTime;
  }
  
  void render(){
    fill(0);
    noStroke();
    ellipseMode(CENTER);
    ellipse(x,y,20,12);
    
    if (flinch <= 0 || takingDamage > 0 || animation % 2 == 0){
      float jumpAnim = 8 * sin (animation * 0.05);
      if (state.equals("jumping")){
        jumpAnim = z;
      }
      pushMatrix();
      translate(0, jumpAnim);
      
      if (takingDamage > 0) imageX(ghostDamage[0], x + spriteOffsetX, y + spriteOffsetY, (facingDirection < 0));
      else if (state.equals("chasing")) imageX(ghostChasing[0], x + spriteOffsetX, y + spriteOffsetY, (facingDirection < 0));
      else imageX(ghostIdle[0], x + spriteOffsetX, y + spriteOffsetY, (facingDirection < 0));
      popMatrix();
    }
    //hitBox.render();
    super.render();
  }
}

//====================== SKULL =========================


class Skull extends Enemy {
  int facingDirection = 1;
  int takingDamage;
  float speed, angle;
  
  Skull(int x, int y){
    super(x,y);
    hp = 1;
    state = "idle";
    speed = 3;
    speedX = speed;
    speedY = speed;
    power = 1;
    
    spriteOffsetX = -skullIdle[0].width/2;
    spriteOffsetY = -120;
    
    hitBox = new HitBox (-30, -15, 60, 30);
  }
  
  void update(){
    facingDirection = (speedX > 0 ? 1 : -1); //resolver
    
    if (takingDamage > 0) {
      x -= facingDirection * 5;
      takingDamage --;
      if (takingDamage == 0 && hp <= 0){
        active = false;
      }
    }
    else {
      x += speedX;
      y += speedY;
    }
    if (flinch > 0){
      flinch--;
    }
    super.update();
  }
  
  void takeDamage(float d){
    super.takeDamage(d);
    takingDamage = 10;
    flinch = enemyFlinchTime;
  }
  
  void render(){
    fill(0);
    noStroke();
    ellipseMode(CENTER);
    ellipse(x,y,20,12);
    
    if (flinch <= 0 || takingDamage > 0 || animation % 2 == 0){
      float jumpAnim = 8 * sin (animation * 0.05);
      pushMatrix();
      translate(0, jumpAnim);
      
      if (takingDamage > 0) imageX(skullDamage[0], x + spriteOffsetX, y + spriteOffsetY, (facingDirection < 0));
      else imageX(skullIdle[animation/6 % 4], x + spriteOffsetX, y + spriteOffsetY, (facingDirection < 0));
      popMatrix();
    }
    //hitBox.render();
    super.render();
  }
}

//====================== BIG GHOST =========================


class BigGhost extends Enemy {
  int ignoringTime = 75;
  int actionTimer;
  int noticingCooldown;
  
  int facingDirection = 1;
  int takingDamage;
  float speed1, speed2, angle;
  
  float z, vz;
  
  BigGhost(int x, int y){
    super(x,y);
    hp = 2;
    state = "idle";
    speed1 = 2.5;
    speed2 = 2.5;
    power = 1;
    
    spriteOffsetX = -bigGhostIdle[0].width/2;
    spriteOffsetY = -90;
    
    hitBox = new HitBox (-22, -15, 44, 30);
  }
  
  void update(){
    facingDirection = (cos(angle) > 0 ? 1 : -1); //resolver
    
    if (takingDamage > 0) {
      x -= facingDirection * 5;
      takingDamage --;
      if (takingDamage == 0 && hp <= 0){
        active = false;
      }
    }
    else switch (state){
      case "idle":
        actionTimer--;
        noticingCooldown--;
        
        if(noticingCooldown < 0 && dist(x,y,player.x,player.y) < noticing_distance){
          state = "jumping";
          vz = -6;
        }
        else if (actionTimer <=0) {
          state = "walking";
          actionTimer = int(random(100,200));
          angle = atan2(level.getRandomX(20) - y, level.getRandomY(20) - x);
          //angle = random(0, TWO_PI);
        }
        break;
      case "walking":
        actionTimer--;
        noticingCooldown--;
        
        x+=cos(angle)*speed1;
        y+=sin(angle)*speed1;
        
        if(noticingCooldown < 0 && dist(x,y,player.x,player.y) < noticing_distance){
          state = "jumping";
          vz = -6;
        }
        else if (actionTimer <=0 || collided) {
          state = "idle";
          actionTimer = int(random(100,200));
        }
        break;
      case "jumping":
        z += vz;
        vz += 0.6;
        if(z > 0){
          z = 0;
          state = "chasing";
          actionTimer = 100;
        }
        break; 
      case "chasing":
        angle = atan2(player.y - y, player.x - x);
        x+=cos(angle)*speed2;
        y+=sin(angle)*speed2;
        actionTimer--;
        if (actionTimer < 0 && dist(x,y,player.x,player.y) > 100){
          state = "idle";
          actionTimer = int(random(100,200));
          noticingCooldown = ignoringTime;
        }
        break;
    }
    if (flinch > 0){
      flinch--;
    }
    super.update();
  }
  
  void takeDamage(float d){
    super.takeDamage(d);
    takingDamage = 10;
    flinch = enemyFlinchTime;
  }
  
  void render(){
    fill(0);
    noStroke();
    ellipseMode(CENTER);
    ellipse(x,y,40,12); //elipse da sombra::????
    
    if (flinch <= 0 || takingDamage > 0 || animation % 2 == 0){
      float jumpAnim = 8 * sin (animation * 0.05);
      if (state.equals("jumping")){
        jumpAnim = z;
      }
      pushMatrix();
      translate(0, jumpAnim);
      
      if (takingDamage > 0) imageX(bigGhostDamage[0], x + spriteOffsetX, y + spriteOffsetY, (facingDirection < 0));
      else if (state.equals("chasing")) imageX(bigGhostChasing[0], x + spriteOffsetX, y + spriteOffsetY, (facingDirection < 0));
      else imageX(bigGhostIdle[0], x + spriteOffsetX, y + spriteOffsetY, (facingDirection < 0));
      popMatrix();
    }
    //hitBox.render();
    super.render();
  }
}

//====================== BIG GHOST =========================


class KingGhost extends Enemy {
  int ignoringTime = 75;
  int actionTimer;
  int noticingCooldown;
  
  int facingDirection = 1;
  int takingDamage;
  float speed1, speed2, angle;
  
  float z, vz;
  
  KingGhost(int x, int y){
    super(x,y);
    hp = 3;
    state = "idle";
    speed1 = 2.7;
    speed2 = 2.7;
    power = 1;
    
    spriteOffsetX = -kingGhostIdle[0].width/2;
    spriteOffsetY = -130;
    
    hitBox = new HitBox (-30, -15, 60, 30);
  }
  
  void update(){
    facingDirection = (cos(angle) > 0 ? 1 : -1); //resolver
    
    if (takingDamage > 0) {
      x -= facingDirection * 5;
      takingDamage --;
      if (takingDamage == 0 && hp <= 0){
        active = false;
      }
    }
    else switch (state){
      case "idle":
        actionTimer--;
        noticingCooldown--;
        
        if(noticingCooldown < 0 && dist(x,y,player.x,player.y) < noticing_distance){
          state = "jumping";
          vz = -6;
        }
        else if (actionTimer <=0) {
          state = "walking";
          actionTimer = int(random(100,200));
          angle = atan2(level.getRandomX(20) - y, level.getRandomY(20) - x);
          //angle = random(0, TWO_PI);
        }
        break;
      case "walking":
        actionTimer--;
        noticingCooldown--;
        
        x+=cos(angle)*speed1;
        y+=sin(angle)*speed1;
        
        if(noticingCooldown < 0 && dist(x,y,player.x,player.y) < noticing_distance){
          state = "jumping";
          vz = -6;
        }
        else if (actionTimer <=0 || collided) {
          state = "idle";
          actionTimer = int(random(100,200));
        }
        break;
      case "jumping":
        z += vz;
        vz += 0.6;
        if(z > 0){
          z = 0;
          state = "chasing";
          actionTimer = 160;
        }
        break; 
      case "chasing":
        angle = atan2(player.y - y, player.x - x);
        x+=cos(angle)*speed2;
        y+=sin(angle)*speed2;
        actionTimer--;
        if (actionTimer < 0 && dist(x,y,player.x,player.y) > 100){
          state = "idle";
          actionTimer = int(random(100,200));
          noticingCooldown = ignoringTime;
        }
        break;
    }
    if (flinch > 0){
      flinch--;
    }
    super.update();
  }
  
  void takeDamage(float d){
    super.takeDamage(d);
    takingDamage = 10;
    flinch = enemyFlinchTime;
  }
  
  void render(){
    fill(0);
    noStroke();
    ellipseMode(CENTER);
    ellipse(x,y,60,20); //elipse da sombra::????
    
    if (flinch <= 0 || takingDamage > 0 || animation % 2 == 0){
      float jumpAnim = 8 * sin (animation * 0.05);
      if (state.equals("jumping")){
        jumpAnim = z;
      }
      pushMatrix();
      translate(0, jumpAnim);
      
      if (takingDamage > 0) imageX(kingGhostDamage[0], x + spriteOffsetX, y + spriteOffsetY, (facingDirection < 0));
      else if (state.equals("chasing")) imageX(kingGhostChasing[animation/6 % 3], x + spriteOffsetX, y + spriteOffsetY, (facingDirection < 0));
      else imageX(kingGhostIdle[animation/6 % 3], x + spriteOffsetX, y + spriteOffsetY, (facingDirection < 0));
      popMatrix();
    }
    //hitBox.render();
    super.render();
  }
}