]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/client/vehicles/all.qc
Integrate the vehicle HUD images into the existing HUD themes.
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / vehicles / all.qc
1 #include "all.qh"
2 #include "../_all.qh"
3
4 #include "../movetypes.qh"
5 #include "../movetypes.qh"
6 #include "../prandom.qh"
7 #include "../scoreboard.qh"
8 #include "../t_items.qh"
9
10 #include "../../common/buffs.qh"
11 #include "../../common/constants.qh"
12 #include "../../common/stats.qh"
13 #include "../../common/util.qh"
14
15 #include "../../csqcmodellib/cl_model.qh"
16
17 .float cnt;
18
19 const string vCROSS_AIM  = "gfx/vehicles/crosshair_aim.tga";
20 const string vCROSS_DROP = "gfx/vehicles/crosshair_drop.tga";
21 const string vCROSS_HEAL = "gfx/vehicles/crosshair_heal.tga";
22 const string vCROSS_HINT = "gfx/vehicles/crosshair_hint.tga";
23 const string vCROSS_LOCK = "gfx/vehicles/crosshair_lock.tga";
24 const string vCROSS_TAG  = "gfx/vehicles/crosshair_tag.tga";
25
26 const int SBRM_FIRST     = 1;
27 const int SBRM_VOLLY     = 1;
28 const int SBRM_GUIDE     = 2;
29 const int SBRM_ARTILLERY = 3;
30 const int SBRM_LAST      = 3;
31
32 const int RSM_FIRST = 1;
33 const int RSM_BOMB  = 1;
34 const int RSM_FLARE = 2;
35 const int RSM_LAST  = 2;
36
37 const int MAX_AXH = 4;
38 entity AuxiliaryXhairs[MAX_AXH];
39 entityclass(AuxiliaryXhair);
40 class(AuxiliaryXhair) .string axh_image;
41 class(AuxiliaryXhair) .float  axh_fadetime;
42 class(AuxiliaryXhair) .float  axh_drawflag;
43
44 entity dropmark;
45
46 float alarm1time;
47 float alarm2time;
48 int weapon2mode;
49
50
51 void AuxiliaryXhair_Draw2D()
52 {
53         if (scoreboard_showscores)
54                 return;
55
56         vector size = draw_getimagesize(self.axh_image) * autocvar_cl_vehicles_crosshair_size;
57         vector pos = project_3d_to_2d(self.move_origin) - 0.5 * size;
58
59         if (!(pos.z < 0 || pos.x < 0 || pos.y < 0 || pos.x > vid_conwidth || pos.y > vid_conheight))
60         {
61                 pos.z = 0;
62                 size.z = 0;
63                 drawpic(pos, self.axh_image, size, self.colormod, autocvar_crosshair_alpha * self.alpha, self.axh_drawflag);
64         }
65
66         if(time - self.cnt > self.axh_fadetime)
67                 self.draw2d = func_null;
68 }
69
70 void Net_AuXair2(bool bIsNew)
71 {
72         int axh_id = bound(0, ReadByte(), MAX_AXH);
73         entity axh = AuxiliaryXhairs[axh_id];
74
75         if(axh == world || wasfreed(axh))  // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?)
76         {
77                 axh              = spawn();
78                 axh.draw2d       = func_null;
79                 axh.drawmask     = MASK_NORMAL;
80                 axh.axh_drawflag = DRAWFLAG_ADDITIVE;
81                 axh.axh_fadetime = 0.1;
82                 axh.axh_image    = vCROSS_HINT;
83                 axh.alpha        = 1;
84
85                 AuxiliaryXhairs[axh_id] = axh;
86         }
87
88         axh.move_origin_x = ReadCoord();
89         axh.move_origin_y = ReadCoord();
90         axh.move_origin_z = ReadCoord();
91         axh.colormod_x = ReadByte() / 255;
92         axh.colormod_y = ReadByte() / 255;
93         axh.colormod_z = ReadByte() / 255;
94         axh.cnt    = time;
95         axh.draw2d = AuxiliaryXhair_Draw2D;
96 }
97
98 void Net_VehicleSetup()
99 {
100         int hud_id = ReadByte();
101
102         // Weapon update?
103         if(hud_id > HUD_VEHICLE_LAST)
104         {
105                 weapon2mode = hud_id - HUD_VEHICLE_LAST;
106                 return;
107         }
108
109         // hud_id == 0 means we exited a vehicle, so stop alarm sound/s
110         if(hud_id == 0)
111         {
112                 sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
113                 sound(self, CH_PAIN_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
114                 return;
115         }
116
117         hud_id  = bound(HUD_VEHICLE_FIRST, hud_id, HUD_VEHICLE_LAST);
118
119         // Init auxiliary crosshairs
120         int i;
121         for(i = 0; i < MAX_AXH; ++i)
122         {
123                 entity axh = AuxiliaryXhairs[i];
124
125                 if(axh != world && !wasfreed(axh))  // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?)
126                         remove(axh);
127
128                 axh              = spawn();
129                 axh.draw2d       = func_null;
130                 axh.drawmask     = MASK_NORMAL;
131                 axh.axh_drawflag = DRAWFLAG_NORMAL;
132                 axh.axh_fadetime = 0.1;
133                 axh.axh_image    = vCROSS_HINT;
134                 axh.alpha        = 1;
135                 AuxiliaryXhairs[i] = axh;
136         }
137
138         switch(hud_id)
139         {
140                 case HUD_SPIDERBOT:
141                         AuxiliaryXhairs[0].axh_image = vCROSS_HINT; // Minigun1
142                         AuxiliaryXhairs[1].axh_image = vCROSS_HINT; // Minigun2
143                         break;
144
145                 case HUD_WAKIZASHI:
146                         AuxiliaryXhairs[0].axh_image = vCROSS_LOCK; // Rocket
147                         break;
148
149                 case HUD_RAPTOR:
150                         AuxiliaryXhairs[1].axh_image = vCROSS_LOCK;
151                         break;
152
153                 case HUD_BUMBLEBEE:
154                         AuxiliaryXhairs[0].axh_image = vCROSS_LOCK; // Raygun-locked
155                         AuxiliaryXhairs[1].axh_image = vCROSS_TAG; // Gunner1
156                         AuxiliaryXhairs[2].axh_image = vCROSS_TAG; // Gunner2
157                         break;
158
159                 case HUD_BUMBLEBEE_GUN:
160                         AuxiliaryXhairs[0].axh_image = vCROSS_TAG; // Plasma cannons
161                         AuxiliaryXhairs[1].axh_image = vCROSS_TAG; // Raygun
162                         break;
163         }
164 }
165
166 void Vehicles_drawHUD(
167         string vehicle,
168         string vehicleWeapon1,
169         string vehicleWeapon2,
170         string iconAmmo1,
171         vector colorAmmo1,
172         string iconAmmo2,
173         vector colorAmmo2,
174         string crosshair)
175 {
176         if(autocvar_r_letterbox)
177                 return;
178
179         if(scoreboard_showscores)
180                 return;
181
182         // Initialize
183         vector hudSize = '0 0 0';
184         vector hudPos  = '0 0 0';
185         vector tmpSize = '0 0 0';
186         vector tmpPos  = '0 0 0';
187
188         float hudAlpha = autocvar_hud_panel_fg_alpha;
189         float barAlpha = autocvar_hud_progressbar_alpha * hudAlpha;
190         float blinkValue = 0.55 + sin(time * 7) * 0.45;
191
192         float health  = getstati(STAT_VEHICLESTAT_HEALTH)  * 0.01;
193         float shield  = getstati(STAT_VEHICLESTAT_SHIELD)  * 0.01;
194         float energy  = getstati(STAT_VEHICLESTAT_ENERGY)  * 0.01;
195         float ammo1   = getstati(STAT_VEHICLESTAT_AMMO1)   * 0.01;
196         float reload1 = getstati(STAT_VEHICLESTAT_RELOAD1) * 0.01;
197         float ammo2   = getstati(STAT_VEHICLESTAT_AMMO2)   * 0.01;
198         float reload2 = getstati(STAT_VEHICLESTAT_RELOAD2) * 0.01;
199
200         // HACK to deal with the inconcistent use of the vehicle stats
201         ammo1 = (ammo1) ? ammo1 : energy;
202
203         // Frame
204         string frame = strcat(hud_skin_path, "/vehicle_frame");
205         if (precache_pic(frame) == "")
206                 frame = "gfx/hud/default/vehicle_frame";
207
208         hudSize  = draw_getimagesize(frame) * autocvar_cl_vehicles_hudscale;
209         hudPos.x = (vid_conwidth - hudSize.x) / 2;
210         hudPos.y = vid_conheight - hudSize.y;
211
212         if(teamplay && autocvar_hud_panel_bg_color_team)
213                 drawpic(hudPos, frame, hudSize, myteamcolors * autocvar_hud_panel_bg_color_team, autocvar_hud_panel_bg_alpha, DRAWFLAG_NORMAL);
214         else
215                 drawpic(hudPos, frame, hudSize, autocvar_hud_panel_bg_color, autocvar_hud_panel_bg_alpha, DRAWFLAG_NORMAL);
216
217         // Model
218         tmpSize.x = hudSize.x / 3;
219         tmpSize.y = hudSize.y;
220         tmpPos.x  = hudPos.x + hudSize.x / 3;
221         tmpPos.y  = hudPos.y;
222
223         if(health < 0.25)
224                 drawpic_skin(tmpPos, vehicle, tmpSize, '1 0 0' + '0 1 1' * blinkValue, hudAlpha, DRAWFLAG_NORMAL);
225         else
226                 drawpic_skin(tmpPos, vehicle, tmpSize, '1 1 1' * health  + '1 0 0' * (1 - health), hudAlpha, DRAWFLAG_NORMAL);
227
228         drawpic_skin(tmpPos, vehicleWeapon1, tmpSize, '1 1 1' * ammo1 + '1 0 0' * (1 - ammo1), hudAlpha, DRAWFLAG_NORMAL);
229         drawpic_skin(tmpPos, vehicleWeapon2, tmpSize, '1 1 1' * ammo2 + '1 0 0' * (1 - ammo2), hudAlpha, DRAWFLAG_NORMAL);
230         drawpic_skin(tmpPos, "vehicle_shield", tmpSize, '1 1 1' * shield + '1 0 0' * (1 - shield), hudAlpha * shield, DRAWFLAG_NORMAL);
231
232         // Health bar
233         tmpSize.y = hudSize.y / 2;
234         tmpPos.x  = hudPos.x + hudSize.x * (32/768);
235         tmpPos.y  = hudPos.y;
236
237         drawsetcliparea(tmpPos.x + (tmpSize.x * (1 - health)), tmpPos.y, tmpSize.x, tmpSize.y);
238         drawpic_skin(tmpPos, "vehicle_bar_northwest", tmpSize, autocvar_hud_progressbar_health_color, barAlpha, DRAWFLAG_NORMAL);
239
240         // Shield bar
241         tmpPos.y = hudPos.y + hudSize.y / 2;
242
243         drawsetcliparea(tmpPos.x + (tmpSize.x * (1 - shield)), tmpPos.y, tmpSize.x, tmpSize.y);
244         drawpic_skin(tmpPos, "vehicle_bar_southwest", tmpSize, autocvar_hud_progressbar_armor_color, barAlpha, DRAWFLAG_NORMAL);
245
246         // Ammo1 bar
247         tmpPos.x = hudPos.x + hudSize.x * (480/768);
248         tmpPos.y = hudPos.y;
249
250         if(ammo1)
251                 drawsetcliparea(tmpPos.x, tmpPos.y, tmpSize.x * ammo1, tmpSize.y);
252         else
253                 drawsetcliparea(tmpPos.x, tmpPos.y, tmpSize.x * reload1, tmpSize.y);
254
255         drawpic_skin(tmpPos, "vehicle_bar_northeast", tmpSize, colorAmmo1, barAlpha, DRAWFLAG_NORMAL);
256
257         // Ammo2 bar
258         tmpPos.y = hudPos.y + hudSize.y / 2;
259
260         if(ammo2)
261                 drawsetcliparea(tmpPos.x, tmpPos.y, tmpSize.x * ammo2, tmpSize.y);
262         else
263                 drawsetcliparea(tmpPos.x, tmpPos.y, tmpSize.x * reload2, tmpSize.y);
264
265         drawpic_skin(tmpPos, "vehicle_bar_southeast", tmpSize, colorAmmo2, barAlpha, DRAWFLAG_NORMAL);
266         drawresetcliparea();
267
268         // Health icon
269         tmpSize.x = hudSize.x * (80/768);
270         tmpSize.y = hudSize.y * (80/256);
271         tmpPos.x  = hudPos.x + hudSize.x * (64/768);
272         tmpPos.y  = hudPos.y + hudSize.y * (48/256);
273
274         if(health < 0.25)
275         {
276                 if(alarm1time < time)
277                 {
278                         alarm1time = time + 2;
279                         sound(self, CH_PAIN_SINGLE, "vehicles/alarm.wav", VOL_BASEVOICE, ATTEN_NONE);
280                 }
281                 drawpic_skin(tmpPos, "vehicle_icon_health", tmpSize, '1 1 1', hudAlpha * blinkValue, DRAWFLAG_NORMAL);
282         }
283         else
284         {
285                 if(alarm1time)
286                 {
287                         sound(self, CH_PAIN_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
288                         alarm1time = 0;
289                 }
290                 drawpic_skin(tmpPos, "vehicle_icon_health", tmpSize, '1 1 1', hudAlpha, DRAWFLAG_NORMAL);
291         }
292
293         // Shield icon
294         tmpPos.y = hudPos.y + hudSize.y / 2;
295
296         if(shield < 0.25)
297         {
298                 if(alarm2time < time)
299                 {
300                         alarm2time = time + 1;
301                         sound(self, CH_TRIGGER_SINGLE, "vehicles/alarm_shield.wav", VOL_BASEVOICE, ATTEN_NONE);
302                 }
303                 drawpic_skin(tmpPos, "vehicle_icon_shield", tmpSize, '1 1 1', hudAlpha * blinkValue, DRAWFLAG_NORMAL);
304         }
305         else
306         {
307                 if(alarm2time)
308                 {
309                         sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
310                         alarm2time = 0;
311                 }
312                 drawpic_skin(tmpPos, "vehicle_icon_shield", tmpSize, '1 1 1', hudAlpha, DRAWFLAG_NORMAL);
313         }
314
315         // Ammo1 icon
316         tmpPos.x = hudPos.x + hudSize.x * (624/768);
317         tmpPos.y = hudPos.y + hudSize.y * (48/256);
318
319         if(ammo1)
320                 drawpic_skin(tmpPos, iconAmmo1, tmpSize, '1 1 1', hudAlpha, DRAWFLAG_NORMAL);
321         else
322                 drawpic_skin(tmpPos, iconAmmo1, tmpSize, '1 1 1', hudAlpha * 0.2, DRAWFLAG_NORMAL);
323
324         // Ammo2 icon
325         tmpPos.y = hudPos.y + hudSize.y / 2;
326
327         if(ammo2)
328                 drawpic_skin(tmpPos, iconAmmo2, tmpSize, '1 1 1', hudAlpha, DRAWFLAG_NORMAL);
329         else
330                 drawpic_skin(tmpPos, iconAmmo2, tmpSize, '1 1 1', hudAlpha * 0.2, DRAWFLAG_NORMAL);
331
332         // Bumblebee gunner crosshairs
333         if(hud == HUD_BUMBLEBEE)
334         {
335                 tmpSize = '1 1 1' * hud_fontsize;
336                 tmpPos.x = hudPos.x + hudSize.x * (520/768);
337
338                 if(!AuxiliaryXhairs[1].draw2d)
339                 {
340                         tmpPos.y = hudPos.y + hudSize.y * (96/256) - tmpSize.y;
341                         drawstring(tmpPos, _("No right gunner!"), tmpSize, '1 1 1', hudAlpha * blinkValue, DRAWFLAG_NORMAL);
342                 }
343
344                 if(!AuxiliaryXhairs[2].draw2d)
345                 {
346                         tmpPos.y = hudPos.y + hudSize.y * (160/256);
347                         drawstring(tmpPos, _("No left gunner!"), tmpSize, '1 1 1', hudAlpha * blinkValue, DRAWFLAG_NORMAL);
348                 }
349         }
350
351         // Raptor bomb crosshair
352         if(hud == HUD_RAPTOR && weapon2mode != RSM_FLARE)
353         {
354                 vector where;
355
356                 if(!dropmark)
357                 {
358                         dropmark = spawn();
359                         dropmark.owner = self;
360                         dropmark.gravity = 1;
361                 }
362
363                 if(reload2 == 1)
364                 {
365                         setorigin(dropmark, pmove_org);
366                         dropmark.velocity = pmove_vel;
367                         tracetoss(dropmark, self);
368
369                         where = project_3d_to_2d(trace_endpos);
370
371                         setorigin(dropmark, trace_endpos);
372                         tmpSize = draw_getimagesize(vCROSS_DROP) * autocvar_cl_vehicles_crosshair_size;
373
374                         if (!(where.z < 0 || where.x < 0 || where.y < 0 || where.x > vid_conwidth || where.y > vid_conheight))
375                         {
376                                 where.x -= tmpSize.x * 0.5;
377                                 where.y -= tmpSize.y * 0.5;
378                                 where.z = 0;
379                                 drawpic(where, vCROSS_DROP, tmpSize, '0 1 0', autocvar_crosshair_alpha * 0.9, DRAWFLAG_ADDITIVE);
380                                 drawpic(where, vCROSS_DROP, tmpSize, '0 1 0', autocvar_crosshair_alpha * 0.6, DRAWFLAG_NORMAL); // Ensure visibility against bright bg
381                         }
382                         dropmark.cnt = time + 5;
383                 }
384                 else
385                 {
386                         if(dropmark.cnt > time)
387                         {
388                                 where = project_3d_to_2d(dropmark.origin);
389                                 tmpSize = draw_getimagesize(vCROSS_DROP) * autocvar_cl_vehicles_crosshair_size * 1.25;
390
391                                 if (!(where.z < 0 || where.x < 0 || where.y < 0 || where.x > vid_conwidth || where.y > vid_conheight))
392                                 {
393                                         where.x -= tmpSize.x * 0.5;
394                                         where.y -= tmpSize.y * 0.5;
395                                         where.z = 0;
396                                         drawpic(where, vCROSS_DROP, tmpSize, '1 0 0', autocvar_crosshair_alpha * 0.9, DRAWFLAG_ADDITIVE);
397                                         drawpic(where, vCROSS_DROP, tmpSize, '1 0 0', autocvar_crosshair_alpha * 0.6, DRAWFLAG_NORMAL); // Ensure visibility against bright bg
398                                 }
399                         }
400                 }
401         }
402
403         // Crosshair
404         tmpSize  = draw_getimagesize(crosshair) * autocvar_cl_vehicles_crosshair_size;
405         tmpPos.x = (vid_conwidth - tmpSize.x) / 2;
406         tmpPos.y = (vid_conheight - tmpSize.y) / 2;
407
408         drawpic(tmpPos, crosshair, tmpSize, '1 1 1', autocvar_crosshair_alpha, DRAWFLAG_NORMAL);
409 }
410
411 void CSQC_BUMBLE_HUD()
412 {
413         Vehicles_drawHUD("vehicle_bumble", "vehicle_bumble_weapon1", "vehicle_bumble_weapon2",
414                 "vehicle_icon_ammo1", autocvar_hud_progressbar_vehicles_ammo1_color,
415                 "vehicle_icon_ammo1", autocvar_hud_progressbar_vehicles_ammo1_color,
416                 vCROSS_HEAL);
417 }
418
419 void CSQC_BUMBLE_GUN_HUD()
420 {
421         Vehicles_drawHUD("vehicle_gunner", "vehicle_gunner_weapon1", "null",
422                 "vehicle_icon_ammo1", autocvar_hud_progressbar_vehicles_ammo1_color,
423                 "null", '0 0 0',
424                 "null");
425 }
426
427 void CSQC_SPIDER_HUD()
428 {
429         string crosshair;
430
431         switch(weapon2mode)
432         {
433                 case SBRM_VOLLY: crosshair = vCROSS_LOCK; break;
434                 case SBRM_GUIDE: crosshair = vCROSS_AIM;  break;
435                 default:         crosshair = vCROSS_TAG;
436         }
437
438         Vehicles_drawHUD("vehicle_spider", "vehicle_spider_weapon1", "vehicle_spider_weapon2",
439                 "vehicle_icon_ammo1", autocvar_hud_progressbar_vehicles_ammo1_color,
440                 "vehicle_icon_ammo2", autocvar_hud_progressbar_vehicles_ammo2_color,
441                 crosshair);
442 }
443
444 void CSQC_RAPTOR_HUD()
445 {
446         string crosshair;
447
448         switch(weapon2mode)
449         {
450                 case RSM_FLARE: crosshair = vCROSS_LOCK; break;
451                 default:        crosshair = vCROSS_AIM;
452         }
453
454         Vehicles_drawHUD("vehicle_raptor", "vehicle_raptor_weapon1", "vehicle_raptor_weapon2",
455                 "vehicle_icon_ammo1", autocvar_hud_progressbar_vehicles_ammo1_color,
456                 "vehicle_icon_ammo2", autocvar_hud_progressbar_vehicles_ammo2_color,
457                 crosshair);
458 }
459
460 void CSQC_WAKIZASHI_HUD()
461 {
462         Vehicles_drawHUD("vehicle_racer", "vehicle_racer_weapon1", "vehicle_racer_weapon2",
463                 "vehicle_icon_ammo1", autocvar_hud_progressbar_vehicles_ammo1_color,
464                 "vehicle_icon_ammo2", autocvar_hud_progressbar_vehicles_ammo2_color,
465                 vCROSS_AIM);
466 }
467
468 void Vehicles_Precache()
469 {
470         precache_model("models/vehicles/bomblet.md3");
471         precache_model("models/vehicles/clusterbomb.md3");
472         precache_model("models/vehicles/clusterbomb_fragment.md3");
473         precache_model("models/vehicles/rocket01.md3");
474         precache_model("models/vehicles/rocket02.md3");
475
476         precache_sound("vehicles/alarm.wav");
477         precache_sound("vehicles/alarm_shield.wav");
478 }
479
480 void RaptorCBShellfragDraw()
481 {
482         if(wasfreed(self))
483                 return;
484
485         Movetype_Physics_MatchTicrate(autocvar_cl_gibs_ticrate, autocvar_cl_gibs_sloppy);
486         self.move_avelocity += randomvec() * 15;
487         self.renderflags = 0;
488
489         if(self.cnt < time)
490                 self.alpha = bound(0, self.nextthink - time, 1);
491
492         if(self.alpha < ALPHA_MIN_VISIBLE)
493                 remove(self);
494 }
495
496 void RaptorCBShellfragToss(vector _org, vector _vel, vector _ang)
497 {
498         entity sfrag;
499
500         sfrag = spawn();
501         setmodel(sfrag, "models/vehicles/clusterbomb_fragment.md3");
502         setorigin(sfrag, _org);
503
504         sfrag.move_movetype = MOVETYPE_BOUNCE;
505         sfrag.gravity = 0.15;
506         sfrag.solid = SOLID_CORPSE;
507
508         sfrag.draw = RaptorCBShellfragDraw;
509
510         sfrag.move_origin = sfrag.origin = _org;
511         sfrag.move_velocity = _vel;
512         sfrag.move_avelocity = prandomvec() * vlen(sfrag.move_velocity);
513         sfrag.angles = self.move_angles = _ang;
514
515         sfrag.move_time = time;
516         sfrag.damageforcescale = 4;
517
518         sfrag.nextthink = time + 3;
519         sfrag.cnt = time + 2;
520         sfrag.alpha = 1;
521         sfrag.drawmask = MASK_NORMAL;
522 }