]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/turrets/cl_turrets.qc
Clean up turrets system a bit
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / turrets / cl_turrets.qc
1 void turret_remove()
2 {
3         remove(self.tur_head);
4         //remove(self.enemy);
5         self.tur_head = world;
6 }
7
8 .vector glowmod;
9 void turret_changeteam()
10 {
11         switch(self.team - 1)
12         {
13                 case NUM_TEAM_1: // Red
14                         self.glowmod = '2 0 0';
15                         self.teamradar_color = '1 0 0';
16                         break;
17
18                 case NUM_TEAM_2: // Blue
19                         self.glowmod = '0 0 2';
20                         self.teamradar_color = '0 0 1';
21                         break;
22
23                 case NUM_TEAM_3: // Yellow
24                         self.glowmod = '1 1 0';
25                         self.teamradar_color = '1 1 0';
26                         break;
27
28                 case NUM_TEAM_4: // Pink
29                         self.glowmod = '1 0 1';
30                         self.teamradar_color = '1 0 1';
31                         break;
32         }
33
34         if(self.team)
35                 self.colormap = 1024 + (self.team - 1) * 17;
36
37         self.tur_head.colormap = self.colormap;
38         self.tur_head.glowmod = self.glowmod;
39
40 }
41
42 void turret_head_draw()
43 {
44         self.drawmask = MASK_NORMAL;
45 }
46
47 void turret_draw()
48 {
49         float dt;
50
51         dt = time - self.move_time;
52         self.move_time = time;
53         if(dt <= 0)
54                 return;
55
56         self.tur_head.angles += dt * self.tur_head.move_avelocity;
57
58         if (self.health < 127)
59         {
60                 dt = random();
61
62                 if(dt < 0.03)
63                         te_spark(self.origin + '0 0 40', randomvec() * 256 + '0 0 256', 16);
64         }
65
66         if(self.health < 85)
67         if(dt < 0.01)
68                 pointparticles(particleeffectnum("smoke_large"), (self.origin + (randomvec() * 80)), '0 0 0', 1);
69
70         if(self.health < 32)
71         if(dt < 0.015)
72                 pointparticles(particleeffectnum("smoke_small"), (self.origin + (randomvec() * 80)), '0 0 0', 1);
73
74 }
75
76 void turret_draw2d()
77 {
78         if(self.netname == "")
79                 return;
80
81         if(!autocvar_g_waypointsprite_turrets)
82                 return;
83
84         if(autocvar_cl_hidewaypoints)
85                 return;
86
87         float dist = vlen(self.origin - view_origin);
88         float t = (GetPlayerColor(player_localnum) + 1);
89
90         vector o;
91         string txt;
92
93         if(autocvar_cl_vehicles_hud_tactical)
94         if(dist < 10240 && t != self.team)
95         {
96                 // TODO: Vehicle tactical hud
97                 o = project_3d_to_2d(self.origin + '0 0 32');
98                 if(o_z < 0
99                 || o_x < (vid_conwidth * waypointsprite_edgeoffset_left)
100                 || o_y < (vid_conheight * waypointsprite_edgeoffset_top)
101                 || o_x > (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right))
102                 || o_y > (vid_conheight - (vid_conheight * waypointsprite_edgeoffset_bottom)))
103                         return; // Dont draw wp's for turrets out of view
104                 o_z = 0;
105                 if(hud != HUD_NORMAL)
106                 {
107                         switch(hud)
108                         {
109                                 case HUD_SPIDERBOT:
110                                 case HUD_WAKIZASHI:
111                                 case HUD_RAPTOR:
112                                 case HUD_BUMBLEBEE:
113                                         if((get_turretinfo(self.turretid)).spawnflags & TUR_FLAG_MOVE)
114                                                 txt = "gfx/vehicles/vth-mover.tga";
115                                         else
116                                                 txt = "gfx/vehicles/vth-stationary.tga";
117
118                                         vector pz = drawgetimagesize(txt) * 0.25;
119                                         drawpic(o - pz * 0.5, txt, pz , '1 1 1', 0.75, DRAWFLAG_NORMAL);
120                                         break;
121                         }
122                 }
123         }
124
125         if(dist > self.maxdistance)
126                 return;
127
128         string spriteimage = self.netname;
129         float a = self.alpha * autocvar_hud_panel_fg_alpha;
130         vector rgb = spritelookupcolor(spriteimage, self.teamradar_color);
131
132
133         if(self.maxdistance > waypointsprite_normdistance)
134                 a *= pow(bound(0, (self.maxdistance - dist) / (self.maxdistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent);
135         else if(self.maxdistance > 0)
136                 a *= pow(bound(0, (waypointsprite_fadedistance - dist) / (waypointsprite_fadedistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent) * (1 - waypointsprite_minalpha) + waypointsprite_minalpha;
137
138         if(rgb == '0 0 0')
139         {
140                 self.teamradar_color = '1 0 1';
141                 print(sprintf("WARNING: sprite of name %s has no color, using pink so you notice it\n", spriteimage));
142         }
143
144         txt = self.netname;
145         if(autocvar_g_waypointsprite_spam && waypointsprite_count >= autocvar_g_waypointsprite_spam)
146                 txt = _("Spam");
147         else
148                 txt = spritelookuptext(spriteimage);
149
150         if(time - floor(time) > 0.5 && t == self.team)
151         {
152                 if(self.helpme && time < self.helpme)
153                 {
154                         a *= SPRITE_HELPME_BLINK;
155                         txt = sprintf(_("%s under attack!"), txt);
156                 }
157                 else
158                         a *= spritelookupblinkvalue(spriteimage);
159         }
160
161         if(autocvar_g_waypointsprite_uppercase)
162                 txt = strtoupper(txt);
163
164         if(a > 1)
165         {
166                 rgb *= a;
167                 a = 1;
168         }
169
170         if(a <= 0)
171                 return;
172
173         rgb = fixrgbexcess(rgb);
174
175         o = project_3d_to_2d(self.origin + '0 0 64');
176         if(o_z < 0
177         || o_x < (vid_conwidth * waypointsprite_edgeoffset_left)
178         || o_y < (vid_conheight * waypointsprite_edgeoffset_top)
179         || o_x > (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right))
180         || o_y > (vid_conheight - (vid_conheight * waypointsprite_edgeoffset_bottom)))
181                 return; // Dont draw wp's for turrets out of view
182
183         o_z = 0;
184
185         float edgedistance_min, crosshairdistance;
186                 edgedistance_min = min((o_y - (vid_conheight * waypointsprite_edgeoffset_top)),
187         (o_x - (vid_conwidth * waypointsprite_edgeoffset_left)),
188         (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right)) - o_x,
189         (vid_conheight - (vid_conheight * waypointsprite_edgeoffset_bottom)) - o_y);
190
191         float vidscale = max(vid_conwidth / vid_width, vid_conheight / vid_height);
192
193         crosshairdistance = sqrt( pow(o_x - vid_conwidth/2, 2) + pow(o_y - vid_conheight/2, 2) );
194
195         t = waypointsprite_scale * vidscale;
196         a *= waypointsprite_alpha;
197
198         {
199                 a = a * (1 - (1 - waypointsprite_distancefadealpha) * (bound(0, dist/waypointsprite_distancefadedistance, 1)));
200                 t = t * (1 - (1 - waypointsprite_distancefadescale) * (bound(0, dist/waypointsprite_distancefadedistance, 1)));
201         }
202         if (edgedistance_min < waypointsprite_edgefadedistance) {
203                 a = a * (1 - (1 - waypointsprite_edgefadealpha) * (1 - bound(0, edgedistance_min/waypointsprite_edgefadedistance, 1)));
204                 t = t * (1 - (1 - waypointsprite_edgefadescale) * (1 - bound(0, edgedistance_min/waypointsprite_edgefadedistance, 1)));
205         }
206         if(crosshairdistance < waypointsprite_crosshairfadedistance) {
207                 a = a * (1 - (1 - waypointsprite_crosshairfadealpha) * (1 - bound(0, crosshairdistance/waypointsprite_crosshairfadedistance, 1)));
208                 t = t * (1 - (1 - waypointsprite_crosshairfadescale) * (1 - bound(0, crosshairdistance/waypointsprite_crosshairfadedistance, 1)));
209         }
210
211         o = drawspritearrow(o, M_PI, rgb, a, SPRITE_ARROW_SCALE * t);
212         o = drawspritetext(o, M_PI, (SPRITE_HEALTHBAR_WIDTH + 2 * SPRITE_HEALTHBAR_BORDER) * t, rgb, a, waypointsprite_fontsize * '1 1 0', txt);
213         drawhealthbar(
214                         o,
215                         0,
216                         self.health / 255,
217                         '0 0 0',
218                         '0 0 0',
219                         0.5 * SPRITE_HEALTHBAR_WIDTH * t,
220                         0.5 * SPRITE_HEALTHBAR_HEIGHT * t,
221                         SPRITE_HEALTHBAR_MARGIN * t + 0.5 * waypointsprite_fontsize,
222                         SPRITE_HEALTHBAR_BORDER * t,
223                         0,
224                         rgb,
225                         a * SPRITE_HEALTHBAR_BORDERALPHA,
226                         rgb,
227                         a * SPRITE_HEALTHBAR_HEALTHALPHA,
228                         DRAWFLAG_NORMAL
229                         );
230 }
231
232 void(entity e, entity tagentity, string tagname) setattachment = #443;
233 void turret_construct()
234 {
235         entity tur = get_turretinfo(self.turretid);
236
237         if(self.tur_head == world)
238                 self.tur_head = spawn();
239
240         self.netname = TUR_NAME(self.turretid);
241
242         setorigin(self, self.origin);
243         setmodel(self, tur.model);
244         setmodel(self.tur_head, tur.head_model);
245         setsize(self, tur.mins, tur.maxs);
246         setsize(self.tur_head, '0 0 0', '0 0 0');
247
248         if(self.turretid == TUR_EWHEEL)
249                 setattachment(self.tur_head, self, "");
250         else
251                 setattachment(self.tur_head, self, "tag_head");
252
253         self.tur_head.classname                 = "turret_head";
254         self.tur_head.owner                             = self;
255         self.tur_head.move_movetype             = MOVETYPE_NOCLIP;
256         self.move_movetype                              = MOVETYPE_NOCLIP;
257         self.tur_head.angles                    = self.angles;
258         self.health                                             = 255;
259         self.solid                                              = SOLID_BBOX;
260         self.tur_head.solid                             = SOLID_NOT;
261         self.movetype                                   = MOVETYPE_NOCLIP;
262         self.tur_head.movetype                  = MOVETYPE_NOCLIP;
263         self.draw                                               = turret_draw;
264         self.entremove                                  = turret_remove;
265         self.drawmask                                   = MASK_NORMAL;
266         self.tur_head.drawmask                  = MASK_NORMAL;
267         self.anim_start_time                    = 0;
268         self.draw2d = turret_draw2d;
269         self.maxdistance = autocvar_g_waypointsprite_turrets_maxdist;
270         self.teamradar_color = '1 0 0';
271         self.alpha = 1;
272         
273         TUR_ACTION(self.turretid, TR_SETUP);
274 }
275
276 entity turret_gibtoss(string _model, vector _from, vector _to, vector _cmod, float _explode);
277 void turret_gibboom();
278 void turret_gib_draw()
279 {
280         Movetype_Physics_MatchTicrate(autocvar_cl_gibs_ticrate, autocvar_cl_gibs_sloppy);
281
282         self.drawmask = MASK_NORMAL;
283
284         if(self.cnt)
285         {
286                 if(time >= self.nextthink)
287                 {
288                         turret_gibboom();
289                         remove(self);
290                 }
291         }
292         else
293         {
294                 self.alpha = bound(0, self.nextthink - time, 1);
295                 if(self.alpha < ALPHA_MIN_VISIBLE)
296                         remove(self);
297         }
298 }
299
300 void turret_gibboom()
301 {
302         float i;
303
304         sound (self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM);
305         pointparticles(particleeffectnum("rocket_explode"), self.origin, '0 0 0', 1);
306
307         for (i = 1; i < 5; i = i + 1)
308                 turret_gibtoss(strcat("models/turrets/head-gib", ftos(i), ".md3"), self.origin + '0 0 2', self.velocity + randomvec() * 700, '0 0 0', FALSE);
309 }
310
311 entity turret_gibtoss(string _model, vector _from, vector _to, vector _cmod, float _explode)
312 {
313         entity gib;
314
315         traceline(_from, _to, MOVE_NOMONSTERS, world);
316         if(trace_startsolid)
317                 return world;
318
319         gib = spawn();
320         setorigin(gib, _from);
321         setmodel(gib, _model);
322         gib.colormod    = _cmod;
323         gib.solid          = SOLID_CORPSE;
324         gib.draw                = turret_gib_draw;
325         gib.cnt          = _explode;
326         setsize(gib, '-1 -1 -1', '1 1 1');
327         if(_explode)
328         {
329                 gib.nextthink = time + 0.2 * (autocvar_cl_gibs_lifetime * (1 + prandom() * 0.15));
330                 gib.effects = EF_FLAME;
331         }
332         else
333                 gib.nextthink = time + autocvar_cl_gibs_lifetime * (1 + prandom() * 0.15);
334
335         gib.gravity              = 1;
336         gib.move_movetype   = MOVETYPE_BOUNCE;
337         gib.move_origin  = _from;
338         setorigin(gib,          _from);
339         gib.move_velocity   = _to;
340         gib.move_avelocity  = prandomvec() * 32;
341         gib.move_time      = time;
342         gib.damageforcescale = 1;
343         gib.classname = "turret_gib";
344
345         return gib;
346 }
347
348 void turret_die()
349 {
350         sound (self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM);
351         pointparticles(particleeffectnum("rocket_explode"), self.origin, '0 0 0', 1);
352         if (!autocvar_cl_nogibs)
353         {
354                 // Base
355                 if(self.turretid == TUR_EWHEEL)
356                         turret_gibtoss((get_turretinfo(self.turretid)).model, self.origin + '0 0 18', self.velocity + '0 0 400' + '0.1 0.1 1' * (random() * 400), '-1 -1 -1', TRUE);
357                 else if (self.turretid == TUR_WALKER)
358                         turret_gibtoss((get_turretinfo(self.turretid)).model, self.origin + '0 0 18', self.velocity + '0 0 300' + '0.1 0.1 1' * (random() * 200), '-1 -1 -1', TRUE);
359                 else if (self.turretid == TUR_TESLA)
360                         turret_gibtoss((get_turretinfo(self.turretid)).model, self.origin + '0 0 18', '0 0 200', '-1 -1 -1', FALSE);
361                 else
362                 {
363                         if (random() > 0.5)
364                         {
365                                 turret_gibtoss("models/turrets/base-gib2.md3", self.origin + '0 0 8', '0 0 50' + randomvec() * 150, '0 0 0', FALSE);
366                                 turret_gibtoss("models/turrets/base-gib3.md3", self.origin + '0 0 8', '0 0 50' + randomvec() * 150, '0 0 0', FALSE);
367                                 turret_gibtoss("models/turrets/base-gib4.md3", self.origin + '0 0 8', '0 0 50' + randomvec() * 150, '0 0 0', FALSE);
368                         }
369                         else
370                                 turret_gibtoss("models/turrets/base-gib1.md3", self.origin + '0 0 8', '0 0 0', '0 0 0', TRUE);
371
372                         entity headgib = turret_gibtoss((get_turretinfo(self.turretid)).head_model, self.origin + '0 0 32', '0 0 200' + randomvec() * 200, '-1 -1 -1', TRUE);
373                         if(headgib)
374                         {
375                                 headgib.angles = headgib.move_angles = self.tur_head.angles;
376                                 headgib.avelocity = headgib.move_avelocity = self.tur_head.move_avelocity + randomvec() * 45;
377                                 headgib.avelocity_y = headgib.move_avelocity_y = headgib.move_avelocity_y * 5;
378                                 headgib.gravity = 0.5;
379                         }
380                 }
381         }
382
383         setmodel(self, "null");
384         setmodel(self.tur_head, "null");
385 }
386
387 void ent_turret()
388 {
389         float sf;
390         sf = ReadByte();
391
392         if(sf & TNSF_SETUP)
393         {
394                 self.turretid = ReadByte();
395
396                 self.origin_x = ReadCoord();
397                 self.origin_y = ReadCoord();
398                 self.origin_z = ReadCoord();
399                 setorigin(self, self.origin);
400
401                 self.angles_x = ReadAngle();
402                 self.angles_y = ReadAngle();
403                 
404                 turret_construct();
405                 self.colormap = 1024;
406                 self.glowmod = '0 1 1';
407                 self.tur_head.colormap = self.colormap;
408                 self.tur_head.glowmod = self.glowmod;
409         }
410
411         if(sf & TNSF_ANG)
412         {
413                 if(self.tur_head == world) // aparenly this can happpen before TNSF_SETUP. great.
414                         self.tur_head = spawn();
415
416                 self.tur_head.move_angles_x = ReadShort();
417                 self.tur_head.move_angles_y = ReadShort();
418                 //self.tur_head.angles = self.angles + self.tur_head.move_angles;
419                 self.tur_head.angles = self.tur_head.move_angles;
420         }
421
422         if(sf & TNSF_AVEL)
423         {
424                 if(self.tur_head == world) // aparenly this can happpen before TNSF_SETUP. great.
425                         self.tur_head = spawn();
426
427                 self.tur_head.move_avelocity_x = ReadShort();
428                 self.tur_head.move_avelocity_y = ReadShort();
429         }
430
431         if(sf & TNSF_MOVE)
432         {
433                 self.origin_x = ReadShort();
434                 self.origin_y = ReadShort();
435                 self.origin_z = ReadShort();
436                 setorigin(self, self.origin);
437
438                 self.velocity_x = ReadShort();
439                 self.velocity_y = ReadShort();
440                 self.velocity_z = ReadShort();
441
442                 self.move_angles_y = ReadShort();
443
444                 self.move_time   = time;
445                 self.move_velocity = self.velocity;
446                 self.move_origin   = self.origin;
447         }
448
449         if(sf & TNSF_ANIM)
450         {
451                 self.frame1time = ReadCoord();
452                 self.frame        = ReadByte();
453         }
454
455         if(sf & TNSF_STATUS)
456         {
457                 float _tmp;
458                 _tmp = ReadByte();
459                 if(_tmp != self.team)
460                 {
461                         self.team = _tmp;
462                         turret_changeteam();
463                 }
464
465                 _tmp = ReadByte();
466                 if(_tmp == 0 && self.health != 0)
467                         turret_die();
468                 else if(self.health && self.health != _tmp)
469                         self.helpme = servertime + 10;
470
471                 self.health = _tmp;
472         }
473         //self.enemy.health = self.health / 255;
474 }