2 const vector HELLKNIGHT_MIN = '-16 -16 -24';
3 const vector HELLKNIGHT_MAX = '16 16 32';
6 float autocvar_g_monster_hellknight;
7 float autocvar_g_monster_hellknight_health;
8 float autocvar_g_monster_hellknight_melee_damage;
9 float autocvar_g_monster_hellknight_inferno_damage;
10 float autocvar_g_monster_hellknight_inferno_damagetime;
11 float autocvar_g_monster_hellknight_inferno_chance;
12 float autocvar_g_monster_hellknight_speed_walk;
13 float autocvar_g_monster_hellknight_speed_run;
14 float autocvar_g_monster_hellknight_fireball_damage;
15 float autocvar_g_monster_hellknight_fireball_force;
16 float autocvar_g_monster_hellknight_fireball_radius;
17 float autocvar_g_monster_hellknight_fireball_chance;
18 float autocvar_g_monster_hellknight_fireball_edgedamage;
19 float autocvar_g_monster_hellknight_spike_chance;
20 float autocvar_g_monster_hellknight_spike_force;
21 float autocvar_g_monster_hellknight_spike_radius;
22 float autocvar_g_monster_hellknight_spike_edgedamage;
23 float autocvar_g_monster_hellknight_spike_damage;
24 float autocvar_g_monster_hellknight_jump_chance;
25 float autocvar_g_monster_hellknight_jump_damage;
26 float autocvar_g_monster_hellknight_jump_dist;
29 #define hellknight_anim_stand 0
30 #define hellknight_anim_walk 1
31 #define hellknight_anim_run 2
32 #define hellknight_anim_pain 3
33 #define hellknight_anim_death1 4
34 #define hellknight_anim_death2 5
35 #define hellknight_anim_charge1 6
36 #define hellknight_anim_magic1 7
37 #define hellknight_anim_magic2 8
38 #define hellknight_anim_charge2 9
39 #define hellknight_anim_slice 10
40 #define hellknight_anim_smash 11
41 #define hellknight_anim_wattack 12
42 #define hellknight_anim_magic3 13
44 void hknight_spike_think()
48 RadiusDamage (self, self.realowner, autocvar_g_monster_hellknight_spike_damage * self.realowner.scale, autocvar_g_monster_hellknight_spike_edgedamage, autocvar_g_monster_hellknight_spike_force, world, autocvar_g_monster_hellknight_spike_radius, DEATH_MONSTER_HKNIGHT_SPIKE, other);
53 void hknight_spike_touch()
57 pointparticles(particleeffectnum("TE_WIZSPIKE"), self.origin, '0 0 0', 1);
59 hknight_spike_think();
62 void() hellknight_think;
65 local entity missile = world;
66 local vector dir = normalize((self.enemy.origin + '0 0 10') - self.origin);
67 local float dist = vlen (self.enemy.origin - self.origin), flytime = 0;
69 flytime = dist * 0.002;
73 self.effects |= EF_MUZZLEFLASH;
74 sound (self, CHAN_WEAPON, "weapons/spike.wav", 1, ATTN_NORM);
77 missile.owner = missile.realowner = self;
78 missile.solid = SOLID_TRIGGER;
79 missile.movetype = MOVETYPE_FLYMISSILE;
80 setsize (missile, '0 0 0', '0 0 0');
81 setorigin(missile, self.origin + '0 0 10' + v_forward * 14);
82 missile.scale = self.scale;
83 missile.flags = FL_PROJECTILE;
84 missile.velocity = dir * 400;
85 missile.avelocity = '300 300 300';
86 missile.nextthink = time + 5;
87 missile.think = hknight_spike_think;
88 missile.enemy = self.enemy;
89 missile.touch = hknight_spike_touch;
90 CSQCProjectile(missile, TRUE, PROJECTILE_CRYLINK, TRUE);
93 void hknight_inferno ()
95 traceline((self.absmin + self.absmax) * 0.5, (self.enemy.absmin + self.enemy.absmax) * 0.5, TRUE, world);
96 if (trace_fraction != 1)
97 return; // not visible
98 if(vlen(self.enemy.origin - self.origin) <= 2000)
99 Fire_AddDamage(self.enemy, self, autocvar_g_monster_hellknight_inferno_damage * monster_skill, autocvar_g_monster_hellknight_inferno_damagetime, DEATH_MONSTER_HKNIGHT_INFERNO);
102 void hknight_infernowarning ()
107 traceline((self.absmin + self.absmax) * 0.5, (self.enemy.absmin + self.enemy.absmax) * 0.5, TRUE, world);
108 if (trace_fraction != 1)
109 return; // not visible
110 self.enemy.effects |= EF_MUZZLEFLASH;
111 sound(self.enemy, CHAN_AUTO, "player/lava.wav", 1, ATTN_NORM);
116 float() hknight_magic;
117 float hknight_checkmagic ()
119 local vector v1 = '0 0 0', v2 = '0 0 0';
122 // use magic to kill zombies as they heal too fast for sword
123 if (self.enemy.classname == "monster_zombie")
125 traceline((self.absmin + self.absmax) * 0.5, (self.enemy.absmin + self.enemy.absmax) * 0.5, FALSE, self);
126 if (trace_ent == self.enemy)
134 return FALSE; // 25% of the time it won't do anything
135 v1 = normalize(self.enemy.velocity);
136 v2 = normalize(self.enemy.origin - self.origin);
138 if (dot >= 0.7) // moving away
139 if (vlen(self.enemy.velocity) >= 150) // walking/running away
140 return hknight_magic();
144 void() hellknight_charge;
145 void CheckForCharge ()
147 // check for mad charge
148 if (time < self.attack_finished_single)
150 if (fabs(self.origin_z - self.enemy.origin_z) > 20)
151 return; // too much height change
152 if (vlen (self.origin - self.enemy.origin) < 80)
153 return; // use regular attack
154 if (hknight_checkmagic())
155 return; // chose magic
161 void CheckContinueCharge ()
163 if(hknight_checkmagic())
164 return; // chose magic
165 if(time >= self.attack_finished_single)
168 return; // done charging
172 void hellknight_think ()
174 self.think = hellknight_think;
175 self.nextthink = time + 0.1;
177 monster_move(autocvar_g_monster_hellknight_speed_run, autocvar_g_monster_hellknight_speed_walk, 100, hellknight_anim_run, hellknight_anim_walk, hellknight_anim_stand);
180 .float hknight_cycles;
181 void hellknight_magic ()
183 self.hknight_cycles += 1;
184 self.think = hellknight_magic;
186 if(self.hknight_cycles >= 5)
188 self.frame = hellknight_anim_magic1;
189 self.attack_finished_single = time + 0.7;
190 hknight_infernowarning();
191 self.think = hellknight_think;
194 self.nextthink = time + 0.1;
197 void hknight_fireball_explode(entity targ)
199 float scle = self.realowner.scale;
202 RadiusDamage (self, self.realowner, autocvar_g_monster_hellknight_fireball_damage * scle, autocvar_g_monster_hellknight_fireball_edgedamage * scle, autocvar_g_monster_hellknight_fireball_force * scle, world, autocvar_g_monster_hellknight_fireball_radius * scle, self.projectiledeathtype, targ);
204 Fire_AddDamage(targ, self, 5 * monster_skill, autocvar_g_monster_hellknight_inferno_damagetime, self.projectiledeathtype);
209 void hknight_fireball_think()
211 hknight_fireball_explode(world);
214 void hknight_fireball_touch()
218 hknight_fireball_explode(other);
221 void hellknight_fireball ()
223 local entity missile = spawn();
224 local vector dir = normalize((self.enemy.origin + '0 0 10') - self.origin);
225 vector fmins = ((self.scale >= 2) ? '-16 -16 -16' : '-4 -4 -4'), fmaxs = ((self.scale >= 2) ? '16 16 16' : '4 4 4');
227 self.effects |= EF_MUZZLEFLASH;
228 sound (self, CHAN_WEAPON, "weapons/fireball2.wav", 1, ATTN_NORM);
230 missile.owner = missile.realowner = self;
231 missile.solid = SOLID_TRIGGER;
232 missile.movetype = MOVETYPE_FLYMISSILE;
233 self.projectiledeathtype = DEATH_MONSTER_HKNIGHT_FBALL;
234 setsize (missile, fmins, fmaxs);
235 setorigin(missile, self.origin + '0 0 10' + v_forward * 14);
236 missile.flags = FL_PROJECTILE;
237 missile.velocity = dir * 400;
238 missile.avelocity = '300 300 300';
239 missile.nextthink = time + 5;
240 missile.think = hknight_fireball_think;
241 missile.enemy = self.enemy;
242 missile.touch = hknight_fireball_touch;
243 CSQCProjectile(missile, TRUE, ((self.scale >= 2) ? PROJECTILE_FIREBALL : PROJECTILE_FIREMINE), TRUE);
248 void hellknight_magic2 ()
250 self.frame = hellknight_anim_magic2;
251 self.attack_finished_single = time + 1.2;
252 self.delay = time + 0.4;
253 self.monster_delayedattack = hellknight_fireball;
256 void hellknight_spikes ()
258 self.think = hellknight_spikes;
259 self.nextthink = time + 0.1;
260 self.hknight_cycles += 1;
262 if(self.hknight_cycles >= 7)
263 self.think = hellknight_think;
266 void hellknight_magic3 ()
268 self.frame = hellknight_anim_magic3;
269 self.attack_finished_single = time + 1;
270 self.think = hellknight_spikes;
271 self.nextthink = time + 0.4;
274 void hellknight_charge ()
276 self.frame = hellknight_anim_charge1;
277 self.attack_finished_single = time + 0.5;
279 hknight_checkmagic();
280 monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 70, DEATH_MONSTER_HKNIGHT_MELEE);
281 hknight_checkmagic();
284 void hellknight_charge2 ()
286 self.frame = hellknight_anim_charge2;
287 self.attack_finished_single = time + 0.5;
289 CheckContinueCharge ();
290 monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 70, DEATH_MONSTER_HKNIGHT_MELEE);
293 void hellknight_slice ()
295 self.frame = hellknight_anim_slice;
296 self.attack_finished_single = time + 0.7;
297 monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 70, DEATH_MONSTER_HKNIGHT_MELEE);
300 void hellknight_smash ()
302 self.frame = hellknight_anim_smash;
303 self.attack_finished_single = time + 0.7;
304 monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 70, DEATH_MONSTER_HKNIGHT_MELEE);
307 void hellknight_weapon_attack ()
309 self.frame = hellknight_anim_wattack;
310 self.attack_finished_single = time + 0.7;
311 monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 70, DEATH_MONSTER_HKNIGHT_MELEE);
315 void hknight_melee ()
319 if (hknight_type == 1)
321 else if (hknight_type == 2)
325 hellknight_weapon_attack();
330 float hknight_magic ()
332 if not(self.flags & FL_ONGROUND)
336 return FALSE; // calling attack check with no enemy?!
338 if(time < self.attack_finished_single)
341 self.hknight_cycles = 0;
343 if (self.enemy.classname == "monster_zombie")
345 // always use fireball to kill zombies
347 self.attack_finished_single = time + 2;
350 RandomSelection_Init();
351 RandomSelection_Add(world, 0, "fireball", autocvar_g_monster_hellknight_fireball_chance, 1);
352 RandomSelection_Add(world, 0, "inferno", autocvar_g_monster_hellknight_inferno_chance, 1);
353 RandomSelection_Add(world, 0, "spikes", autocvar_g_monster_hellknight_spike_chance, 1);
354 if(self.health >= 100)
355 RandomSelection_Add(world, 0, "jump", ((vlen(self.enemy.origin - self.origin) > autocvar_g_monster_hellknight_jump_dist * self.scale) ? 1 : autocvar_g_monster_hellknight_jump_chance), 1);
357 switch(RandomSelection_chosen_string)
362 self.attack_finished_single = time + 2;
368 self.attack_finished_single = time + 3;
374 self.attack_finished_single = time + 3;
379 if (vlen(self.enemy.origin - self.origin) >= 400)
380 if (findtrajectorywithleading(self.origin, self.mins, self.maxs, self.enemy, 1000, 0, 10, 0, self))
382 self.velocity = findtrajectory_velocity;
383 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));
384 self.attack_finished_single = time + 2;
395 void hellknight_die ()
397 float chance = random();
398 Monster_CheckDropCvars ("hellknight");
400 self.solid = SOLID_NOT;
401 self.takedamage = DAMAGE_NO;
402 self.event_damage = func_null;
404 self.movetype = MOVETYPE_TOSS;
405 self.think = Monster_Fade;
406 self.nextthink = time + 2.1;
408 if(chance < 0.10 || self.flags & MONSTERFLAG_MINIBOSS)
411 self.superweapons_finished = time + autocvar_g_balance_superweapons_time + 5; // give the player a few seconds to find the weapon
412 W_ThrowNewWeapon(self, WEP_FIREBALL, 0, self.origin, self.velocity);
416 self.frame = hellknight_anim_death1;
418 self.frame = hellknight_anim_death2;
420 monster_hook_death(); // for post-death mods
423 void hellknight_spawn ()
426 self.health = autocvar_g_monster_hellknight_health * self.scale;
428 self.damageforcescale = 0.003;
429 self.classname = "monster_hellknight";
430 self.checkattack = GenericCheckAttack;
431 self.attack_melee = hknight_melee;
432 self.attack_ranged = hknight_magic;
433 self.nextthink = time + random() * 0.5 + 0.1;
434 self.think = hellknight_think;
435 self.sprite_height = 30 * self.scale;
436 self.frame = hellknight_anim_stand;
438 monster_hook_spawn(); // for post-spawn mods
441 void spawnfunc_monster_hell_knight ()
443 if not(autocvar_g_monster_hellknight) { remove(self); return; }
445 self.monster_spawnfunc = spawnfunc_monster_hell_knight;
447 if(self.spawnflags & MONSTERFLAG_APPEAR)
449 self.think = func_null;
451 self.use = Monster_Appear;
457 if not (monster_initialize(
459 "models/monsters/hknight.mdl",
460 HELLKNIGHT_MIN, HELLKNIGHT_MAX,
462 hellknight_die, hellknight_spawn))
468 precache_sound ("weapons/spike.wav");
471 // compatibility with old spawns
472 void spawnfunc_monster_hellknight () { spawnfunc_monster_hell_knight(); }