]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/client/tturrets.qc
Merge remote branch 'origin/master' into tzork/turrets-csqc
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / tturrets.qc
1 string tid2info_base;
2 string tid2info_head;
3 string tid2info_name;
4 vector  tid2info_min;
5 vector  tid2info_max;
6
7 void turrets_precache()
8 {
9     precache_model ("models/turrets/ewheel-base2.md3");
10     precache_model ("models/turrets/ewheel-gun1.md3");
11     precache_model ("models/turrets/base.md3");
12     precache_model ("models/turrets/flac.md3");
13     precache_model ("models/turrets/reactor.md3");
14     precache_model ("models/turrets/hellion.md3");
15     precache_model ("models/turrets/hk.md3");
16     precache_model ("models/turrets/machinegun.md3");
17     precache_model ("models/turrets/mlrs.md3");
18     precache_model ("models/turrets/phaser.md3");
19     precache_model ("models/turrets/phaser_beam.md3");
20     precache_model ("models/turrets/plasma.md3");
21     precache_model ("models/turrets/plasmad.md3");
22     precache_model ("models/turrets/tesla_head.md3");
23     precache_model ("models/turrets/tesla_base.md3");
24     precache_model ("models/turrets/walker_head_minigun.md3");
25     precache_model ("models/turrets/walker_body.md3");
26     precache_model ("models/turrets/rocket.md3");
27     
28     precache_sound ("turrets/phaser.wav");
29     precache_sound ("weapons/rocket_impact.wav");
30     precache_sound ("weapons/uzi_fire.wav");
31 }
32
33 void turret_tid2info(float _tid)
34 {
35     tid2info_base = "models/turrets/base.md3";
36     tid2info_min = '-32 -32 0';
37     tid2info_max = '32 32 64';
38
39     switch(_tid)
40     {
41         case TID_EWHEEL:
42             tid2info_base = "models/turrets/ewheel-base2.md3";
43             tid2info_head = "models/turrets/ewheel-gun1.md3";
44             tid2info_name = "eWheel";
45             break;
46         case TID_FLAC:
47             tid2info_head = "models/turrets/flac.md3";
48             tid2info_name = "Flac Cannon";
49             break;
50         case TID_FUSION:
51             tid2info_head = "models/turrets/reactor.md3";
52             tid2info_name = "Fusion Reactor";
53             tid2info_min = '-34 -34 0';
54             tid2info_max = '34 34 90';
55             break;
56         case TID_HELLION:
57             tid2info_head = "models/turrets/hellion.md3";
58             tid2info_name = "Hellion";
59             break;
60         case TID_HK:
61             tid2info_head = "models/turrets/hk.md3";
62             tid2info_name = "Hunter-Killer";
63             break;
64         case TID_MACHINEGUN:
65             tid2info_head = "models/turrets/machinegun.md3";
66             tid2info_name = "Machinegun";
67             break;
68         case TID_MLRS:
69             tid2info_head = "models/turrets/mlrs.md3";
70             tid2info_name = "MLRS";
71             break;
72         case TID_PHASER:
73             tid2info_head = "models/turrets/phaser.md3";
74             tid2info_name = "Phaser";
75             break;
76         case TID_PLASMA:
77             tid2info_head = "models/turrets/plasma.md3";
78             tid2info_name = "Plasma";
79             break;
80         case TID_PLASMA_DUAL:
81             tid2info_head = "models/turrets/plasmad.md3";
82             tid2info_name = "Dual Plasma";
83             break;
84         case TID_TESLA:
85             tid2info_base = "models/turrets/tesla_base.md3";
86             tid2info_head = "models/turrets/tesla_head.md3";
87             tid2info_name = "Tesla coil";
88             tid2info_min = '-60 -60 0';
89             tid2info_max  ='60 60 128';
90             break;
91         case TID_WALKER:
92             tid2info_base = "models/turrets/walker_body.md3";
93             tid2info_head = "models/turrets/walker_head_minigun.md3";
94             tid2info_name = "Walker";
95             tid2info_min = '-70 -70 0';
96             tid2info_max = '70 70 95';
97             break;
98     }    
99 }
100
101 void turret_remove()
102 {
103     turret_tid2info(self.turret_type);
104     dprint("Removing ", tid2info_name, " turrret.\n");
105     
106     remove(self.tur_head);
107     self.tur_head = world;    
108 }
109
110 void turret_changeteam()
111 {
112         self.colormod = '0 0 0';
113         
114         switch(self.team)
115         {
116         case COLOR_TEAM1: // Red
117             self.colormod = '2 0.5 0.5';
118             break;
119
120         case COLOR_TEAM2: // Blue
121             self.colormod = '0.5 0.5 2';
122             break;
123
124         case COLOR_TEAM3: // Yellow
125             self.colormod = '1.4 1.4 0.6';
126             break;
127
128         case COLOR_TEAM4: // Pink
129             self.colormod = '1.4 0.6 1.4';
130             break;
131         }
132         
133         self.tur_head.colormod = self.colormod;    
134 }
135
136 void turret_head_draw()
137 {    
138     self.drawmask = MASK_NORMAL;
139 }
140
141 void turret_draw()
142 {        
143     float dt;
144
145     dt = time - self.move_time;
146     self.move_time = time;
147     if(dt <= 0)
148         return;
149     
150     self.tur_head.angles += dt * self.tur_head.move_avelocity;
151
152     if (self.health < 127)
153     if(random() < 0.25)
154         te_spark(self.origin + '0 0 40', randomvec() * 256 + '0 0 256', 16);    
155 }
156
157
158 void turret_walker_draw()
159 {        
160     float dt;
161             
162     dt = time - self.move_time;
163     self.move_time = time;
164     if(dt <= 0)
165         return;
166     
167     fixedmakevectors(self.angles);
168     movelib_groundalign4point(300, 100, 0.25);
169     
170     setorigin(self, self.origin + self.velocity * dt);
171     setorigin(self.tur_head, gettaginfo(self, gettagindex(self, "tag_head")));
172     
173     self.tur_head.angles += dt * self.tur_head.move_avelocity;
174     
175     self.angles_y = self.move_angles_y;
176     
177     if (self.health < 127)
178     if(random() < 0.25)
179         te_spark(self.origin + '0 0 40', randomvec() * 256 + '0 0 256', 16);    
180 }
181
182 void turret_ewheel_draw()
183 {        
184     float dt;
185             
186     dt = time - self.move_time;
187     self.move_time = time;
188     if(dt <= 0)
189         return;
190     
191     fixedmakevectors(self.angles);
192     movelib_groundalign4point(300, 100, 0.25);
193     
194     setorigin(self, self.origin + self.velocity * dt);
195     setorigin(self.tur_head, self.origin);
196     
197     self.tur_head.angles += dt * self.tur_head.move_avelocity;
198     
199     // Simulate banking
200     //self.angles_z -= self.angles_z * dt * 2;
201     //self.angles_z = bound(-45, self.angles_z  + ((self.move_angles_y - self.angles_y * -25) * dt), 45);
202     
203     self.angles_y = self.move_angles_y;
204     
205     if (self.health < 127)
206     if(random() < 0.25)
207         te_spark(self.origin + '0 0 40', randomvec() * 256 + '0 0 256', 16);    
208 }
209
210 void turret_construct()
211 {    
212     if(self.tur_head == world)
213         self.tur_head = spawn();
214     
215     turret_tid2info(self.turret_type);
216     dprint("Constructing ", tid2info_name , " turret (", ftos(self.turret_type), ")\n");
217
218     setorigin(self, self.origin);
219     setmodel(self, tid2info_base);
220     setmodel(self.tur_head, tid2info_head);
221     setsize(self, tid2info_min, tid2info_max);
222     setsize(self.tur_head, '0 0 0', '0 0 0');
223     setorigin(self.tur_head, gettaginfo(self, gettagindex(self, "tag_head")));
224
225     self.tur_head.classname     = "turret_head";
226     self.tur_head.owner         = self;
227     self.tur_head.move_movetype = MOVETYPE_NOCLIP;
228     self.move_movetype          = MOVETYPE_NOCLIP;
229     self.tur_head.angles        = self.angles;
230     self.health                 = 255;
231     self.solid                  = SOLID_BBOX;
232     self.tur_head.solid         = SOLID_NOT;
233     self.movetype               = MOVETYPE_NOCLIP;
234     self.tur_head.movetype      = MOVETYPE_NOCLIP;    
235     self.draw                   = turret_draw;
236     self.entremove              = turret_remove;
237     self.drawmask = MASK_NORMAL;
238     self.tur_head.drawmask = MASK_NORMAL;
239
240     if(self.turret_type == TID_EWHEEL || self.turret_type == TID_WALKER)
241     {
242         self.gravity            = 1;
243         self.movetype           = MOVETYPE_BOUNCE;
244         self.move_movetype      = MOVETYPE_BOUNCE;
245         self.move_origin        = self.origin;                
246         self.move_time          = time;
247         switch(self.turret_type)
248         {
249             case TID_EWHEEL:
250                 self.draw               = turret_ewheel_draw;
251                 break;
252             case TID_WALKER:
253                 self.draw               = turret_walker_draw;
254         }
255         
256     }
257 }
258
259 entity turret_gibtoss(string _model, vector _from, vector _to, vector _cmod, float _explode);
260 void turret_gibboom();
261 void turret_gib_draw()
262 {
263     Movetype_Physics_MatchTicrate(autocvar_cl_gibs_ticrate, autocvar_cl_gibs_sloppy);
264     
265     self.drawmask = MASK_NORMAL;
266         
267         if(self.cnt)
268         {
269             if(time >= self.nextthink)
270             {
271             turret_gibboom();
272             remove(self);
273             }
274         }
275         else
276         {
277         self.alpha = bound(0, self.nextthink - time, 1);
278         if(self.alpha < ALPHA_MIN_VISIBLE)
279             remove(self);           
280         }
281 }
282
283 void turret_gibboom()
284 {
285     float i;
286     
287     sound (self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
288     pointparticles(particleeffectnum("rocket_explode"), self.origin, '0 0 0', 1);
289
290     for (i = 1; i < 5; i = i + 1)
291         turret_gibtoss(strcat("models/turrets/head-gib", ftos(i), ".md3"), self.origin, self.velocity + randomvec() * 700, '0 0 0', FALSE);
292 }
293
294 entity turret_gibtoss(string _model, vector _from, vector _to, vector _cmod, float _explode)
295 {
296     entity gib;
297
298     gib = spawn();
299     setorigin(gib, _from);
300     setmodel(gib, _model);
301     gib.colormod    = _cmod;
302         gib.solid       = SOLID_CORPSE;
303     gib.draw        = turret_gib_draw;    
304     gib.cnt         = _explode;
305     
306     if(_explode)
307     {
308         gib.nextthink = time + 0.2 * (autocvar_cl_gibs_lifetime * (1 + prandom() * 0.15));
309         gib.effects = EF_FLAME;
310     }        
311     else
312         gib.nextthink = time + autocvar_cl_gibs_lifetime * (1 + prandom() * 0.15);
313     
314     gib.gravity         = 1;
315         gib.move_movetype   = MOVETYPE_BOUNCE;
316         gib.move_origin     = gib.origin = _from;
317         gib.move_velocity   = _to;      
318         gib.move_avelocity  = prandomvec() * 32;
319         gib.move_time       = time;
320         gib.damageforcescale = 1;
321         
322         return gib;
323 }
324
325 void turret_die()
326 {    
327     entity headgib;
328     
329     setmodel(self, "");
330     setmodel(self.tur_head, "");
331     sound (self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
332     pointparticles(particleeffectnum("rocket_explode"), self.origin, '0 0 0', 1);
333     turret_tid2info(self.turret_type);
334     dprint("Turret ", tid2info_name, " dies.\n");
335     
336     // Base
337     if(self.turret_type == TID_EWHEEL)
338         turret_gibtoss(tid2info_base, self.origin, self.velocity, '-1 -1 -1', FALSE);
339     else if (self.turret_type == TID_WALKER)
340         turret_gibtoss(tid2info_base, self.origin, self.velocity, '-1 -1 -1', FALSE);
341     else if (self.turret_type == TID_TESLA)
342         turret_gibtoss(tid2info_base, self.origin, self.velocity, '-1 -1 -1', FALSE);
343     else
344     {        
345         if (random() > 0.5)
346         {
347             turret_gibtoss("models/turrets/base-gib2.md3", self.origin + '0 0 2', '0 0 50' + randomvec() * 150, '0 0 0', FALSE);
348             turret_gibtoss("models/turrets/base-gib3.md3", self.origin + '0 0 2', '0 0 50' + randomvec() * 150, '0 0 0', FALSE);
349             turret_gibtoss("models/turrets/base-gib4.md3", self.origin + '0 0 2', '0 0 50' + randomvec() * 150, '0 0 0', FALSE);
350         }
351         else
352             turret_gibtoss("models/turrets/base-gib1.md3", self.origin + '0 0 4', '0 0 0', '0 0 0', TRUE);
353     }
354     
355     headgib = turret_gibtoss(tid2info_head, self.origin + '0 0 32', '0 0 200' + randomvec() * 200, '-1 -1 -1', TRUE);
356     headgib.angles = headgib.move_angles = self.tur_head.angles;
357     headgib.avelocity = headgib.move_avelocity = self.tur_head.move_avelocity + randomvec() * 45;
358     headgib.avelocity_y = headgib.move_avelocity_y = headgib.move_avelocity_y * 5;
359     headgib.gravity = 0.5;
360 }
361
362 void ent_turret()
363 {
364     float sf;
365     sf = ReadByte();
366
367         if(sf & TNSF_SETUP)
368         {           
369             self.turret_type = ReadByte();
370                     
371             self.origin_x = ReadCoord();
372             self.origin_y = ReadCoord();
373             self.origin_z = ReadCoord();
374             
375             self.angles_x = ReadAngle();
376             self.angles_y = ReadAngle();
377             
378             turret_construct();
379     }
380     
381     if(sf & TNSF_ANG)
382     {
383         self.tur_head.move_angles_x = ReadShort();
384         self.tur_head.move_angles_y = ReadShort();
385         self.tur_head.angles = self.angles + self.tur_head.move_angles;
386     }
387     
388     if(sf & TNSF_AVEL)
389     {
390         self.tur_head.move_avelocity_x = ReadShort();
391         self.tur_head.move_avelocity_y = ReadShort();            
392     }
393     
394     if(sf & TNSF_MOVE)
395     {
396         self.origin_x = ReadShort();
397         self.origin_y = ReadShort();
398         self.origin_z = ReadShort();
399         setorigin(self, self.origin);
400         
401         self.velocity_x = ReadShort();
402         self.velocity_y = ReadShort();
403         self.velocity_z = ReadShort();
404         
405         self.move_angles_y = ReadShort();
406             
407         self.move_time     = time;
408         self.move_velocity = self.velocity;
409         self.move_origin   = self.origin;
410     }
411         
412     if(sf & TNSF_ANIM)
413     {
414         self.frame1time = ReadCoord();
415         self.frame      = ReadByte();
416     }
417
418     if(sf & TNSF_STATUS)
419     {
420         float _team;
421         _team = ReadByte();
422         _team -= 1; // /&)=(%&#)&%)/#&)=½!!!½!!". thanks.
423         self.health = ReadByte();
424         if(_team != self.team)
425         {
426             self.team = _team;
427             turret_changeteam();        
428         }
429     } 
430     
431     if(self.health == 0)
432         turret_die();
433 }