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