]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/monsters/monster/shalrath.qc
Remove enemy_range() checks
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / monsters / monster / shalrath.qc
1 // size
2 const vector SHALRATH_MIN = '-32 -32 -24';
3 const vector SHALRATH_MAX = '32 32 32';
4
5 // cvars
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;
14
15 // animations
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
22
23
24 void() ShalMissile;
25
26 void shalrath_think ()
27 {
28         self.think = shalrath_think;
29         self.nextthink = time + 0.1;
30         
31         if(self.delay != -1)
32                 self.nextthink = self.delay;
33         
34         monster_move(autocvar_g_monster_shalrath_speed, autocvar_g_monster_shalrath_speed, 50, shalrath_anim_walk, shalrath_anim_run, shalrath_anim_idle);
35 }
36
37 void shalrath_attack ()
38 {
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;
43 }
44
45 void shalrathattack_melee ()
46 {
47         float bigdmg = 0, rdmg = autocvar_g_monster_shalrath_attack_melee_damage * random();
48
49         bigdmg = rdmg * self.scale;
50
51         monster_melee(self.enemy, bigdmg * monster_skill, 120, DEATH_MONSTER_MAGE);
52 }
53
54 void shalrath_attack_melee ()
55 {
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;
60 }
61
62 float shal_missile ()
63 {
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)
67                 return FALSE;
68         if (trace_ent != self.enemy)
69                 return FALSE;
70         shalrath_attack();
71         return TRUE;
72 }
73
74 void ShalHome ()
75 {
76         local vector dir = '0 0 0', vtemp = self.enemy.origin + '0 0 10';
77         
78         if (self.enemy.health <= 0 || self.owner.health <= 0 || time >= self.ltime)
79         {
80                 remove(self);
81                 return;
82         }
83         dir = normalize(vtemp - self.origin);
84         UpdateCSQCProjectile(self);
85         if (monster_skill == 3)
86                 self.velocity = dir * 350;
87         else
88                 self.velocity = dir * 250;
89         self.nextthink = time + 0.2;
90         self.think = ShalHome;  
91 }
92
93 void shal_spike_explode ()
94 {
95         self.event_damage = func_null;
96
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);
99
100         remove (self);
101 }
102
103 void shal_spike_touchexplode()
104 {
105         PROJECTILE_TOUCH;
106
107         shal_spike_explode();
108 }
109
110 void ShalMissile ()
111 {
112         local   entity  missile = world;
113         local   vector  dir = '0 0 0';
114         local   float   dist = 0;
115         
116         self.effects |= EF_MUZZLEFLASH;
117
118         missile = spawn ();
119         missile.owner = missile.realowner = self;
120         
121         self.v_angle = self.angles;
122         makevectors (self.angles);
123         
124         dir = normalize((self.enemy.origin + '0 0 10') - self.origin);
125         dist = vlen (self.enemy.origin - self.origin);
126
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;
139         
140         CSQCProjectile(missile, TRUE, PROJECTILE_VORE_SPIKE, TRUE);
141 }
142
143 float ShalrathCheckAttack ()
144 {
145         local vector spot1 = '0 0 0', spot2 = '0 0 0';
146         local entity targ = self.enemy;
147
148         if (self.health <= 0 || targ == world || targ.health < 1)
149                 return FALSE;
150         
151         if(self.monster_delayedattack && self.delay != -1)
152         {
153                 if(time < self.delay)
154                         return FALSE;
155                         
156                 self.monster_delayedattack();
157                 self.delay = -1;
158                 self.monster_delayedattack = func_null;
159         }
160         
161         if(time < self.attack_finished_single)
162                 return FALSE;
163         
164         if (vlen(self.enemy.origin - self.origin) <= 120)
165         {       // melee attack
166                 if (self.attack_melee)
167                 {
168                         monster_sound(self.msound_attack_melee, 0, FALSE); // no delay for attack sounds
169                         self.attack_melee();
170                         return TRUE;
171                 }
172         }
173
174         if (vlen(targ.origin - self.origin) >= 2000) // long traces are slow
175                 return FALSE;
176
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';
180
181         traceline (spot1, spot2, FALSE, self);
182
183         if (trace_ent != targ && trace_fraction < 1)
184                 return FALSE; // don't have a clear shot
185
186         //if (trace_inopen && trace_inwater)
187         //      return FALSE; // sight line crossed contents
188
189         if (random() < 0.2)
190         if (self.attack_ranged())
191                 return TRUE;
192
193         return FALSE;
194 }
195
196 void shalrath_die ()
197 {
198         Monster_CheckDropCvars ("shalrath");
199         
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;
205         self.enemy                      = world;
206         self.nextthink          = time + 2.1;   
207         self.movetype           = MOVETYPE_TOSS;
208         
209         monster_hook_death(); // for post-death mods
210 }
211
212 void shalrath_spawn ()
213 {
214         if not(self.health)
215                 self.health = autocvar_g_monster_shalrath_health * self.scale;
216
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;
226         
227         monster_hook_spawn(); // for post-spawn mods
228 }
229
230 void spawnfunc_monster_shalrath ()
231 {       
232         if not(autocvar_g_monster_shalrath) { remove(self); return; }
233         
234         self.monster_spawnfunc = spawnfunc_monster_shalrath;
235         
236         if(self.spawnflags & MONSTERFLAG_APPEAR)
237         {
238                 self.think = func_null;
239                 self.nextthink = -1;
240                 self.use = Monster_Appear;
241                 
242                 return;
243         }
244         
245         self.scale = 1.3;
246         
247         if not (monster_initialize(
248                          "Mage",
249                          "models/monsters/mage.dpm",
250                          SHALRATH_MIN, SHALRATH_MAX,
251                          FALSE,
252                          shalrath_die, shalrath_spawn))
253         {
254                 remove(self);
255                 return;
256         }
257 }
258
259 // compatibility with old spawns
260 void spawnfunc_monster_vore () { spawnfunc_monster_shalrath(); }