2 const vector SHALRATH_MIN = '-32 -32 -24';
3 const vector SHALRATH_MAX = '32 32 32';
6 float autocvar_g_monster_shalrath;
7 float autocvar_g_monster_shalrath_health;
8 float autocvar_g_monster_shalrath_speed;
9 float autocvar_g_monster_shalrath_attack_spike_damage;
10 float autocvar_g_monster_shalrath_attack_spike_radius;
11 float autocvar_g_monster_shalrath_attack_spike_delay;
12 float autocvar_g_monster_shalrath_attack_melee_damage;
13 float autocvar_g_monster_shalrath_attack_melee_delay;
16 #define shalrath_anim_idle 0
17 #define shalrath_anim_walk 1
18 #define shalrath_anim_attack 2
19 #define shalrath_anim_pain 3
20 #define shalrath_anim_death 4
21 #define shalrath_anim_run 5
26 void shalrath_think ()
28 self.think = shalrath_think;
29 self.nextthink = time + 0.1;
32 self.nextthink = self.delay;
34 monster_move(autocvar_g_monster_shalrath_speed, autocvar_g_monster_shalrath_speed, 50, shalrath_anim_walk, shalrath_anim_run, shalrath_anim_idle);
37 void shalrath_attack ()
39 self.frame = shalrath_anim_attack;
40 self.delay = time + 0.2;
41 self.attack_finished_single = time + autocvar_g_monster_shalrath_attack_spike_delay;
42 self.monster_delayedattack = ShalMissile;
45 void shalrathattack_melee ()
47 float bigdmg = 0, rdmg = autocvar_g_monster_shalrath_attack_melee_damage * random();
49 bigdmg = rdmg * self.scale;
51 monster_melee(self.enemy, bigdmg * monster_skill, 120, DEATH_MONSTER_MAGE);
54 void shalrath_attack_melee ()
56 self.monster_delayedattack = shalrathattack_melee;
57 self.delay = time + 0.2;
58 self.frame = shalrath_anim_attack;
59 self.attack_finished_single = time + autocvar_g_monster_shalrath_attack_melee_delay;
64 // don't throw if it is blocked
65 traceline(self.origin + '0 0 10', self.enemy.origin + '0 0 10', FALSE, self);
66 if (vlen(self.enemy.origin - self.origin) > 1000)
68 if (trace_ent != self.enemy)
76 local vector dir = '0 0 0', vtemp = self.enemy.origin + '0 0 10';
78 if (self.enemy.health <= 0 || self.owner.health <= 0 || time >= self.ltime)
83 dir = normalize(vtemp - self.origin);
84 UpdateCSQCProjectile(self);
85 if (monster_skill == 3)
86 self.velocity = dir * 350;
88 self.velocity = dir * 250;
89 self.nextthink = time + 0.2;
90 self.think = ShalHome;
93 void shal_spike_explode ()
95 self.event_damage = func_null;
97 pointparticles(particleeffectnum("explosion_small"), self.origin, '0 0 0', 1);
98 RadiusDamage (self, self.realowner, autocvar_g_monster_shalrath_attack_spike_damage, autocvar_g_monster_shalrath_attack_spike_damage * 0.5, autocvar_g_monster_shalrath_attack_spike_radius, world, 0, DEATH_MONSTER_MAGE, other);
103 void shal_spike_touchexplode()
107 shal_spike_explode();
112 local entity missile = world;
113 local vector dir = '0 0 0';
114 local float dist = 0;
116 self.effects |= EF_MUZZLEFLASH;
119 missile.owner = missile.realowner = self;
121 self.v_angle = self.angles;
122 makevectors (self.angles);
124 dir = normalize((self.enemy.origin + '0 0 10') - self.origin);
125 dist = vlen (self.enemy.origin - self.origin);
127 missile.think = ShalHome;
128 missile.ltime = time + 7;
129 missile.nextthink = time;
130 missile.solid = SOLID_BBOX;
131 missile.movetype = MOVETYPE_FLYMISSILE;
132 missile.flags = FL_PROJECTILE;
133 setorigin (missile, self.origin + v_forward * 14 + '0 0 30' + v_right * -14);
134 setsize (missile, '0 0 0', '0 0 0');
135 missile.velocity = dir * 400;
136 missile.avelocity = '300 300 300';
137 missile.enemy = self.enemy;
138 missile.touch = shal_spike_touchexplode;
140 CSQCProjectile(missile, TRUE, PROJECTILE_VORE_SPIKE, TRUE);
143 float ShalrathCheckAttack ()
145 local vector spot1 = '0 0 0', spot2 = '0 0 0';
146 local entity targ = self.enemy;
148 if (self.health <= 0 || targ == world || targ.health < 1)
151 if(self.monster_delayedattack && self.delay != -1)
153 if(time < self.delay)
156 self.monster_delayedattack();
158 self.monster_delayedattack = func_null;
161 if(time < self.attack_finished_single)
164 if (vlen(self.enemy.origin - self.origin) <= 120)
166 if (self.attack_melee)
168 monster_sound(self.msound_attack_melee, 0, FALSE); // no delay for attack sounds
174 if (vlen(targ.origin - self.origin) >= 2000) // long traces are slow
177 // see if any entities are in the way of the shot
178 spot1 = self.origin + '0 0 10';
179 spot2 = targ.origin + '0 0 10';
181 traceline (spot1, spot2, FALSE, self);
183 if (trace_ent != targ && trace_fraction < 1)
184 return FALSE; // don't have a clear shot
186 //if (trace_inopen && trace_inwater)
187 // return FALSE; // sight line crossed contents
190 if (self.attack_ranged())
198 Monster_CheckDropCvars ("shalrath");
200 self.think = Monster_Fade;
201 self.frame = shalrath_anim_death;
202 self.solid = SOLID_NOT;
203 self.takedamage = DAMAGE_NO;
204 self.event_damage = func_null;
206 self.nextthink = time + 2.1;
207 self.movetype = MOVETYPE_TOSS;
209 monster_hook_death(); // for post-death mods
212 void shalrath_spawn ()
215 self.health = autocvar_g_monster_shalrath_health * self.scale;
217 self.damageforcescale = 0.003;
218 self.classname = "monster_shalrath";
219 self.checkattack = ShalrathCheckAttack;
220 self.attack_ranged = shal_missile;
221 self.attack_melee = shalrath_attack_melee;
222 self.nextthink = time + random() * 0.5 + 0.1;
223 self.think = shalrath_think;
224 self.frame = shalrath_anim_walk;
225 self.sprite_height = 40 * self.scale;
227 monster_hook_spawn(); // for post-spawn mods
230 void spawnfunc_monster_shalrath ()
232 if not(autocvar_g_monster_shalrath) { remove(self); return; }
234 self.monster_spawnfunc = spawnfunc_monster_shalrath;
236 if(self.spawnflags & MONSTERFLAG_APPEAR)
238 self.think = func_null;
240 self.use = Monster_Appear;
247 if not (monster_initialize(
249 "models/monsters/mage.dpm",
250 SHALRATH_MIN, SHALRATH_MAX,
252 shalrath_die, shalrath_spawn))
259 // compatibility with old spawns
260 void spawnfunc_monster_vore () { spawnfunc_monster_shalrath(); }