#pragma once

#include "all.qh"

float autocvar_g_monsters;
bool autocvar_g_monsters_edit;
bool autocvar_g_monsters_sounds;
int autocvar_g_monsters_max;
int autocvar_g_monsters_max_perplayer;
float autocvar_g_monsters_damageforcescale = 0.8;
float autocvar_g_monsters_target_range;
bool autocvar_g_monsters_target_infront;
float autocvar_g_monsters_target_infront_range = 0.3;
bool autocvar_g_monsters_target_infront_2d = true;
float autocvar_g_monsters_attack_range;
int autocvar_g_monsters_score_kill;
int autocvar_g_monsters_score_spawned;
bool autocvar_g_monsters_typefrag;
bool autocvar_g_monsters_owners;
bool autocvar_g_monsters_playerclip_collisions;
float autocvar_g_monsters_miniboss_chance;
float autocvar_g_monsters_miniboss_healthboost;
string autocvar_g_monsters_miniboss_loot = "vortex";
float autocvar_g_monsters_drop_time = 10;
float autocvar_g_monsters_spawnshieldtime;
bool autocvar_g_monsters_quake_resize = true;
bool autocvar_g_monsters_teams;
float autocvar_g_monsters_respawn_delay;
bool autocvar_g_monsters_respawn;
float autocvar_g_monsters_armor_blockpercent;
float autocvar_g_monsters_healthbars;
bool autocvar_g_monsters_lineofsight = true;
//bool autocvar_g_monsters_ignoretraces = true;

// stats networking
int monsters_total;
int monsters_killed;

// monster properties
.int monster_movestate;   ///< monster move target priority
.entity monster_follow;   ///< monster follow target
.float wander_delay;      ///< monster logic delay between moving while idle
.float wander_distance;   ///< distance to move between wander delays for monsters
.float monster_lifetime;  ///< monster dies instantly after this delay, set from spawn
.float attack_range;      ///< melee attack if closer, ranged attack if further away (TODO: separate ranged attack range?)
.float spawn_time;        ///< delay monster thinking until spawn animation has completed
.bool candrop;            ///< toggle to allow disabling monster item drops
.int monster_movestate;   ///< will be phased out
.int monster_moveflags;
.string oldtarget2;       ///< a copy of the original follow target string for monsters
.float last_trace;        ///< monster logic delay between target tracing
.float last_enemycheck;   ///< for checking monster enemy
.float anim_finished;     ///< will be phased out when we have proper animations system
.vector monster_moveto;   ///< custom destination for monster (reset to '0 0 0' when you're done!)
.vector monster_face;     ///< custom looking direction for monster (reset to '0 0 0' when you're done!)
.float speed;             ///< monster walk speed
.float speed2;            ///< monster run speed
.float stopspeed;
.int oldskin;
.string mdl_dead;         ///< dead model for goombas
.bool monster_item;       ///< identifier for dropped monster loot TODO: generic identifiers? ok_item exists too!

#define MONSTER_SKILLMOD(mon) (0.5 + mon.monster_skill * ((1.2 - 0.3) / 10))

// other properties
.bool monster_attack; ///< indicates whether an entity can be attacked by monsters

// monster state declarations
const int MONSTER_MOVE_FOLLOW    = 1; ///< monster will follow if in range, or stand still
const int MONSTER_MOVE_WANDER    = 2; ///< monster will ignore owner & wander around
const int MONSTER_MOVE_SPAWNLOC  = 3; ///< monster will move to its spawn location when not attacking
const int MONSTER_MOVE_NOMOVE    = 4; ///< monster simply stands still
const int MONSTER_MOVE_ENEMY     = 5; ///< used only as a movestate, for monsters
const int MONSTER_ATTACK_MELEE   = 6;
const int MONSTER_ATTACK_RANGED  = 7;

// skill declarations
const int MONSTER_SKILL_EASY       = 1;
const int MONSTER_SKILL_MEDIUM     = 3;
const int MONSTER_SKILL_HARD       = 5;
const int MONSTER_SKILL_INSANE     = 7;
const int MONSTER_SKILL_NIGHTMARE  = 10;

const int MONSTERSKILL_NOTEASY    = BIT(8);  ///< monster will not spawn on skill <= 1
const int MONSTERSKILL_NOTMEDIUM  = BIT(9);  ///< monster will not spawn on skill 2
const int MONSTERSKILL_NOTHARD    = BIT(10); ///< monster will not spawn on skill >= 3

// spawn flags
const int MONSTERFLAG_APPEAR        = BIT(1);  ///< delay monster spawn until triggered
const int MONSTERFLAG_NORESPAWN     = BIT(2);  ///< monster doesn't respawn (revive)
const int MONSTERFLAG_FLY_VERTICAL  = BIT(3);  ///< monster can fly/swim vertically
const int MONSTERFLAG_INFRONT       = BIT(5);  ///< only check for enemies infront of us, for monsters
const int MONSTERFLAG_MINIBOSS      = BIT(6);  ///< monster spawns as mini-boss (also has a chance of naturally becoming one)
const int MONSTERFLAG_INVINCIBLE    = BIT(7);  ///< monster doesn't take damage (may be used for map objects & temporary monsters)
const int MONSTERFLAG_SPAWNED       = BIT(14); ///< flag for spawned monsters
const int MONSTERFLAG_RESPAWNED     = BIT(15); ///< flag for respawned monsters

// compatibility with old maps (soon to be removed)
.float monster_lifetime;
.int monster_skill;

// functions used elsewhere
void Monster_Remove(entity this);
void monsters_setstatus(entity this);
bool Monster_Spawn(entity this, bool check_appear, Monster mon);

void monster_setupcolors(entity this);

void Monster_Touch(entity this, entity toucher);

void Monster_Move_2D(entity this, float mspeed, float allow_jumpoff);

void Monster_Delay(entity this, int repeat_count, float defer_amnt, void(entity) func);

float Monster_Attack_Melee(entity this, entity targ, float damg, vector anim, float er, float animtime, int deathtype, float dostop);
bool Monster_Attack_Leap(entity this, vector anm, void(entity this, entity toucher) touchfunc, vector vel, float animtime);

entity Monster_FindTarget(entity this);

void monster_makevectors(entity this, entity targ);

void Monster_Sound(entity this, .string samplefield, float sound_delay, float delaytoo, float chan);

int totalspawned; ///< number of monsters spawned with mobspawn command

// monster sounds
.float msound_delay; ///< temporary antilag system
#define ALLMONSTERSOUNDS \
	_MSOUND(death) \
	_MSOUND(sight) \
	_MSOUND(ranged) \
	_MSOUND(melee) \
	_MSOUND(pain) \
	_MSOUND(spawn) \
	_MSOUND(idle) \
	_MSOUND(attack)

#define _MSOUND(m) .string monstersound_##m;
ALLMONSTERSOUNDS
#undef _MSOUND

bool GetMonsterSoundSampleField_notFound;

IntrusiveList g_monsters;
STATIC_INIT(g_monsters)
{
	g_monsters = IL_NEW();
}

IntrusiveList g_monster_targets;
STATIC_INIT(g_monster_targets)
{
	g_monster_targets = IL_NEW();
}
