3 const vector HELLKNIGHT_MIN = '-16 -16 -24';
4 const vector HELLKNIGHT_MAX = '16 16 32';
7 string HELLKNIGHT_MODEL = "models/monsters/hknight.mdl";
13 float autocvar_g_monster_hellknight;
14 float autocvar_g_monster_hellknight_health;
15 float autocvar_g_monster_hellknight_melee_damage;
16 float autocvar_g_monster_hellknight_inferno_damage;
17 float autocvar_g_monster_hellknight_inferno_damagetime;
18 float autocvar_g_monster_hellknight_inferno_chance;
19 float autocvar_g_monster_hellknight_speed_walk;
20 float autocvar_g_monster_hellknight_speed_run;
21 float autocvar_g_monster_hellknight_fireball_damage;
22 float autocvar_g_monster_hellknight_fireball_force;
23 float autocvar_g_monster_hellknight_fireball_radius;
24 float autocvar_g_monster_hellknight_fireball_chance;
25 float autocvar_g_monster_hellknight_fireball_edgedamage;
26 float autocvar_g_monster_hellknight_spike_chance;
27 float autocvar_g_monster_hellknight_spike_force;
28 float autocvar_g_monster_hellknight_spike_radius;
29 float autocvar_g_monster_hellknight_spike_edgedamage;
30 float autocvar_g_monster_hellknight_spike_damage;
31 float autocvar_g_monster_hellknight_jump_chance;
32 float autocvar_g_monster_hellknight_jump_damage;
33 float autocvar_g_monster_hellknight_jump_dist;
36 const float hellknight_anim_stand = 0;
37 const float hellknight_anim_walk = 1;
38 const float hellknight_anim_run = 2;
39 const float hellknight_anim_pain = 3;
40 const float hellknight_anim_death1 = 4;
41 const float hellknight_anim_death2 = 5;
42 const float hellknight_anim_charge1 = 6;
43 const float hellknight_anim_magic1 = 7;
44 const float hellknight_anim_magic2 = 8;
45 const float hellknight_anim_charge2 = 9;
46 const float hellknight_anim_slice = 10;
47 const float hellknight_anim_smash = 11;
48 const float hellknight_anim_wattack = 12;
49 const float hellknight_anim_magic3 = 13;
51 void hknight_spike_think()
55 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);
60 void hknight_spike_touch()
64 pointparticles(particleeffectnum("TE_WIZSPIKE"), self.origin, '0 0 0', 1);
66 hknight_spike_think();
69 void() hellknight_think;
72 local entity missile = world;
73 local vector dir = normalize((self.enemy.origin + '0 0 10') - self.origin);
74 local float dist = vlen (self.enemy.origin - self.origin), flytime = 0;
76 flytime = dist * 0.002;
80 self.effects |= EF_MUZZLEFLASH;
81 sound (self, CHAN_WEAPON, "weapons/spike.wav", 1, ATTN_NORM);
84 missile.owner = missile.realowner = self;
85 missile.solid = SOLID_TRIGGER;
86 missile.movetype = MOVETYPE_FLYMISSILE;
87 setsize (missile, '0 0 0', '0 0 0');
88 setorigin(missile, self.origin + '0 0 10' + v_forward * 14);
89 missile.scale = self.scale;
90 missile.flags = FL_PROJECTILE;
91 missile.velocity = dir * 400;
92 missile.avelocity = '300 300 300';
93 missile.nextthink = time + 5;
94 missile.think = hknight_spike_think;
95 missile.enemy = self.enemy;
96 missile.touch = hknight_spike_touch;
97 CSQCProjectile(missile, TRUE, PROJECTILE_CRYLINK, TRUE);
100 void hknight_inferno ()
102 traceline((self.absmin + self.absmax) * 0.5, (self.enemy.absmin + self.enemy.absmax) * 0.5, TRUE, world);
103 if (trace_fraction != 1)
104 return; // not visible
105 if(vlen(self.enemy.origin - self.origin) <= 2000)
106 Fire_AddDamage(self.enemy, self, autocvar_g_monster_hellknight_inferno_damage * monster_skill, autocvar_g_monster_hellknight_inferno_damagetime, DEATH_MONSTER_HKNIGHT_INFERNO);
109 void hknight_infernowarning ()
114 traceline((self.absmin + self.absmax) * 0.5, (self.enemy.absmin + self.enemy.absmax) * 0.5, TRUE, world);
115 if (trace_fraction != 1)
116 return; // not visible
117 self.enemy.effects |= EF_MUZZLEFLASH;
118 sound(self.enemy, CHAN_AUTO, "player/lava.wav", 1, ATTN_NORM);
123 float() hknight_magic;
124 float hknight_checkmagic ()
126 local vector v1 = '0 0 0', v2 = '0 0 0';
129 // use magic to kill zombies as they heal too fast for sword
130 if (self.enemy.monsterid == MONSTER_ZOMBIE)
132 traceline((self.absmin + self.absmax) * 0.5, (self.enemy.absmin + self.enemy.absmax) * 0.5, FALSE, self);
133 if (trace_ent == self.enemy)
141 return FALSE; // 25% of the time it won't do anything
142 v1 = normalize(self.enemy.velocity);
143 v2 = normalize(self.enemy.origin - self.origin);
145 if (dot >= 0.7) // moving away
146 if (vlen(self.enemy.velocity) >= 150) // walking/running away
147 return hknight_magic();
151 void() hellknight_charge;
152 void CheckForCharge ()
154 // check for mad charge
155 if (time < self.attack_finished_single)
157 if (fabs(self.origin_z - self.enemy.origin_z) > 20)
158 return; // too much height change
159 if (vlen (self.origin - self.enemy.origin) < 80)
160 return; // use regular attack
161 if (hknight_checkmagic())
162 return; // chose magic
168 void CheckContinueCharge ()
170 if(hknight_checkmagic())
171 return; // chose magic
172 if(time >= self.attack_finished_single)
175 return; // done charging
179 void hellknight_think ()
181 self.think = hellknight_think;
182 self.nextthink = time + self.ticrate;
184 monster_move(autocvar_g_monster_hellknight_speed_run, autocvar_g_monster_hellknight_speed_walk, 100, hellknight_anim_run, hellknight_anim_walk, hellknight_anim_stand);
187 .float hknight_cycles;
188 void hellknight_magic ()
190 self.hknight_cycles += 1;
191 self.think = hellknight_magic;
193 if(self.hknight_cycles >= 5)
195 monsters_setframe(hellknight_anim_magic1);
196 self.attack_finished_single = time + 0.7;
197 hknight_infernowarning();
198 self.think = hellknight_think;
201 self.nextthink = time + 0.1;
204 void hknight_fireball_explode(entity targ)
206 float scle = self.realowner.scale;
209 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);
211 Fire_AddDamage(targ, self, 5 * monster_skill, autocvar_g_monster_hellknight_inferno_damagetime, self.projectiledeathtype);
216 void hknight_fireball_think()
218 hknight_fireball_explode(world);
221 void hknight_fireball_touch()
225 hknight_fireball_explode(other);
228 void hellknight_fireball ()
230 local entity missile = spawn();
231 local vector dir = normalize((self.enemy.origin + '0 0 10') - self.origin);
232 vector fmins = ((self.scale >= 2) ? '-16 -16 -16' : '-4 -4 -4'), fmaxs = ((self.scale >= 2) ? '16 16 16' : '4 4 4');
234 self.effects |= EF_MUZZLEFLASH;
235 sound (self, CHAN_WEAPON, "weapons/fireball2.wav", 1, ATTN_NORM);
237 missile.owner = missile.realowner = self;
238 missile.solid = SOLID_TRIGGER;
239 missile.movetype = MOVETYPE_FLYMISSILE;
240 self.projectiledeathtype = DEATH_MONSTER_HKNIGHT_FBALL;
241 setsize (missile, fmins, fmaxs);
242 setorigin(missile, self.origin + '0 0 10' + v_forward * 14);
243 missile.flags = FL_PROJECTILE;
244 missile.velocity = dir * 400;
245 missile.avelocity = '300 300 300';
246 missile.nextthink = time + 5;
247 missile.think = hknight_fireball_think;
248 missile.enemy = self.enemy;
249 missile.touch = hknight_fireball_touch;
250 CSQCProjectile(missile, TRUE, ((self.scale >= 2) ? PROJECTILE_FIREBALL : PROJECTILE_FIREMINE), TRUE);
255 void hellknight_magic2 ()
257 monsters_setframe(hellknight_anim_magic2);
258 self.attack_finished_single = time + 1.2;
259 self.delay = time + 0.4;
260 self.monster_delayedattack = hellknight_fireball;
263 void hellknight_spikes ()
265 self.think = hellknight_spikes;
266 self.nextthink = time + 0.1;
267 self.hknight_cycles += 1;
269 if(self.hknight_cycles >= 7)
270 self.think = hellknight_think;
273 void hellknight_magic3 ()
275 monsters_setframe(hellknight_anim_magic3);
276 self.attack_finished_single = time + 1;
277 self.think = hellknight_spikes;
278 self.nextthink = time + 0.4;
281 void hellknight_charge ()
283 monsters_setframe(hellknight_anim_charge1);
284 self.attack_finished_single = time + 0.5;
286 hknight_checkmagic();
287 monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, FALSE);
288 hknight_checkmagic();
291 void hellknight_charge2 ()
293 monsters_setframe(hellknight_anim_charge2);
294 self.attack_finished_single = time + 0.5;
296 CheckContinueCharge ();
297 monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, FALSE);
300 void hellknight_slice ()
302 monsters_setframe(hellknight_anim_slice);
303 self.attack_finished_single = time + 0.7;
304 monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, FALSE);
307 void hellknight_smash ()
309 monsters_setframe(hellknight_anim_smash);
310 self.attack_finished_single = time + 0.7;
311 monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, TRUE);
314 void hellknight_weapon_attack ()
316 monsters_setframe(hellknight_anim_wattack);
317 self.attack_finished_single = time + 0.7;
318 monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, TRUE);
322 void hknight_melee ()
326 if (hknight_type == 1)
328 else if (hknight_type == 2)
332 hellknight_weapon_attack();
337 float hknight_magic ()
339 if not(self.flags & FL_ONGROUND)
343 return FALSE; // calling attack check with no enemy?!
345 if(time < self.attack_finished_single)
348 self.hknight_cycles = 0;
350 if (self.enemy.monsterid == MONSTER_ZOMBIE)
352 // always use fireball to kill zombies
354 self.attack_finished_single = time + 2;
357 RandomSelection_Init();
358 RandomSelection_Add(world, 0, "fireball", autocvar_g_monster_hellknight_fireball_chance, 1);
359 RandomSelection_Add(world, 0, "inferno", autocvar_g_monster_hellknight_inferno_chance, 1);
360 RandomSelection_Add(world, 0, "spikes", autocvar_g_monster_hellknight_spike_chance, 1);
361 if(self.health >= 100)
362 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);
364 switch(RandomSelection_chosen_string)
369 self.attack_finished_single = time + 2;
375 self.attack_finished_single = time + 3;
381 self.attack_finished_single = time + 3;
386 if (vlen(self.enemy.origin - self.origin) >= 400)
387 if (findtrajectorywithleading(self.origin, self.mins, self.maxs, self.enemy, 1000, 0, 10, 0, self))
389 self.velocity = findtrajectory_velocity;
390 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));
391 self.attack_finished_single = time + 2;
402 void hellknight_die ()
404 float chance = random();
405 Monster_CheckDropCvars ("hellknight");
407 self.think = Monster_Fade;
408 self.nextthink = time + 5;
409 monsters_setframe((random() > 0.5) ? hellknight_anim_death1 : hellknight_anim_death2);
411 if(chance < 0.10 || self.flags & MONSTERFLAG_MINIBOSS)
414 self.superweapons_finished = time + autocvar_g_balance_superweapons_time + 5; // give the player a few seconds to find the weapon
415 self.weapon = WEP_FIREBALL;
418 monster_hook_death(); // for post-death mods
421 void hellknight_spawn ()
424 self.health = autocvar_g_monster_hellknight_health * self.scale;
426 self.damageforcescale = 0.003;
427 self.classname = "monster_hellknight";
428 self.checkattack = GenericCheckAttack;
429 self.attack_melee = hknight_melee;
430 self.attack_ranged = hknight_magic;
431 self.nextthink = time + random() * 0.5 + 0.1;
432 self.think = hellknight_think;
433 self.sprite_height = 30;
435 monsters_setframe(hellknight_anim_stand);
437 monster_hook_spawn(); // for post-spawn mods
440 void spawnfunc_monster_hell_knight ()
442 if not(autocvar_g_monster_hellknight) { remove(self); return; }
444 self.monster_spawnfunc = spawnfunc_monster_hell_knight;
446 if(Monster_CheckAppearFlags(self))
451 if not (monster_initialize(
452 "Hell-knight", MONSTER_HELLKNIGHT,
453 HELLKNIGHT_MIN, HELLKNIGHT_MAX,
455 hellknight_die, hellknight_spawn))
461 precache_sound ("weapons/spike.wav");
464 // compatibility with old spawns
465 void spawnfunc_monster_hellknight () { spawnfunc_monster_hell_knight(); }