]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/monsters/monster/shalrath.qc
Add FLAC Cannon support to TD
[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_damage;
9 float autocvar_g_monster_shalrath_speed;
10
11 // animations
12 #define shalrath_anim_attack    0
13 #define shalrath_anim_pain              1
14 #define shalrath_anim_death     2
15 #define shalrath_anim_walk              3
16
17 void() ShalMissile;
18
19 void shalrath_think ()
20 {
21         self.think = shalrath_think;
22         self.nextthink = time + 0.1;
23         
24         if(self.delay != -1)
25                 self.nextthink = self.delay;
26         
27         monster_move(autocvar_g_monster_shalrath_speed, autocvar_g_monster_shalrath_speed, 50, shalrath_anim_walk, shalrath_anim_walk, shalrath_anim_walk);
28 }
29
30 void shalrath_attack ()
31 {
32         self.frame = shalrath_anim_attack;
33         self.delay = time + 0.1;
34         self.attack_finished_single = time + 0.7;
35         self.monster_delayedattack = ShalMissile;
36 }
37
38 void shalrathattack_melee ()
39 {
40         float bigdmg = 0, rdmg = autocvar_g_monster_shalrath_damage * random();
41
42         bigdmg = rdmg * self.scale;
43
44         monster_melee(self.enemy, bigdmg * monster_skill, 120, DEATH_MONSTER_SHALRATH_MELEE);
45 }
46
47 void shalrath_attack_melee ()
48 {
49         self.monster_delayedattack = shalrathattack_melee;
50         self.delay = time + 0.2;
51         self.frame = shalrath_anim_attack;
52         self.attack_finished_single = time + 0.7;
53 }
54
55 float shal_missile ()
56 {
57         // don't throw if it is blocked
58         traceline(self.origin + '0 0 10', self.enemy.origin + '0 0 10', FALSE, self);
59         if (enemy_range() > 1000)
60                 return FALSE;
61         if (trace_ent != self.enemy)
62                 return FALSE;
63         shalrath_attack();
64         return TRUE;
65 }
66
67 .float shal_cycles;
68 void ShalHome ()
69 {
70         local vector dir = '0 0 0', vtemp = self.enemy.origin + '0 0 10';
71         
72         self.shal_cycles += 1;
73         if (self.enemy.health <= 0 || self.owner.health <= 0 || self.shal_cycles >= 20)
74         {
75                 remove(self);
76                 return;
77         }
78         dir = normalize(vtemp - self.origin);
79         UpdateCSQCProjectile(self);
80         if (monster_skill == 3)
81                 self.velocity = dir * 350;
82         else
83                 self.velocity = dir * 250;
84         self.nextthink = time + 0.2;
85         self.think = ShalHome;  
86 }
87
88 void ShalMissile ()
89 {
90         local   entity  missile = world;
91         local   vector  dir = '0 0 0';
92         local   float   dist = 0;
93         
94         self.effects |= EF_MUZZLEFLASH;
95
96         sound (self, CHAN_WEAPON, "weapons/spike.wav", 1, ATTN_NORM);
97
98         missile = spawn ();
99         missile.owner = missile.realowner = self;
100         
101         self.v_angle = self.angles;
102         makevectors (self.angles);
103         
104         dir = normalize((self.enemy.origin + '0 0 10') - self.origin);
105         dist = vlen (self.enemy.origin - self.origin);
106
107         missile.think = ShalHome;
108         missile.nextthink = time;
109         missile.solid = SOLID_BBOX;
110         missile.movetype = MOVETYPE_FLYMISSILE;
111         missile.flags = FL_PROJECTILE;
112         setorigin (missile, self.origin + v_forward * 14 + '0 0 30' + v_right * -14);
113         setsize (missile, '0 0 0', '0 0 0');    
114         missile.velocity = dir * 400;
115         missile.avelocity = '300 300 300';
116         missile.enemy = self.enemy;
117         missile.touch = W_Plasma_TouchExplode;
118         
119         CSQCProjectile(missile, TRUE, PROJECTILE_CRYLINK, TRUE);
120 }
121
122 float ShalrathCheckAttack ()
123 {
124         local vector spot1 = '0 0 0', spot2 = '0 0 0';
125         local entity targ = self.enemy;
126
127         if (self.health <= 0 || targ == world || targ.health < 1)
128                 return FALSE;
129         
130         if(self.monster_delayedattack && self.delay != -1)
131         {
132                 if(time < self.delay)
133                         return FALSE;
134                         
135                 self.monster_delayedattack();
136                 self.delay = -1;
137                 self.monster_delayedattack = func_null;
138         }
139         
140         if(time < self.attack_finished_single)
141                 return FALSE;
142         
143         if (vlen(self.enemy.origin - self.origin) <= 120)
144         {       // melee attack
145                 if (self.attack_melee)
146                 {
147                         self.attack_melee();
148                         return TRUE;
149                 }
150         }
151
152         if (vlen(targ.origin - self.origin) >= 2000) // long traces are slow
153                 return FALSE;
154
155 // see if any entities are in the way of the shot
156         spot1 = self.origin + '0 0 10';
157         spot2 = targ.origin + '0 0 10';
158
159         traceline (spot1, spot2, FALSE, self);
160
161         if (trace_ent != targ && trace_fraction < 1)
162                 return FALSE; // don't have a clear shot
163
164         //if (trace_inopen && trace_inwater)
165         //      return FALSE; // sight line crossed contents
166
167         if (random() < 0.2)
168         if (self.attack_ranged())
169                 return TRUE;
170
171         return FALSE;
172 }
173
174 void shalrath_die ()
175 {
176         Monster_CheckDropCvars ("shalrath");
177         
178         self.think                      = Monster_Fade;
179         self.frame                      = shalrath_anim_death;
180         self.solid                      = SOLID_NOT;
181         self.takedamage         = DAMAGE_NO;
182         self.event_damage   = func_null;
183         self.enemy                      = world;
184         self.nextthink          = time + 2.1;
185         self.pain_finished  = self.nextthink;   
186         self.movetype           = MOVETYPE_TOSS;
187         
188         monster_hook_death(); // for post-death mods
189 }
190
191 void shalrath_spawn ()
192 {
193         if not(self.health)
194                 self.health = autocvar_g_monster_shalrath_health * self.scale;
195
196         self.damageforcescale   = 0.003;
197         self.classname                  = "monster_shalrath";
198         self.checkattack                = ShalrathCheckAttack;
199         self.attack_ranged              = shal_missile;
200         self.attack_melee               = shalrath_attack_melee;
201         self.nextthink                  = time + random() * 0.5 + 0.1;
202         self.think                              = shalrath_think;
203         self.frame                              = shalrath_anim_walk;
204         self.sprite_height              = 40 * self.scale;
205         
206         monster_hook_spawn(); // for post-spawn mods
207 }
208
209 void spawnfunc_monster_shalrath ()
210 {       
211         if not(autocvar_g_monster_shalrath)
212         {
213                 remove(self);
214                 return;
215         }
216         
217         self.monster_spawnfunc = spawnfunc_monster_shalrath;
218         
219         if(self.spawnflags & MONSTERFLAG_APPEAR)
220         {
221                 self.think = func_null;
222                 self.nextthink = -1;
223                 self.use = Monster_Appear;
224                 
225                 return;
226         }
227         
228         self.scale = 1.3;
229         
230         if not (monster_initialize(
231                          "Vore",
232                          "models/monsters/shalrath.mdl",
233                          SHALRATH_MIN, SHALRATH_MAX,
234                          FALSE,
235                          shalrath_die, shalrath_spawn))
236         {
237                 remove(self);
238                 return;
239         }
240 }
241
242 // compatibility with old spawns
243 void spawnfunc_monster_vore () { spawnfunc_monster_shalrath(); }