#include "monsters"
#include "../weapons/projectile"
#include "../items"

const string Q1_QUADER_MODEL = "models/comover/army.mdl";

const string Q1_QUADER_IDLE  = "cmv/army/idle.wav";
const string Q1_QUADER_SIGHT = "cmv/army/sight.wav";
const array<string> Q1_QUADER_PAIN = {
  "cmv/army/pain1.wav",
  "cmv/army/pain2.wav"
};
const string Q1_QUADER_DEATH = "cmv/army/death.wav";
const string Q1_QUADER_SHOOT = "cmv/army/shoot.wav";
const string Q1_QUADER_QUAD = "cmv/quad_s.wav";

enum Q1_QUADER_EVENTS {
  QUADER_END_ATTACK = 1,
  QUADER_DROP_BACKPACK = 2,
  QUADER_SHOOT = 3,
  QUADER_IDLE_SOUND = 4
}

class monster_qquader : ScriptBaseMonsterEntity, monster_qgeneric {
  void Spawn() {
    Precache();

    g_EntityFuncs.SetModel(self, Q1_QUADER_MODEL);
    self.m_bloodColor = BLOOD_COLOR_RED;

    self.pev.health = 300;
    self.pev.solid = SOLID_SLIDEBOX;
    self.pev.movetype = MOVETYPE_STEP;
    g_EntityFuncs.SetSize(self.pev, Vector(-16, -16, -24), Vector(16, 16, 40));

    set_user_rendering(self, kRenderFxGlowShell, 0, 0, 255, kRenderNormal, 25);

    self.StartMonster();
    self.m_MonsterState = MONSTERSTATE_NONE;

    self.m_FormattedName = "Quader Grunt";

    self.pev.pain_finished = 0.0;
    m_iGibHealth = -200;

    WalkMonsterInit();
  }

  void Precache() {
    g_Game.PrecacheModel(Q1_QUADER_MODEL);

    g_SoundSystem.PrecacheSound(Q1_QUADER_IDLE);
    g_SoundSystem.PrecacheSound(Q1_QUADER_SIGHT);
    g_SoundSystem.PrecacheSound(Q1_QUADER_DEATH);
    g_SoundSystem.PrecacheSound(Q1_QUADER_SHOOT);
    g_SoundSystem.PrecacheSound(Q1_QUADER_QUAD);
    for (uint i = 0; i < Q1_QUADER_PAIN.length(); ++i)
      g_SoundSystem.PrecacheSound(Q1_QUADER_PAIN[i]);
  }

  void MonsterIdle() {
    m_iAIState = STATE_IDLE;
    SetActivity(ACT_IDLE);
    m_flMonsterSpeed = 0;
  }

  void MonsterSight() {
    AI_Face();
    g_SoundSystem.EmitSoundDyn(self.edict(), CHAN_VOICE, Q1_QUADER_SIGHT, Math.RandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + Math.RandomLong(0, 0xf));
  }

  void MonsterWalk() {
    m_iAIState = STATE_WALK;
    SetActivity(ACT_WALK);
    m_flMonsterSpeed = 2.5;
    AI_Turn();
  }

  void MonsterRun() {
    m_iAIState = STATE_RUN;
    SetActivity(ACT_RUN);
    m_flMonsterSpeed = 8;
  }

  void MonsterMissileAttack() {
    if (Math.RandomFloat(0, 1) < 0.3)
      m_fLeftY = !m_fLeftY;
    m_iAIState = STATE_ATTACK;
    SetActivity(ACT_RANGE_ATTACK1);
  }

  void MonsterPain(CBaseEntity@ pAttacker, float flDamage) {
    if (self.pev.pain_finished > g_Engine.time) return;
    int i = Math.RandomLong(0, 1);
    g_SoundSystem.EmitSoundDyn(self.edict(), CHAN_VOICE, Q1_QUADER_PAIN[i], Math.RandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + Math.RandomLong(0, 0xf));
    m_iAIState = STATE_PAIN;
    self.SetActivity(ACT_BIG_FLINCH);
    m_flMonsterSpeed = 0;
    self.pev.pain_finished = g_Engine.time + 1.0 - 0.3; // TODO: replace the 1.0 with sequence duration
  }

