]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/monsters/monster/shalrath.qc
Merge branch 'master' into mario/monsters
[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 void() ShalHome;
68 void ShalMissile_Spawn ()
69 {
70         local   vector  dir = '0 0 0';
71         local   float   dist = 0;
72         
73         self.realowner.effects |= EF_MUZZLEFLASH;
74         
75         dir = normalize((self.owner.enemy.origin + '0 0 10') - self.owner.origin);
76         dist = vlen (self.owner.enemy.origin - self.owner.origin);
77         
78         self.solid = SOLID_BBOX;
79         self.movetype = MOVETYPE_FLYMISSILE;
80         CSQCProjectile(self, TRUE, PROJECTILE_CRYLINK, TRUE);
81         
82         self.realowner.v_angle = self.realowner.angles;
83         makevectors (self.realowner.angles);
84
85         setsize (self, '0 0 0', '0 0 0');               
86
87         setorigin (self, self.realowner.origin + v_forward * 14 + '0 0 30' + v_right * -14);
88         self.velocity = dir * 400;
89         self.avelocity = '300 300 300';
90         self.enemy = self.realowner.enemy;
91         self.touch = W_Plasma_TouchExplode;
92         ShalHome();
93 }
94
95 void ShalMissile ()
96 {
97         local   entity  missile = world;
98
99         sound (self, CHAN_WEAPON, "weapons/spike.wav", 1, ATTN_NORM);
100
101         missile = spawn ();
102         missile.owner = missile.realowner = self;
103
104         missile.think = ShalMissile_Spawn;
105         missile.nextthink = time;
106 }
107
108 .float shal_cycles;
109 void ShalHome ()
110 {
111         local vector dir = '0 0 0', vtemp = self.enemy.origin + '0 0 10';
112         
113         self.shal_cycles += 1;
114         if (self.enemy.health <= 0 || self.owner.health <= 0 || self.shal_cycles >= 20)
115         {
116                 remove(self);
117                 return;
118         }
119         dir = normalize(vtemp - self.origin);
120         UpdateCSQCProjectile(self);
121         if (autocvar_skill == 3)
122                 self.velocity = dir * 350;
123         else
124                 self.velocity = dir * 250;
125         self.nextthink = time + 0.2;
126         self.think = ShalHome;  
127 }
128
129 float ShalrathCheckAttack ()
130 {
131         local vector spot1 = '0 0 0', spot2 = '0 0 0';
132         local entity targ = self.enemy;
133
134         if (self.health <= 0 || targ == world || targ.health < 1)
135                 return FALSE;
136         
137         if(self.monster_delayedattack && self.delay != -1)
138         {
139                 if(time < self.delay)
140                         return FALSE;
141                         
142                 self.monster_delayedattack();
143                 self.delay = -1;
144                 self.monster_delayedattack = func_null;
145         }
146         
147         if(time < self.attack_finished_single)
148                 return FALSE;
149         
150         if (vlen(self.enemy.origin - self.origin) <= 120)
151         {       // melee attack
152                 if (self.attack_melee)
153                 {
154                         self.attack_melee();
155                         return TRUE;
156                 }
157         }
158
159         if (vlen(targ.origin - self.origin) >= 2000) // long traces are slow
160                 return FALSE;
161
162 // see if any entities are in the way of the shot
163         spot1 = self.origin + '0 0 10';
164         spot2 = targ.origin + '0 0 10';
165
166         traceline (spot1, spot2, FALSE, self);
167
168         if (trace_ent != targ && trace_fraction < 1)
169                 return FALSE; // don't have a clear shot
170
171         //if (trace_inopen && trace_inwater)
172         //      return FALSE; // sight line crossed contents
173
174         if (random() < 0.2)
175         if (self.attack_ranged())
176                 return TRUE;
177
178         return FALSE;
179 }
180
181 void shalrath_die ()
182 {
183         Monster_CheckDropCvars ("shalrath");
184         
185         self.think                      = Monster_Fade;
186         self.frame                      = shalrath_anim_death;
187         self.solid                      = SOLID_NOT;
188         self.takedamage         = DAMAGE_NO;
189         self.event_damage   = func_null;
190         self.enemy                      = world;
191         self.nextthink          = time + 2.1;
192         self.pain_finished  = self.nextthink;   
193         self.movetype           = MOVETYPE_TOSS;
194         
195         monster_hook_death(); // for post-death mods
196 }
197
198 void shalrath_spawn ()
199 {
200         if not(self.health)
201                 self.health = autocvar_g_monster_shalrath_health * self.scale;
202
203         self.damageforcescale   = 0.003;
204         self.classname                  = "monster_shalrath";
205         self.checkattack                = ShalrathCheckAttack;
206         self.attack_ranged              = shal_missile;
207         self.attack_melee               = shalrath_attack_melee;
208         self.nextthink                  = time + random() * 0.5 + 0.1;
209         self.think                              = shalrath_think;
210         self.frame                              = shalrath_anim_walk;
211         self.sprite_height              = 40 * self.scale;
212         
213         monster_hook_spawn(); // for post-spawn mods
214 }
215
216 void spawnfunc_monster_shalrath ()
217 {       
218         if not(autocvar_g_monster_shalrath)
219         {
220                 remove(self);
221                 return;
222         }
223         
224         self.monster_spawnfunc = spawnfunc_monster_shalrath;
225         
226         if(self.spawnflags & MONSTERFLAG_APPEAR)
227         {
228                 self.think = func_null;
229                 self.nextthink = -1;
230                 self.use = Monster_Appear;
231                 
232                 return;
233         }
234         
235         self.scale = 1.3;
236         
237         if not (monster_initialize(
238                          "Vore",
239                          "models/monsters/shalrath.mdl",
240                          SHALRATH_MIN, SHALRATH_MAX,
241                          FALSE,
242                          shalrath_die, shalrath_spawn))
243         {
244                 remove(self);
245                 return;
246         }
247 }
248
249 // compatibility with old spawns
250 void spawnfunc_monster_vore () { spawnfunc_monster_shalrath(); }