2 const vector HELLKNIGHT_MIN = '-20 -20 -32';
3 const vector HELLKNIGHT_MAX = '20 20 41';
6 string HELLKNIGHT_MODEL = "models/monsters/hknight.mdl";
10 float autocvar_g_monster_hellknight;
11 float autocvar_g_monster_hellknight_health;
12 float autocvar_g_monster_hellknight_melee_damage;
13 float autocvar_g_monster_hellknight_inferno_damage;
14 float autocvar_g_monster_hellknight_inferno_damagetime;
15 float autocvar_g_monster_hellknight_inferno_chance;
16 float autocvar_g_monster_hellknight_speed_walk;
17 float autocvar_g_monster_hellknight_speed_run;
18 float autocvar_g_monster_hellknight_fireball_damage;
19 float autocvar_g_monster_hellknight_fireball_force;
20 float autocvar_g_monster_hellknight_fireball_radius;
21 float autocvar_g_monster_hellknight_fireball_chance;
22 float autocvar_g_monster_hellknight_fireball_edgedamage;
23 float autocvar_g_monster_hellknight_spike_chance;
24 float autocvar_g_monster_hellknight_spike_force;
25 float autocvar_g_monster_hellknight_spike_radius;
26 float autocvar_g_monster_hellknight_spike_edgedamage;
27 float autocvar_g_monster_hellknight_spike_damage;
28 float autocvar_g_monster_hellknight_jump_chance;
29 float autocvar_g_monster_hellknight_jump_damage;
30 float autocvar_g_monster_hellknight_jump_dist;
33 const float hellknight_anim_stand = 0;
34 const float hellknight_anim_walk = 1;
35 const float hellknight_anim_run = 2;
36 const float hellknight_anim_pain = 3;
37 const float hellknight_anim_death1 = 4;
38 const float hellknight_anim_death2 = 5;
39 const float hellknight_anim_charge1 = 6;
40 const float hellknight_anim_magic1 = 7;
41 const float hellknight_anim_magic2 = 8;
42 const float hellknight_anim_charge2 = 9;
43 const float hellknight_anim_slice = 10;
44 const float hellknight_anim_smash = 11;
45 const float hellknight_anim_wattack = 12;
46 const float hellknight_anim_magic3 = 13;
48 void hellknight_think()
50 self.think = hellknight_think;
51 self.nextthink = time + self.ticrate;
53 monster_move(autocvar_g_monster_hellknight_speed_run, autocvar_g_monster_hellknight_speed_walk, 100, hellknight_anim_run, hellknight_anim_walk, hellknight_anim_stand);
56 void hknight_spike_think()
60 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);
65 void hknight_spike_touch()
69 pointparticles(particleeffectnum("TE_WIZSPIKE"), self.origin, '0 0 0', 1);
71 hknight_spike_think();
74 void() hellknight_think;
77 local entity missile = world;
78 local vector dir = normalize((self.enemy.origin + '0 0 10') - self.origin);
79 local float dist = vlen (self.enemy.origin - self.origin), flytime = 0;
81 flytime = dist * 0.002;
85 self.effects |= EF_MUZZLEFLASH;
88 missile.owner = missile.realowner = self;
89 missile.solid = SOLID_TRIGGER;
90 missile.movetype = MOVETYPE_FLYMISSILE;
91 setsize (missile, '0 0 0', '0 0 0');
92 setorigin(missile, self.origin + '0 0 10' + v_forward * 14);
93 missile.scale = self.scale;
94 missile.flags = FL_PROJECTILE;
95 missile.velocity = dir * 400;
96 missile.avelocity = '300 300 300';
97 missile.nextthink = time + 5;
98 missile.think = hknight_spike_think;
99 missile.enemy = self.enemy;
100 missile.touch = hknight_spike_touch;
101 CSQCProjectile(missile, TRUE, PROJECTILE_CRYLINK, TRUE);
104 void hknight_inferno ()
106 traceline((self.absmin + self.absmax) * 0.5, (self.enemy.absmin + self.enemy.absmax) * 0.5, TRUE, world);
107 if (trace_fraction != 1)
108 return; // not visible
109 if(vlen(self.enemy.origin - self.origin) <= 2000)
110 Fire_AddDamage(self.enemy, self, autocvar_g_monster_hellknight_inferno_damage * monster_skill, autocvar_g_monster_hellknight_inferno_damagetime, DEATH_MONSTER_HKNIGHT_INFERNO);
113 void hknight_infernowarning ()
115 self.monster_delayedattack = func_null;
120 traceline((self.absmin + self.absmax) * 0.5, (self.enemy.absmin + self.enemy.absmax) * 0.5, TRUE, world);
121 if (trace_fraction != 1)
122 return; // not visible
123 self.enemy.effects |= EF_MUZZLEFLASH;
124 sound(self.enemy, CHAN_AUTO, "player/lava.wav", 1, ATTN_NORM);
129 .float hknight_cycles;
130 void hellknight_magic ()
132 self.monster_delayedattack = hknight_infernowarning;
133 self.delay = time + 0.5;
134 self.attack_finished_single = time + 1.2;
137 void hknight_fireball_explode(entity targ)
141 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);
143 Fire_AddDamage(targ, self, 5 * monster_skill, autocvar_g_monster_hellknight_inferno_damagetime, self.projectiledeathtype);
148 void hknight_fireball_think()
150 hknight_fireball_explode(world);
153 void hknight_fireball_touch()
157 hknight_fireball_explode(other);
160 void hellknight_fireball ()
162 local entity missile = spawn();
163 local vector dir = normalize((self.enemy.origin + '0 0 10') - self.origin);
164 vector fmins = '-4 -4 -4', fmaxs = '4 4 4';
166 self.effects |= EF_MUZZLEFLASH;
167 sound (self, CHAN_WEAPON, "weapons/fireball2.wav", 1, ATTN_NORM);
169 missile.owner = missile.realowner = self;
170 missile.solid = SOLID_TRIGGER;
171 missile.movetype = MOVETYPE_FLYMISSILE;
172 missile.projectiledeathtype = DEATH_MONSTER_HKNIGHT_FBALL;
173 setsize (missile, fmins, fmaxs);
174 setorigin(missile, self.origin + '0 0 10' + v_forward * 14);
175 missile.flags = FL_PROJECTILE;
176 missile.velocity = dir * 400;
177 missile.avelocity = '300 300 300';
178 missile.nextthink = time + 5;
179 missile.think = hknight_fireball_think;
180 missile.enemy = self.enemy;
181 missile.touch = hknight_fireball_touch;
182 CSQCProjectile(missile, TRUE, PROJECTILE_FIREMINE, TRUE);
187 void hellknight_magic2 ()
189 monsters_setframe(hellknight_anim_magic2);
190 self.attack_finished_single = time + 1.2;
191 self.delay = time + 0.4;
192 self.monster_delayedattack = hellknight_fireball;
195 void hellknight_spikes ()
197 self.monster_delayedattack = hellknight_spikes;
198 self.delay = time + 0.1;
199 self.hknight_cycles += 1;
201 if(self.hknight_cycles >= 7)
203 self.monster_delayedattack = func_null;
208 void hellknight_magic3 ()
210 monsters_setframe(hellknight_anim_magic3);
211 self.attack_finished_single = time + 1.1;
212 self.monster_delayedattack = hellknight_spikes;
213 self.delay = time + 0.4;
216 float hknight_magic()
218 if not(self.flags & FL_ONGROUND)
222 return FALSE; // calling attack check with no enemy?!
224 if(time < self.attack_finished_single)
227 self.hknight_cycles = 0;
229 if (self.enemy.monsterid == MONSTER_ZOMBIE)
231 // always use fireball to kill zombies
233 self.attack_finished_single = time + 2;
236 RandomSelection_Init();
237 RandomSelection_Add(world, 0, "fireball", autocvar_g_monster_hellknight_fireball_chance, 1);
238 RandomSelection_Add(world, 0, "inferno", autocvar_g_monster_hellknight_inferno_chance, 1);
239 RandomSelection_Add(world, 0, "spikes", autocvar_g_monster_hellknight_spike_chance, 1);
240 if(self.health >= 100)
241 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);
243 switch(RandomSelection_chosen_string)
248 self.attack_finished_single = time + 2;
254 self.attack_finished_single = time + 3;
260 self.attack_finished_single = time + 3;
265 if (vlen(self.enemy.origin - self.origin) >= 400)
266 if (findtrajectorywithleading(self.origin, self.mins, self.maxs, self.enemy, 1000, 0, 10, 0, self))
268 self.velocity = findtrajectory_velocity;
269 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));
270 self.attack_finished_single = time + 2;
280 float knight_attack(float attack_type)
284 case MONSTER_ATTACK_MELEE:
288 anim = hellknight_anim_slice;
289 else if(random() < 0.6)
290 anim = hellknight_anim_smash;
292 anim = hellknight_anim_wattack;
294 monsters_setframe(anim);
295 self.attack_finished_single = time + 0.7;
296 monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, TRUE);
300 case MONSTER_ATTACK_RANGED:
310 void hellknight_die ()
312 float chance = random();
313 Monster_CheckDropCvars ("hellknight");
315 self.think = monster_dead_think;
316 self.nextthink = time + self.ticrate;
317 self.ltime = time + 5;
318 monsters_setframe((random() > 0.5) ? hellknight_anim_death1 : hellknight_anim_death2);
320 if(chance < 0.10 || self.flags & MONSTERFLAG_MINIBOSS)
323 self.superweapons_finished = time + autocvar_g_balance_superweapons_time + 5; // give the player a few seconds to find the weapon
324 self.weapon = WEP_FIREBALL;
327 monster_hook_death(); // for post-death mods
330 void hellknight_spawn ()
333 self.health = autocvar_g_monster_hellknight_health;
335 self.damageforcescale = 0.003;
336 self.classname = "monster_hellknight";
337 self.monster_attackfunc = knight_attack;
338 self.nextthink = time + random() * 0.5 + 0.1;
339 self.think = hellknight_think;
341 monsters_setframe(hellknight_anim_stand);
343 monster_setupsounds("hellknight");
345 monster_hook_spawn(); // for post-spawn mods
348 void spawnfunc_monster_hellknight ()
350 if not(autocvar_g_monster_hellknight) { remove(self); return; }
352 self.monster_spawnfunc = spawnfunc_monster_hellknight;
354 if(Monster_CheckAppearFlags(self))
359 if not (monster_initialize(
360 "Hell-knight", MONSTER_HELLKNIGHT,
361 HELLKNIGHT_MIN, HELLKNIGHT_MAX,
363 hellknight_die, hellknight_spawn))
370 // compatibility with old spawns
371 void spawnfunc_monster_hell_knight() { spawnfunc_monster_hellknight(); }