-// size
-const vector HELLKNIGHT_MIN = '-20 -20 -32';
-const vector HELLKNIGHT_MAX = '20 20 41';
-
-// model
-string HELLKNIGHT_MODEL = "models/monsters/hknight.mdl";
-
-#ifdef SVQC
-// cvars
-float autocvar_g_monster_hellknight;
-float autocvar_g_monster_hellknight_health;
-float autocvar_g_monster_hellknight_melee_damage;
-float autocvar_g_monster_hellknight_inferno_damage;
-float autocvar_g_monster_hellknight_inferno_damagetime;
-float autocvar_g_monster_hellknight_inferno_chance;
-float autocvar_g_monster_hellknight_speed_walk;
-float autocvar_g_monster_hellknight_speed_run;
-float autocvar_g_monster_hellknight_fireball_damage;
-float autocvar_g_monster_hellknight_fireball_force;
-float autocvar_g_monster_hellknight_fireball_radius;
-float autocvar_g_monster_hellknight_fireball_chance;
-float autocvar_g_monster_hellknight_fireball_edgedamage;
-float autocvar_g_monster_hellknight_spike_chance;
-float autocvar_g_monster_hellknight_spike_force;
-float autocvar_g_monster_hellknight_spike_radius;
-float autocvar_g_monster_hellknight_spike_edgedamage;
-float autocvar_g_monster_hellknight_spike_damage;
-float autocvar_g_monster_hellknight_jump_chance;
-float autocvar_g_monster_hellknight_jump_damage;
-float autocvar_g_monster_hellknight_jump_dist;
-
-// animations
-const float hellknight_anim_stand = 0;
-const float hellknight_anim_walk = 1;
-const float hellknight_anim_run = 2;
-const float hellknight_anim_pain = 3;
-const float hellknight_anim_death1 = 4;
-const float hellknight_anim_death2 = 5;
-const float hellknight_anim_charge1 = 6;
-const float hellknight_anim_magic1 = 7;
-const float hellknight_anim_magic2 = 8;
-const float hellknight_anim_charge2 = 9;
-const float hellknight_anim_slice = 10;
-const float hellknight_anim_smash = 11;
-const float hellknight_anim_wattack = 12;
-const float hellknight_anim_magic3 = 13;
-
-void hellknight_think()
-{
- self.think = hellknight_think;
- self.nextthink = time + self.ticrate;
-
- monster_move(autocvar_g_monster_hellknight_speed_run, autocvar_g_monster_hellknight_speed_walk, 100, hellknight_anim_run, hellknight_anim_walk, hellknight_anim_stand);
-}
-
-void hknight_spike_think()
-{
- if(self)
- {
- RadiusDamage (self, self.realowner, autocvar_g_monster_hellknight_spike_damage, autocvar_g_monster_hellknight_spike_edgedamage, autocvar_g_monster_hellknight_spike_force, world, autocvar_g_monster_hellknight_spike_radius, DEATH_MONSTER_HKNIGHT_SPIKE, other);
- remove(self);
- }
-}
-
-void hknight_spike_touch()
-{
- PROJECTILE_TOUCH;
-
- pointparticles(particleeffectnum("TE_WIZSPIKE"), self.origin, '0 0 0', 1);
-
- hknight_spike_think();
-}
-
-void() hellknight_think;
-void hknight_shoot ()
-{
- local entity missile = world;
- local vector dir = normalize((self.enemy.origin + '0 0 10') - self.origin);
- local float dist = vlen (self.enemy.origin - self.origin), flytime = 0;
-
- flytime = dist * 0.002;
- if (flytime < 0.1)
- flytime = 0.1;
-
- self.effects |= EF_MUZZLEFLASH;
-
- missile = spawn ();
- missile.owner = missile.realowner = self;
- missile.solid = SOLID_TRIGGER;
- missile.movetype = MOVETYPE_FLYMISSILE;
- setsize (missile, '0 0 0', '0 0 0');
- setorigin(missile, self.origin + '0 0 10' + v_forward * 14);
- missile.scale = self.scale;
- missile.flags = FL_PROJECTILE;
- missile.velocity = dir * 400;
- missile.avelocity = '300 300 300';
- missile.nextthink = time + 5;
- missile.think = hknight_spike_think;
- missile.enemy = self.enemy;
- missile.touch = hknight_spike_touch;
- CSQCProjectile(missile, TRUE, PROJECTILE_CRYLINK, TRUE);
-}
-
-void hknight_inferno ()
-{
- traceline((self.absmin + self.absmax) * 0.5, (self.enemy.absmin + self.enemy.absmax) * 0.5, TRUE, world);
- if (trace_fraction != 1)
- return; // not visible
- if(vlen(self.enemy.origin - self.origin) <= 2000)
- Fire_AddDamage(self.enemy, self, autocvar_g_monster_hellknight_inferno_damage * monster_skill, autocvar_g_monster_hellknight_inferno_damagetime, DEATH_MONSTER_HKNIGHT_INFERNO);
-}
-
-void hknight_infernowarning ()
-{
- self.monster_delayedattack = func_null;
- self.delay = -1;
- if(!self.enemy)
- return;
-
- traceline((self.absmin + self.absmax) * 0.5, (self.enemy.absmin + self.enemy.absmax) * 0.5, TRUE, world);
- if (trace_fraction != 1)
- return; // not visible
- self.enemy.effects |= EF_MUZZLEFLASH;
- sound(self.enemy, CHAN_AUTO, "player/lava.wav", 1, ATTN_NORM);
-
- hknight_inferno();
-}
-
-.float hknight_cycles;
-void hellknight_magic ()
-{
- self.monster_delayedattack = hknight_infernowarning;
- self.delay = time + 0.5;
- self.attack_finished_single = time + 1.2;
-}
-
-void hknight_fireball_explode(entity targ)
-{
- if(self)
- {
- RadiusDamage (self, self.realowner, autocvar_g_monster_hellknight_fireball_damage, autocvar_g_monster_hellknight_fireball_edgedamage, autocvar_g_monster_hellknight_fireball_force, world, autocvar_g_monster_hellknight_fireball_radius, self.projectiledeathtype, targ);
- if(targ)
- Fire_AddDamage(targ, self, 5 * monster_skill, autocvar_g_monster_hellknight_inferno_damagetime, self.projectiledeathtype);
- remove(self);
- }
-}
-
-void hknight_fireball_think()
-{
- hknight_fireball_explode(world);
-}
-
-void hknight_fireball_touch()
-{
- PROJECTILE_TOUCH;
-
- hknight_fireball_explode(other);
-}
-
-void hellknight_fireball ()
-{
- local entity missile = spawn();
- local vector dir = normalize((self.enemy.origin + '0 0 10') - self.origin);
- vector fmins = '-4 -4 -4', fmaxs = '4 4 4';
-
- self.effects |= EF_MUZZLEFLASH;
- sound (self, CHAN_WEAPON, "weapons/fireball2.wav", 1, ATTN_NORM);
-
- missile.owner = missile.realowner = self;
- missile.solid = SOLID_TRIGGER;
- missile.movetype = MOVETYPE_FLYMISSILE;
- missile.projectiledeathtype = DEATH_MONSTER_HKNIGHT_FBALL;
- setsize (missile, fmins, fmaxs);
- setorigin(missile, self.origin + '0 0 10' + v_forward * 14);
- missile.flags = FL_PROJECTILE;
- missile.velocity = dir * 400;
- missile.avelocity = '300 300 300';
- missile.nextthink = time + 5;
- missile.think = hknight_fireball_think;
- missile.enemy = self.enemy;
- missile.touch = hknight_fireball_touch;
- CSQCProjectile(missile, TRUE, PROJECTILE_FIREMINE, TRUE);
-
- self.delay = -1;
-}
-
-void hellknight_magic2 ()
-{
- monsters_setframe(hellknight_anim_magic2);
- self.attack_finished_single = time + 1.2;
- self.delay = time + 0.4;
- self.monster_delayedattack = hellknight_fireball;
-}
-
-void hellknight_spikes ()
-{
- self.monster_delayedattack = hellknight_spikes;
- self.delay = time + 0.1;
- self.hknight_cycles += 1;
- hknight_shoot();
- if(self.hknight_cycles >= 7)
- {
- self.monster_delayedattack = func_null;
- self.delay = -1;
- }
-}
-
-void hellknight_magic3 ()
-{
- monsters_setframe(hellknight_anim_magic3);
- self.attack_finished_single = time + 1.1;
- self.monster_delayedattack = hellknight_spikes;
- self.delay = time + 0.4;
-}
-
-float hknight_magic()
-{
- if not(self.flags & FL_ONGROUND)
- return FALSE;
-
- if not(self.enemy)
- return FALSE; // calling attack check with no enemy?!
-
- if(time < self.attack_finished_single)
- return FALSE;
-
- self.hknight_cycles = 0;
-
- if (self.enemy.monsterid == MONSTER_ZOMBIE)
- {
- // always use fireball to kill zombies
- hellknight_magic2();
- self.attack_finished_single = time + 2;
- return TRUE;
- }
- RandomSelection_Init();
- RandomSelection_Add(world, 0, "fireball", autocvar_g_monster_hellknight_fireball_chance, 1);
- RandomSelection_Add(world, 0, "inferno", autocvar_g_monster_hellknight_inferno_chance, 1);
- RandomSelection_Add(world, 0, "spikes", autocvar_g_monster_hellknight_spike_chance, 1);
- if(self.health >= 100)
- RandomSelection_Add(world, 0, "jump", ((vlen(self.enemy.origin - self.origin) > autocvar_g_monster_hellknight_jump_dist) ? 1 : autocvar_g_monster_hellknight_jump_chance), 1);
-
- switch(RandomSelection_chosen_string)
- {
- case "fireball":
- {
- hellknight_magic2();
- self.attack_finished_single = time + 2;
- return TRUE;
- }
- case "spikes":
- {
- hellknight_magic3();
- self.attack_finished_single = time + 3;
- return TRUE;
- }
- case "inferno":
- {
- hellknight_magic();
- self.attack_finished_single = time + 3;
- return TRUE;
- }
- case "jump":
- {
- if (vlen(self.enemy.origin - self.origin) >= 400)
- if (findtrajectorywithleading(self.origin, self.mins, self.maxs, self.enemy, 1000, 0, 10, 0, self))
- {
- self.velocity = findtrajectory_velocity;
- Damage(self.enemy, self, self, autocvar_g_monster_hellknight_jump_damage * monster_skill, DEATH_MONSTER_HKNIGHT_CRUSH, self.enemy.origin, normalize(self.enemy.origin - self.origin));
- self.attack_finished_single = time + 2;
- return TRUE;
- }
- return FALSE;
- }
- }
-
- return FALSE;
-}
-
-float knight_attack(float attack_type)
-{
- switch(attack_type)
- {
- case MONSTER_ATTACK_MELEE:
- {
- float anim;
- if(random() < 0.3)
- anim = hellknight_anim_slice;
- else if(random() < 0.6)
- anim = hellknight_anim_smash;
- else
- anim = hellknight_anim_wattack;
-
- monsters_setframe(anim);
- self.attack_finished_single = time + 0.7;
- monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, TRUE);
-
- return TRUE;
- }
- case MONSTER_ATTACK_RANGED:
- {
- if(hknight_magic())
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-void hellknight_die ()
-{
- float chance = random();
- Monster_CheckDropCvars ("hellknight");
-
- self.think = monster_dead_think;
- self.nextthink = time + self.ticrate;
- self.ltime = time + 5;
- monsters_setframe((random() > 0.5) ? hellknight_anim_death1 : hellknight_anim_death2);
-
- if(chance < 0.10 || self.flags & MONSTERFLAG_MINIBOSS)
- if(self.candrop)
- {
- self.superweapons_finished = time + autocvar_g_balance_superweapons_time + 5; // give the player a few seconds to find the weapon
- self.weapon = WEP_FIREBALL;
- }
-
- monster_hook_death(); // for post-death mods
-}
-
-void hellknight_spawn ()
-{
- if not(self.health)
- self.health = autocvar_g_monster_hellknight_health;
-
- self.damageforcescale = 0.003;
- self.classname = "monster_hellknight";
- self.monster_attackfunc = knight_attack;
- self.nextthink = time + random() * 0.5 + 0.1;
- self.think = hellknight_think;
-
- monsters_setframe(hellknight_anim_stand);
-
- monster_setupsounds("hellknight");
-
- monster_hook_spawn(); // for post-spawn mods
-}
-
-void spawnfunc_monster_hellknight ()
-{
- if not(autocvar_g_monster_hellknight) { remove(self); return; }
-
- self.monster_spawnfunc = spawnfunc_monster_hellknight;
-
- if(Monster_CheckAppearFlags(self))
- return;
-
- self.scale = 1.3;
-
- if not (monster_initialize(
- "Hell-knight", MONSTER_HELLKNIGHT,
- HELLKNIGHT_MIN, HELLKNIGHT_MAX,
- FALSE,
- hellknight_die, hellknight_spawn))
- {
- remove(self);
- return;
- }
-}
-
-// compatibility with old spawns
-void spawnfunc_monster_hell_knight() { spawnfunc_monster_hellknight(); }
-
-#endif // SVQC