  bool MonsterHasMissileAttack() { return true; }
  bool MonsterHasPain() { return true; }

  void MonsterAttack() {
    if (m_fAttackDone) {
      m_fAttackDone = false;
      m_fInAttack = false;
      if (CheckRefire())
        MonsterMissileAttack();
      else
        MonsterRun();
    }
    AI_Face();
  }

  void MonsterFire() {
    if (m_fInAttack) return;

    AI_Face();

    g_SoundSystem.EmitSoundDyn(self.edict(), CHAN_VOICE, Q1_QUADER_SHOOT, Math.RandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + Math.RandomLong(0, 0xf));

    // fire somewhat behind the player, so a dodging player is harder to hit
    CBaseEntity@ pEnemy = m_hEnemy;

    Vector vecDir = ((pEnemy.pev.origin - pEnemy.pev.velocity * 0.2f) - self.pev.origin).Normalize();
    self.FireBullets(25, self.pev.origin, vecDir, Vector(0.1, 0.1, 0), 2048, BULLET_PLAYER_CUSTOMDAMAGE, 4, 4);

    g_SoundSystem.EmitSoundDyn(self.edict(), CHAN_ITEM, Q1_QUADER_QUAD, Math.RandomFloat(0.69, 0.7), ATTN_NORM, 0, 93 + Math.RandomLong(0, 0xf));

    self.pev.effects |= EF_MUZZLEFLASH;
    m_fInAttack = true;
  }

  void MonsterKilled(entvars_t@ pevAttacker, int iGib) {
    item_qbackpack@ pPack = q1_SpawnBackpack(self);
    pPack.m_iAmmoShells = 5;

    if (ShouldGibMonster(iGib)) {
      g_SoundSystem.EmitSoundDyn(self.edict(), CHAN_VOICE, "cmv/gib.wav", Math.RandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + Math.RandomLong(0, 0xf));
      g_EntityFuncs.SpawnRandomGibs(self.pev, 1, 1);
      g_EntityFuncs.Remove(self);
      return;
    }
    g_SoundSystem.EmitSoundDyn(self.edict(), CHAN_VOICE, Q1_QUADER_DEATH, Math.RandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + Math.RandomLong(0, 0xf));
  }

  void HandleAnimEvent(MonsterEvent@ pEvent) {
    switch (pEvent.event) {
      case QUADER_END_ATTACK:
        m_fAttackDone = true;
        m_fInAttack = true;
        break;

      case QUADER_DROP_BACKPACK:
        break;

      case QUADER_SHOOT:
        MonsterFire();
        break;

      case QUADER_IDLE_SOUND:
        if (Math.RandomFloat(0, 1) < 0.2)
          g_SoundSystem.EmitSoundDyn(self.edict(), CHAN_VOICE, Q1_QUADER_IDLE, Math.RandomFloat(0.95, 1.0), ATTN_IDLE, 0, 93 + Math.RandomLong(0, 0xf));
        break;

      default:
        BaseClass.HandleAnimEvent(pEvent);
    }
  }
}

void set_user_rendering(CBaseEntity@ cEnt, int rfx = kRenderFxNone, float r = 255, float g = 255, float b = 255, int rmode = kRenderNormal, float namt = 16)
{
	if(cEnt is null) return;
		cEnt.pev.renderfx = rfx;
		Vector rClr;
		rClr.x = r;
		rClr.y = g;
		rClr.z = b;
		cEnt.pev.rendermode = rmode;
		cEnt.pev.renderamt = namt;
		cEnt.pev.rendercolor = rClr;
}


void q1_RegisterMonster_QUADER() {
  g_CustomEntityFuncs.RegisterCustomEntity("monster_qquader", "monster_qquader");
}