]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/vehicles/unit/bumblebee.qc
Merge branch 'master' into Mario/vehicles
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / vehicles / unit / bumblebee.qc
1 #ifdef REGISTER_VEHICLE
2 REGISTER_VEHICLE(
3 /* VEH_##id   */ BUMBLEBEE,
4 /* function   */ v_bumblebee,
5 /* spawnflags */ VHF_DMGSHAKE,
6 /* mins,maxs  */ '-245 -130 -130', '230 130 130',
7 /* model          */ "models/vehicles/bumblebee_body.dpm",
8 /* head_model */ "",
9 /* hud_model  */ "models/vehicles/spiderbot_cockpit.dpm",
10 /* tags           */ "", "", "tag_viewport",
11 /* netname        */ "bumblebee",
12 /* fullname   */ _("Bumblebee")
13 );
14 #else
15
16 const float BRG_SETUP = 2;
17 const float BRG_START = 4;
18 const float BRG_END = 8;
19
20 #ifdef SVQC
21 float autocvar_g_vehicle_bumblebee_speed_forward;
22 float autocvar_g_vehicle_bumblebee_speed_strafe;
23 float autocvar_g_vehicle_bumblebee_speed_up;
24 float autocvar_g_vehicle_bumblebee_speed_down;
25 float autocvar_g_vehicle_bumblebee_turnspeed;
26 float autocvar_g_vehicle_bumblebee_pitchspeed;
27 float autocvar_g_vehicle_bumblebee_pitchlimit;
28 float autocvar_g_vehicle_bumblebee_friction;
29
30 float autocvar_g_vehicle_bumblebee_energy;
31 float autocvar_g_vehicle_bumblebee_energy_regen;
32 float autocvar_g_vehicle_bumblebee_energy_regen_pause;
33
34 float autocvar_g_vehicle_bumblebee_health;
35 float autocvar_g_vehicle_bumblebee_health_regen;
36 float autocvar_g_vehicle_bumblebee_health_regen_pause;
37
38 float autocvar_g_vehicle_bumblebee_shield;
39 float autocvar_g_vehicle_bumblebee_shield_regen;
40 float autocvar_g_vehicle_bumblebee_shield_regen_pause;
41
42 float autocvar_g_vehicle_bumblebee_cannon_cost;
43 float autocvar_g_vehicle_bumblebee_cannon_damage;
44 float autocvar_g_vehicle_bumblebee_cannon_radius;
45 float autocvar_g_vehicle_bumblebee_cannon_refire;
46 float autocvar_g_vehicle_bumblebee_cannon_speed;
47 float autocvar_g_vehicle_bumblebee_cannon_spread;
48 float autocvar_g_vehicle_bumblebee_cannon_force;
49
50 float autocvar_g_vehicle_bumblebee_cannon_ammo;
51 float autocvar_g_vehicle_bumblebee_cannon_ammo_regen;
52 float autocvar_g_vehicle_bumblebee_cannon_ammo_regen_pause;
53
54 var float autocvar_g_vehicle_bumblebee_cannon_lock = 0;
55
56 float autocvar_g_vehicle_bumblebee_cannon_turnspeed;
57 float autocvar_g_vehicle_bumblebee_cannon_pitchlimit_down;
58 float autocvar_g_vehicle_bumblebee_cannon_pitchlimit_up;
59 float autocvar_g_vehicle_bumblebee_cannon_turnlimit_in;
60 float autocvar_g_vehicle_bumblebee_cannon_turnlimit_out;
61
62
63 float autocvar_g_vehicle_bumblebee_raygun_turnspeed;
64 float autocvar_g_vehicle_bumblebee_raygun_pitchlimit_down;
65 float autocvar_g_vehicle_bumblebee_raygun_pitchlimit_up;
66 float autocvar_g_vehicle_bumblebee_raygun_turnlimit_sides;
67
68 float autocvar_g_vehicle_bumblebee_raygun_range;
69 float autocvar_g_vehicle_bumblebee_raygun_dps;
70 float autocvar_g_vehicle_bumblebee_raygun_aps;
71 float autocvar_g_vehicle_bumblebee_raygun_fps;
72
73 float autocvar_g_vehicle_bumblebee_raygun;
74 float autocvar_g_vehicle_bumblebee_healgun_hps;
75 float autocvar_g_vehicle_bumblebee_healgun_hmax;
76 float autocvar_g_vehicle_bumblebee_healgun_aps;
77 float autocvar_g_vehicle_bumblebee_healgun_amax;
78 float autocvar_g_vehicle_bumblebee_healgun_sps;
79 float autocvar_g_vehicle_bumblebee_healgun_locktime;
80
81 float autocvar_g_vehicle_bumblebee_respawntime;
82
83 float autocvar_g_vehicle_bumblebee_blowup_radius;
84 float autocvar_g_vehicle_bumblebee_blowup_coredamage;
85 float autocvar_g_vehicle_bumblebee_blowup_edgedamage;
86 float autocvar_g_vehicle_bumblebee_blowup_forceintensity;
87 var vector autocvar_g_vehicle_bumblebee_bouncepain;
88
89 var float autocvar_g_vehicle_bumblebee = 0;
90
91 float bumble_raygun_send(entity to, int sf);
92
93 void bumblebee_fire_cannon(entity _gun, string _tagname, entity _owner)
94 {
95         vector v = gettaginfo(_gun, gettagindex(_gun, _tagname));
96         vehicles_projectile("bigplasma_muzzleflash", "weapons/flacexp3.wav",
97                                                 v, normalize(v_forward + randomvec() * autocvar_g_vehicle_bumblebee_cannon_spread) * autocvar_g_vehicle_bumblebee_cannon_speed,
98                                                 autocvar_g_vehicle_bumblebee_cannon_damage, autocvar_g_vehicle_bumblebee_cannon_radius, autocvar_g_vehicle_bumblebee_cannon_force,  0,
99                                                 DEATH_VH_BUMB_GUN, PROJECTILE_BUMBLE_GUN, 0, true, true, _owner);
100 }
101
102 float bumblebee_gunner_frame()
103 {
104         entity vehic    = self.vehicle.owner;
105         entity gun      = self.vehicle;
106         entity gunner   = self;
107         self = vehic;
108
109         vehic.solid = SOLID_NOT;
110         //setorigin(gunner, vehic.origin);
111         gunner.velocity = vehic.velocity;
112
113         float _in, _out;
114         vehic.angles_x *= -1;
115         makevectors(vehic.angles);
116         vehic.angles_x *= -1;
117         if((gun == vehic.gun1))
118         {
119                 _in = autocvar_g_vehicle_bumblebee_cannon_turnlimit_in;
120                 _out = autocvar_g_vehicle_bumblebee_cannon_turnlimit_out;
121                 setorigin(gunner, vehic.origin + v_up * -16 + v_forward * -16 + v_right * 128);
122         }
123         else
124         {
125                 _in = autocvar_g_vehicle_bumblebee_cannon_turnlimit_out;
126                 _out = autocvar_g_vehicle_bumblebee_cannon_turnlimit_in;
127                 setorigin(gunner, vehic.origin + v_up * -16 + v_forward * -16 + v_right * -128);
128         }
129
130         crosshair_trace(gunner);
131         vector _ct = trace_endpos;
132         vector ad;
133
134         if(autocvar_g_vehicle_bumblebee_cannon_lock)
135         {
136                 if(gun.lock_time < time)
137                         gun.enemy = world;
138
139                 if(trace_ent)
140                         if(trace_ent.movetype)
141                                 if(trace_ent.takedamage)
142                                         if(!trace_ent.deadflag)
143                                         {
144                                                 if(teamplay)
145                                                 {
146                                                         if(trace_ent.team != gunner.team)
147                                                         {
148                                                                 gun.enemy = trace_ent;
149                                                                 gun.lock_time = time + 5;
150                                                         }
151                                                 }
152                                                 else
153                                                 {
154                                                         gun.enemy = trace_ent;
155                                                         gun.lock_time = time + 5;
156                                                 }
157                                         }
158         }
159
160         if(gun.enemy)
161         {
162                 float distance, impact_time;
163
164                 vector vf = real_origin(gun.enemy);
165                 vector _vel = gun.enemy.velocity;
166                 if(gun.enemy.movetype == MOVETYPE_WALK)
167                         _vel.z *= 0.1;
168
169
170                 ad = vf;
171                 distance = vlen(ad - gunner.origin);
172                 impact_time = distance / autocvar_g_vehicle_bumblebee_cannon_speed;
173                 ad = vf + _vel * impact_time;
174                 trace_endpos = ad;
175
176
177                 UpdateAuxiliaryXhair(gunner, ad, '1 0 1', 1);
178                 vehicle_aimturret(vehic, trace_endpos, gun, "fire",
179                                                   autocvar_g_vehicle_bumblebee_cannon_pitchlimit_down * -1, autocvar_g_vehicle_bumblebee_cannon_pitchlimit_up,
180                                                   _out * -1,  _in,  autocvar_g_vehicle_bumblebee_cannon_turnspeed);
181
182         }
183         else
184                 vehicle_aimturret(vehic, _ct, gun, "fire",
185                                                   autocvar_g_vehicle_bumblebee_cannon_pitchlimit_down * -1, autocvar_g_vehicle_bumblebee_cannon_pitchlimit_up,
186                                                   _out * -1,  _in,  autocvar_g_vehicle_bumblebee_cannon_turnspeed);
187
188         if(!forbidWeaponUse(gunner))
189         if(gunner.BUTTON_ATCK)
190                 if(time > gun.attack_finished_single)
191                         if(gun.vehicle_energy >= autocvar_g_vehicle_bumblebee_cannon_cost)
192                         {
193                                 gun.vehicle_energy -= autocvar_g_vehicle_bumblebee_cannon_cost;
194                                 bumblebee_fire_cannon(gun, "fire", gunner);
195                                 gun.delay = time;
196                                 gun.attack_finished_single = time + autocvar_g_vehicle_bumblebee_cannon_refire;
197                         }
198
199         VEHICLE_UPDATE_PLAYER(gunner, health, bumblebee);
200
201         if(vehic.vehicle_flags & VHF_HASSHIELD)
202                 VEHICLE_UPDATE_PLAYER(gunner, shield, bumblebee);
203
204         ad = gettaginfo(gun, gettagindex(gun, "fire"));
205         traceline(ad, ad + v_forward * MAX_SHOT_DISTANCE, MOVE_NORMAL, gun);
206
207         UpdateAuxiliaryXhair(gunner, trace_endpos, ('1 0 0' * gunner.vehicle_reload1) + ('0 1 0' *(1 - gunner.vehicle_reload1)), 0);
208
209         if(vehic.owner)
210                 UpdateAuxiliaryXhair(vehic.owner, trace_endpos, ('1 0 0' * gunner.vehicle_reload1) + ('0 1 0' *(1 - gunner.vehicle_reload1)), ((gunner == vehic.gunner1) ? 1 : 2));
211
212         vehic.solid = SOLID_BBOX;
213         gunner.BUTTON_ATCK = gunner.BUTTON_ATCK2 = gunner.BUTTON_CROUCH = 0;
214         gunner.vehicle_energy = (gun.vehicle_energy / autocvar_g_vehicle_bumblebee_cannon_ammo) * 100;
215
216         self = gunner;
217         return 1;
218 }
219
220 void bumblebee_gunner_exit(float _exitflag)
221 {
222         if(IS_REAL_CLIENT(self))
223         {
224                 msg_entity = self;
225                 WriteByte(MSG_ONE, SVC_SETVIEWPORT);
226                 WriteEntity(MSG_ONE, self);
227
228                 WriteByte(MSG_ONE, SVC_SETVIEWANGLES);
229                 WriteAngle(MSG_ONE, 0);
230                 WriteAngle(MSG_ONE, self.vehicle.angles.y);
231                 WriteAngle(MSG_ONE, 0);
232         }
233
234         CSQCVehicleSetup(self, HUD_NORMAL);
235         setsize(self, PL_MIN, PL_MAX);
236
237         self.takedamage     = DAMAGE_AIM;
238         self.solid          = SOLID_SLIDEBOX;
239         self.movetype       = MOVETYPE_WALK;
240         self.effects        &= ~EF_NODRAW;
241         self.alpha          = 1;
242         self.PlayerPhysplug = func_null;
243         self.view_ofs       = PL_VIEW_OFS;
244         self.event_damage   = PlayerDamage;
245         self.hud            = HUD_NORMAL;
246         self.teleportable       = TELEPORT_NORMAL;
247         self.switchweapon   = self.vehicle.switchweapon;
248
249     vh_player = self;
250     vh_vehicle = self.vehicle;
251     MUTATOR_CALLHOOK(VehicleExit);
252     self = vh_player;
253     self.vehicle = vh_vehicle;
254
255         self.vehicle.vehicle_hudmodel.viewmodelforclient = self.vehicle;
256
257         fixedmakevectors(self.vehicle.owner.angles);
258
259         if(self == self.vehicle.owner.gunner1)
260         {
261                 self.vehicle.owner.gunner1 = world;
262         }
263         else if(self == self.vehicle.owner.gunner2)
264         {
265                 self.vehicle.owner.gunner2 = world;
266                 v_right *= -1;
267         }
268         else
269                 dprint("^1self != gunner1 or gunner2, this is a BIG PROBLEM, tell tZork this happend.\n");
270
271         vector spot = self.vehicle.owner.origin + + v_up * 128 + v_right * 300;
272         spot = vehicles_findgoodexit(spot);
273         //setorigin(self , spot);
274
275         self.velocity = 0.75 * self.vehicle.owner.velocity + normalize(spot - self.vehicle.owner.origin) * 200;
276         self.velocity_z += 10;
277
278         self.vehicle.phase = time + 5;
279         self.vehicle        = world;
280 }
281
282 float bumblebee_gunner_enter()
283 {
284         RemoveGrapplingHook(other);
285         entity _gun, _gunner;
286         if(!self.gunner1)
287         {
288                 _gun = self.gun1;
289                 _gunner = self.gunner1;
290                 self.gunner1 = other;
291         }
292         else if(!self.gunner2)
293         {
294                 _gun = self.gun2;
295                 _gunner = self.gunner2;
296                 self.gunner2 = other;
297         }
298         else
299         {
300                 dprint("^1ERROR:^7Tried to enter a fully occupied vehicle!\n");
301                 return false;
302         }
303
304         _gunner            = other;
305         _gunner.vehicle    = _gun;
306         _gun.switchweapon  = other.switchweapon;
307         _gun.vehicle_exit  = bumblebee_gunner_exit;
308
309         other.angles            = self.angles;
310         other.takedamage        = DAMAGE_NO;
311         other.solid             = SOLID_NOT;
312         other.movetype          = MOVETYPE_NOCLIP;
313         other.alpha             = -1;
314         other.event_damage      = func_null;
315         other.view_ofs          = '0 0 0';
316         other.hud               = _gun.hud;
317         other.teleportable              = false;
318         other.PlayerPhysplug    = _gun.PlayerPhysplug;
319         other.vehicle_ammo1     = self.vehicle_ammo1;
320         other.vehicle_ammo2     = self.vehicle_ammo2;
321         other.vehicle_reload1   = self.vehicle_reload1;
322         other.vehicle_reload2   = self.vehicle_reload2;
323         other.vehicle_energy    = self.vehicle_energy;
324         other.PlayerPhysplug    = bumblebee_gunner_frame;
325         other.flags             &= ~FL_ONGROUND;
326
327         if(IS_REAL_CLIENT(other))
328         {
329                 msg_entity = other;
330                 WriteByte(MSG_ONE, SVC_SETVIEWPORT);
331                 WriteEntity(MSG_ONE, _gun.vehicle_viewport);
332                 WriteByte(MSG_ONE, SVC_SETVIEWANGLES);
333                 WriteAngle(MSG_ONE, _gun.angles_x + self.angles_x);    // tilt
334                 WriteAngle(MSG_ONE, _gun.angles_y + self.angles_y);    // yaw
335                 WriteAngle(MSG_ONE, 0);                             // roll
336         }
337
338         _gun.vehicle_hudmodel.viewmodelforclient = other;
339
340         CSQCVehicleSetup(other, other.hud);
341
342     vh_player = other;
343     vh_vehicle = _gun;
344     MUTATOR_CALLHOOK(VehicleEnter);
345     other = vh_player;
346     _gun = vh_vehicle;
347
348         return true;
349 }
350
351 float vehicles_valid_pilot()
352 {
353         if (!IS_PLAYER(other))
354                 return false;
355
356         if(other.deadflag != DEAD_NO)
357                 return false;
358
359         if(other.vehicle != world)
360                 return false;
361
362         if (!IS_REAL_CLIENT(other))
363                 if(!autocvar_g_vehicles_allow_bots)
364                         return false;
365
366         if(teamplay && other.team != self.team)
367                 return false;
368
369         return true;
370 }
371
372 void bumblebee_touch()
373 {
374         if(autocvar_g_vehicles_enter) { return; }
375
376         if(self.gunner1 != world && self.gunner2 != world)
377         {
378                 vehicles_touch();
379                 return;
380         }
381
382         if(vehicles_valid_pilot())
383         {
384                 if(self.gun1.phase <= time)
385                         if(bumblebee_gunner_enter())
386                                 return;
387
388                 if(self.gun2.phase <= time)
389                         if(bumblebee_gunner_enter())
390                                 return;
391         }
392
393         vehicles_touch();
394 }
395
396 void bumblebee_regen()
397 {
398         if(self.gun1.delay + autocvar_g_vehicle_bumblebee_cannon_ammo_regen_pause < time)
399                 self.gun1.vehicle_energy = min(autocvar_g_vehicle_bumblebee_cannon_ammo,
400                                                                            self.gun1.vehicle_energy + autocvar_g_vehicle_bumblebee_cannon_ammo_regen * frametime);
401
402         if(self.gun2.delay + autocvar_g_vehicle_bumblebee_cannon_ammo_regen_pause < time)
403                 self.gun2.vehicle_energy = min(autocvar_g_vehicle_bumblebee_cannon_ammo,
404                                                                            self.gun2.vehicle_energy + autocvar_g_vehicle_bumblebee_cannon_ammo_regen * frametime);
405
406         if(self.vehicle_flags  & VHF_SHIELDREGEN)
407                 vehicles_regen(self.dmg_time, vehicle_shield, autocvar_g_vehicle_bumblebee_shield, autocvar_g_vehicle_bumblebee_shield_regen_pause, autocvar_g_vehicle_bumblebee_shield_regen, frametime, true);
408
409         if(self.vehicle_flags  & VHF_HEALTHREGEN)
410                 vehicles_regen(self.dmg_time, vehicle_health, autocvar_g_vehicle_bumblebee_health, autocvar_g_vehicle_bumblebee_health_regen_pause, autocvar_g_vehicle_bumblebee_health_regen, frametime, false);
411
412         if(self.vehicle_flags  & VHF_ENERGYREGEN)
413                 vehicles_regen(self.wait, vehicle_energy, autocvar_g_vehicle_bumblebee_energy, autocvar_g_vehicle_bumblebee_energy_regen_pause, autocvar_g_vehicle_bumblebee_energy_regen, frametime, false);
414
415 }
416
417 float bumblebee_pilot_frame()
418 {
419         entity pilot, vehic;
420         vector newvel;
421         
422         if(intermission_running)
423         {
424                 self.vehicle.velocity = '0 0 0';
425                 self.vehicle.avelocity = '0 0 0';
426                 return 1;
427         }
428
429         pilot = self;
430         vehic = self.vehicle;
431         self   = vehic;
432
433         if(vehic.deadflag != DEAD_NO)
434         {
435                 self = pilot;
436                 pilot.BUTTON_ATCK = pilot.BUTTON_ATCK2 = 0;
437                 return 1;
438         }
439
440         bumblebee_regen();
441
442         crosshair_trace(pilot);
443
444         vector vang;
445         float ftmp;
446
447         vang = vehic.angles;
448         newvel = vectoangles(normalize(trace_endpos - self.origin + '0 0 32'));
449         vang.x *= -1;
450         newvel.x *= -1;
451         if(newvel.x > 180)  newvel.x -= 360;
452         if(newvel.x < -180) newvel.x += 360;
453         if(newvel.y > 180)  newvel.y -= 360;
454         if(newvel.y < -180) newvel.y += 360;
455
456         ftmp = shortangle_f(pilot.v_angle.y - vang.y, vang.y);
457         if(ftmp > 180)  ftmp -= 360;
458         if(ftmp < -180) ftmp += 360;
459         vehic.avelocity_y = bound(-autocvar_g_vehicle_bumblebee_turnspeed, ftmp + vehic.avelocity.y * 0.9, autocvar_g_vehicle_bumblebee_turnspeed);
460
461         // Pitch
462         ftmp = 0;
463         if(pilot.movement.x > 0 && vang.x < autocvar_g_vehicle_bumblebee_pitchlimit)
464                 ftmp = 4;
465         else if(pilot.movement.x < 0 && vang.x > -autocvar_g_vehicle_bumblebee_pitchlimit)
466                 ftmp = -8;
467
468         newvel.x = bound(-autocvar_g_vehicle_bumblebee_pitchlimit, newvel.x , autocvar_g_vehicle_bumblebee_pitchlimit);
469         ftmp = vang.x - bound(-autocvar_g_vehicle_bumblebee_pitchlimit, newvel.x + ftmp, autocvar_g_vehicle_bumblebee_pitchlimit);
470         vehic.avelocity_x = bound(-autocvar_g_vehicle_bumblebee_pitchspeed, ftmp + vehic.avelocity.x * 0.9, autocvar_g_vehicle_bumblebee_pitchspeed);
471
472         vehic.angles_x = anglemods(vehic.angles.x);
473         vehic.angles_y = anglemods(vehic.angles.y);
474         vehic.angles_z = anglemods(vehic.angles.z);
475
476         makevectors('0 1 0' * vehic.angles.y);
477         newvel = vehic.velocity * -autocvar_g_vehicle_bumblebee_friction;
478
479         if(pilot.movement.x != 0)
480         {
481                 if(pilot.movement.x > 0)
482                         newvel += v_forward  * autocvar_g_vehicle_bumblebee_speed_forward;
483                 else if(pilot.movement.x < 0)
484                         newvel -= v_forward  * autocvar_g_vehicle_bumblebee_speed_forward;
485         }
486
487         if(pilot.movement.y != 0)
488         {
489                 if(pilot.movement.y < 0)
490                         newvel -= v_right * autocvar_g_vehicle_bumblebee_speed_strafe;
491                 else if(pilot.movement.y > 0)
492                         newvel += v_right * autocvar_g_vehicle_bumblebee_speed_strafe;
493                 ftmp = newvel * v_right;
494                 ftmp *= frametime * 0.1;
495                 vehic.angles_z = bound(-15, vehic.angles.z + ftmp, 15);
496         }
497         else
498         {
499                 vehic.angles_z *= 0.95;
500                 if(vehic.angles.z >= -1 && vehic.angles.z <= -1)
501                         vehic.angles_z = 0;
502         }
503
504         if(pilot.BUTTON_CROUCH)
505                 newvel -=   v_up * autocvar_g_vehicle_bumblebee_speed_down;
506         else if(pilot.BUTTON_JUMP)
507                 newvel +=  v_up * autocvar_g_vehicle_bumblebee_speed_up;
508
509         vehic.velocity  += newvel * frametime;
510         pilot.velocity = pilot.movement  = vehic.velocity;
511
512
513         if(autocvar_g_vehicle_bumblebee_healgun_locktime)
514         {
515                 if(vehic.tur_head.lock_time < time || vehic.tur_head.enemy.deadflag)
516                         vehic.tur_head.enemy = world;
517
518                 if(trace_ent)
519                 if(trace_ent.movetype)
520                 if(trace_ent.takedamage)
521                 if(!trace_ent.deadflag)
522                 {
523                         if(teamplay)
524                         {
525                                 if(trace_ent.team == pilot.team)
526                                 {
527                                         vehic.tur_head.enemy = trace_ent;
528                                         vehic.tur_head.lock_time = time + autocvar_g_vehicle_bumblebee_healgun_locktime;
529                                 }
530                         }
531                         else
532                         {
533                                 vehic.tur_head.enemy = trace_ent;
534                                 vehic.tur_head.lock_time = time + autocvar_g_vehicle_bumblebee_healgun_locktime;
535                         }
536                 }
537
538                 if(vehic.tur_head.enemy)
539                 {
540                         trace_endpos = real_origin(vehic.tur_head.enemy);
541                         UpdateAuxiliaryXhair(pilot, trace_endpos, '0 0.75 0', 0);
542                 }
543         }
544
545         vang = vehicle_aimturret(vehic, trace_endpos, self.gun3, "fire",
546                                           autocvar_g_vehicle_bumblebee_raygun_pitchlimit_down * -1,  autocvar_g_vehicle_bumblebee_raygun_pitchlimit_up,
547                                           autocvar_g_vehicle_bumblebee_raygun_turnlimit_sides * -1,  autocvar_g_vehicle_bumblebee_raygun_turnlimit_sides,  autocvar_g_vehicle_bumblebee_raygun_turnspeed);
548
549         if(!forbidWeaponUse(pilot))
550         if((pilot.BUTTON_ATCK || pilot.BUTTON_ATCK2) && (vehic.vehicle_energy > autocvar_g_vehicle_bumblebee_raygun_dps * sys_frametime || autocvar_g_vehicle_bumblebee_raygun == 0))
551         {
552                 vehic.gun3.enemy.realowner = pilot;
553                 vehic.gun3.enemy.effects &= ~EF_NODRAW;
554
555                 vehic.gun3.enemy.hook_start = gettaginfo(vehic.gun3, gettagindex(vehic.gun3, "fire"));
556                 vehic.gun3.enemy.SendFlags |= BRG_START;
557
558                 traceline(vehic.gun3.enemy.hook_start, vehic.gun3.enemy.hook_start + v_forward * autocvar_g_vehicle_bumblebee_raygun_range, MOVE_NORMAL, vehic);
559
560                 if(trace_ent)
561                 {
562                         if(autocvar_g_vehicle_bumblebee_raygun)
563                         {
564                                 Damage(trace_ent, vehic, pilot, autocvar_g_vehicle_bumblebee_raygun_dps * sys_frametime, DEATH_GENERIC, trace_endpos, v_forward * autocvar_g_vehicle_bumblebee_raygun_fps * sys_frametime);
565                                 vehic.vehicle_energy -= autocvar_g_vehicle_bumblebee_raygun_aps * sys_frametime;
566                         }
567                         else
568                         {
569                                 if(trace_ent.deadflag == DEAD_NO)
570                                         if((teamplay && trace_ent.team == pilot.team) || !teamplay)
571                                         {
572
573                                                 if(trace_ent.vehicle_flags & VHF_ISVEHICLE)
574                                                 {
575                                                         if(autocvar_g_vehicle_bumblebee_healgun_sps && trace_ent.vehicle_health <= trace_ent.max_health)
576                                                                 trace_ent.vehicle_shield = min(trace_ent.vehicle_shield + autocvar_g_vehicle_bumblebee_healgun_sps * frametime, trace_ent.tur_head.max_health);
577
578                                                         if(autocvar_g_vehicle_bumblebee_healgun_hps)
579                                                                 trace_ent.vehicle_health = min(trace_ent.vehicle_health + autocvar_g_vehicle_bumblebee_healgun_hps * frametime, trace_ent.max_health);
580                                                 }
581                                                 else if(IS_CLIENT(trace_ent))
582                                                 {
583                                                         if(trace_ent.health <= autocvar_g_vehicle_bumblebee_healgun_hmax && autocvar_g_vehicle_bumblebee_healgun_hps)
584                                                                 trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * frametime, autocvar_g_vehicle_bumblebee_healgun_hmax);
585
586                                                         if(trace_ent.armorvalue <= autocvar_g_vehicle_bumblebee_healgun_amax && autocvar_g_vehicle_bumblebee_healgun_aps)
587                                                                 trace_ent.armorvalue = min(trace_ent.armorvalue + autocvar_g_vehicle_bumblebee_healgun_aps * frametime, autocvar_g_vehicle_bumblebee_healgun_amax);
588
589                                                         trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * frametime, autocvar_g_vehicle_bumblebee_healgun_hmax);
590                                                 }
591                                                 else if(trace_ent.turrcaps_flags & TFL_TURRCAPS_ISTURRET)
592                                                 {
593                                                         if(trace_ent.health  <= trace_ent.max_health && autocvar_g_vehicle_bumblebee_healgun_hps)
594                                                                 trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * frametime, trace_ent.max_health);
595                                                         //else ..hmmm what? ammo?
596
597                                                         trace_ent.SendFlags |= TNSF_STATUS;
598                                                 }
599                                         }
600                         }
601                 }
602
603                 vehic.gun3.enemy.hook_end = trace_endpos;
604                 setorigin(vehic.gun3.enemy, trace_endpos);
605                 vehic.gun3.enemy.SendFlags |= BRG_END;
606
607                 vehic.wait = time + 1;
608         }
609         else
610                 vehic.gun3.enemy.effects |= EF_NODRAW;
611         /*{
612                 if(vehic.gun3.enemy)
613                         remove(vehic.gun3.enemy);
614
615                 vehic.gun3.enemy = world;
616         }
617         */
618
619         VEHICLE_UPDATE_PLAYER(pilot, health, bumblebee);
620         VEHICLE_UPDATE_PLAYER(pilot, energy, bumblebee);
621
622         pilot.vehicle_ammo1 = (vehic.gun1.vehicle_energy / autocvar_g_vehicle_bumblebee_cannon_ammo) * 100;
623         pilot.vehicle_ammo2 = (vehic.gun2.vehicle_energy / autocvar_g_vehicle_bumblebee_cannon_ammo) * 100;
624
625         if(vehic.vehicle_flags & VHF_HASSHIELD)
626                 VEHICLE_UPDATE_PLAYER(pilot, shield, bumblebee);
627
628         vehic.angles_x *= -1;
629         makevectors(vehic.angles);
630         vehic.angles_x *= -1;
631         setorigin(pilot, vehic.origin + v_up * 48 + v_forward * 160);
632
633         pilot.BUTTON_ATCK = pilot.BUTTON_ATCK2 = pilot.BUTTON_CROUCH = 0;
634         self = pilot;
635
636         return 1;
637 }
638
639 void bumblebee_land()
640 {
641         float hgt;
642
643         hgt = raptor_altitude(512);
644         self.velocity = (self.velocity * 0.9) + ('0 0 -1800' * (hgt / 256) * sys_frametime);
645         self.angles_x *= 0.95;
646         self.angles_z *= 0.95;
647
648         if(hgt < 16)
649                 self.think      = vehicles_think;
650
651         self.nextthink = time;
652         
653         CSQCMODEL_AUTOUPDATE();
654 }
655
656 void bumblebee_exit(float eject)
657 {
658         if(self.owner.vehicleid == VEH_BUMBLEBEE)
659         {
660                 bumblebee_gunner_exit(eject);
661                 return;
662         }
663
664         self.touch = vehicles_touch;
665
666         if(self.deadflag == DEAD_NO)
667         {
668                 self.think = bumblebee_land;
669                 self.nextthink  = time;
670         }
671         
672         self.movetype = MOVETYPE_TOSS;
673
674         if(!self.owner)
675                 return;
676
677         fixedmakevectors(self.angles);
678         vector spot;
679         if(vlen(self.velocity) > autocvar_g_vehicle_bumblebee_speed_forward * 0.5)
680                 spot = self.origin + v_up * 128 + v_forward * 300;
681         else
682                 spot = self.origin + v_up * 128 - v_forward * 300;
683
684         spot = vehicles_findgoodexit(spot);
685
686         // Hide beam
687         if(self.gun3.enemy || !wasfreed(self.gun3.enemy)) {
688                 self.gun3.enemy.effects |= EF_NODRAW;
689     }
690
691         self.owner.velocity = 0.75 * self.vehicle.velocity + normalize(spot - self.vehicle.origin) * 200;
692         self.owner.velocity_z += 10;
693         setorigin(self.owner, spot);
694
695         antilag_clear(self.owner);
696     self.owner = world;
697 }
698
699 void bumblebee_blowup()
700 {
701         RadiusDamage(self, self.enemy, autocvar_g_vehicle_bumblebee_blowup_coredamage,
702                                  autocvar_g_vehicle_bumblebee_blowup_edgedamage,
703                                  autocvar_g_vehicle_bumblebee_blowup_radius, self, world,
704                                  autocvar_g_vehicle_bumblebee_blowup_forceintensity,
705                                  DEATH_VH_BUMB_DEATH, world);
706
707         sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM);
708         pointparticles(particleeffectnum("explosion_big"), (self.origin + '0 0 100') + (randomvec() * 80), '0 0 0', 1);
709
710         if(self.owner.deadflag == DEAD_DYING)
711                 self.owner.deadflag = DEAD_DEAD;
712
713         remove(self);
714 }
715
716 void bumblebee_diethink()
717 {
718         if(time >= self.wait)
719                 self.think = bumblebee_blowup;
720
721         if(random() < 0.1)
722         {
723                 sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM);
724                 pointparticles(particleeffectnum("explosion_small"), randomvec() * 80 + (self.origin + '0 0 100'), '0 0 0', 1);
725         }
726
727         self.nextthink = time + 0.1;
728 }
729
730 float bumble_raygun_send(entity to, float sf)
731 {
732         WriteByte(MSG_ENTITY, ENT_CLIENT_BUMBLE_RAYGUN);
733
734         WriteByte(MSG_ENTITY, sf);
735         if(sf & BRG_SETUP)
736         {
737                 WriteByte(MSG_ENTITY, num_for_edict(self.realowner));
738                 WriteByte(MSG_ENTITY, self.realowner.team);
739                 WriteByte(MSG_ENTITY, self.cnt);
740         }
741
742         if(sf & BRG_START)
743         {
744                 WriteCoord(MSG_ENTITY, self.hook_start_x);
745                 WriteCoord(MSG_ENTITY, self.hook_start_y);
746                 WriteCoord(MSG_ENTITY, self.hook_start_z);
747         }
748
749         if(sf & BRG_END)
750         {
751                 WriteCoord(MSG_ENTITY, self.hook_end_x);
752                 WriteCoord(MSG_ENTITY, self.hook_end_y);
753                 WriteCoord(MSG_ENTITY, self.hook_end_z);
754         }
755
756         return true;
757 }
758
759 void spawnfunc_vehicle_bumblebee()
760 {
761         if(!autocvar_g_vehicle_bumblebee) { remove(self); return; }
762         if(!vehicle_initialize(VEH_BUMBLEBEE, false)) { remove(self); return; }
763 }
764
765 float v_bumblebee(float req)
766 {
767         switch(req)
768         {
769                 case VR_IMPACT:
770                 {
771                         if(autocvar_g_vehicle_bumblebee_bouncepain)
772                                 vehicles_impact(autocvar_g_vehicle_bumblebee_bouncepain_x, autocvar_g_vehicle_bumblebee_bouncepain_y, autocvar_g_vehicle_bumblebee_bouncepain_z);
773                                 
774                         return true;
775                 }
776                 case VR_ENTER:
777                 {
778                         self.touch = bumblebee_touch;
779                         self.nextthink = 0;
780                         self.movetype = MOVETYPE_BOUNCEMISSILE;
781                         return true;
782                 }
783                 case VR_THINK:
784                 {
785                         self.angles_z *= 0.8;
786                         self.angles_x *= 0.8;
787                         
788                         self.nextthink = time;
789                         
790                         if(!self.owner)
791                         {
792                                 entity oldself = self;          
793                                 if(self.gunner1)
794                                 {
795                                         self = self.gunner1;
796                                         oldself.gun1.vehicle_exit(VHEF_EJECT);
797                                         entity oldother = other;
798                                         other = self;
799                                         self = oldself;
800                                         self.phase = 0;
801                                         self.touch();
802                                         other = oldother;
803                                         return true;
804                                 }
805                                 
806                                 if(self.gunner2)
807                                 {
808                                         self = self.gunner2;
809                                         oldself.gun2.vehicle_exit(VHEF_EJECT);
810                                         entity oldother = other;
811                                         other = self;
812                                         self = oldself;
813                                         self.phase = 0;
814                                         self.touch();
815                                         other = oldother;
816                                         return true;
817                                 }               
818                         }
819                         
820                         return true;
821                 }
822                 case VR_DEATH:
823                 {
824                         entity oldself = self;
825
826                         CSQCModel_UnlinkEntity();
827
828                         // Hide beam
829                         if(self.gun3.enemy || !wasfreed(self.gun3.enemy))
830                                 self.gun3.enemy.effects |= EF_NODRAW;
831                         
832                         if(self.gunner1)
833                         {
834                                 self = self.gunner1;
835                                 oldself.gun1.vehicle_exit(VHEF_EJECT);
836                                 self = oldself;
837                         }
838
839                         if(self.gunner2)
840                         {
841                                 self = self.gunner2;
842                                 oldself.gun2.vehicle_exit(VHEF_EJECT);
843                                 self = oldself;
844                         }
845
846                         self.vehicle_exit(VHEF_EJECT);
847
848                         fixedmakevectors(self.angles);
849                         vehicle_tossgib(self.gun1, self.velocity + v_right * 300 + v_up * 100 + randomvec() * 200, "cannon_right", rint(random()), rint(random()), 6, randomvec() * 200);
850                         vehicle_tossgib(self.gun2, self.velocity + v_right * -300 + v_up * 100 + randomvec() * 200, "cannon_left", rint(random()), rint(random()), 6, randomvec() * 200);
851                         vehicle_tossgib(self.gun3, self.velocity + v_forward * 300 + v_up * -100 + randomvec() * 200, "raygun", rint(random()), rint(random()), 6, randomvec() * 300);
852
853                         entity _body = vehicle_tossgib(self, self.velocity + randomvec() * 200, "", rint(random()), rint(random()), 6, randomvec() * 100);
854
855                         if(random() > 0.5)
856                                 _body.touch = bumblebee_blowup;
857                         else
858                                 _body.touch = func_null;
859                                 
860                         _body.think = bumblebee_diethink;
861                         _body.nextthink = time;
862                         _body.wait = time + 2 + (random() * 8);
863                         _body.owner = self;
864                         _body.enemy = self.enemy;
865                         _body.scale = 1.5;
866                         _body.angles = self.angles;
867                         
868                         pointparticles(particleeffectnum("explosion_medium"), findbetterlocation(self.origin, 16), '0 0 0', 1);
869                         
870                         self.health                     = 0;
871                         self.event_damage       = func_null;
872                         self.solid                      = SOLID_NOT;
873                         self.takedamage         = DAMAGE_NO;
874                         self.deadflag           = DEAD_DYING;
875                         self.movetype           = MOVETYPE_NONE;
876                         self.effects            = EF_NODRAW;
877                         self.colormod           = '0 0 0';
878                         self.avelocity          = '0 0 0';
879                         self.velocity           = '0 0 0';
880                         self.touch                      = func_null;
881                         self.nextthink          = 0;
882
883                         setorigin(self, self.pos1);
884                         return true;
885                 }
886                 case VR_SPAWN:
887                 {
888                         if(!self.gun1)
889                         {
890                                 // for some reason, autosizing of the shield entity refuses to work for this one so set it up in advance.
891                                 self.vehicle_shieldent = spawn();
892                                 self.vehicle_shieldent.effects = EF_LOWPRECISION;
893                                 setmodel(self.vehicle_shieldent, "models/vhshield.md3");
894                                 setattachment(self.vehicle_shieldent, self, "");
895                                 setorigin(self.vehicle_shieldent, real_origin(self) - self.origin);
896                                 self.vehicle_shieldent.scale       = 512 / vlen(self.maxs - self.mins);
897                                 self.vehicle_shieldent.think       = shieldhit_think;
898                                 self.vehicle_shieldent.alpha = -1;
899                                 self.vehicle_shieldent.effects = EF_LOWPRECISION | EF_NODRAW;
900
901                                 self.gun1 = spawn();
902                                 self.gun2 = spawn();
903                                 self.gun3 = spawn();
904
905                                 self.vehicle_flags |= VHF_MULTISLOT;
906
907                                 self.gun1.owner = self;
908                                 self.gun2.owner = self;
909                                 self.gun3.owner = self;
910
911                                 setmodel(self.gun1, "models/vehicles/bumblebee_plasma_right.dpm");
912                                 setmodel(self.gun2, "models/vehicles/bumblebee_plasma_left.dpm");
913                                 setmodel(self.gun3, "models/vehicles/bumblebee_ray.dpm");
914
915                                 setattachment(self.gun1, self, "cannon_right");
916                                 setattachment(self.gun2, self, "cannon_left");
917
918                                 // Angled bones are no fun, messes up gun-aim; so work arround it.
919                                 self.gun3.pos1 = self.angles;
920                                 self.angles = '0 0 0';
921                                 vector ofs = gettaginfo(self, gettagindex(self, "raygun"));
922                                 ofs -= self.origin;
923                                 setattachment(self.gun3, self, "");
924                                 setorigin(self.gun3, ofs);
925                                 self.angles = self.gun3.pos1;
926
927                                 vehicle_addplayerslot(self, self.gun1, HUD_BUMBLEBEE_GUN, "models/vehicles/wakizashi_cockpit.dpm", bumblebee_gunner_frame, bumblebee_gunner_exit, bumblebee_gunner_enter);
928                                 vehicle_addplayerslot(self, self.gun2, HUD_BUMBLEBEE_GUN, "models/vehicles/wakizashi_cockpit.dpm", bumblebee_gunner_frame, bumblebee_gunner_exit, bumblebee_gunner_enter);
929
930                                 setorigin(self.vehicle_hudmodel, '50 0 -5');    // Move cockpit forward - down.
931                                 setorigin(self.vehicle_viewport, '5 0 2');    // Move camera forward up
932
933                                 //fixme-model-bones
934                                 setorigin(self.gun1.vehicle_hudmodel, '90 -27 -23');
935                                 setorigin(self.gun1.vehicle_viewport, '-85 0 50');
936                                 //fixme-model-bones
937                                 setorigin(self.gun2.vehicle_hudmodel, '90 27 -23');
938                                 setorigin(self.gun2.vehicle_viewport, '-85 0 50');
939
940                                 self.scale = 1.5;
941                                 
942                                 // Raygun beam
943                                 if(self.gun3.enemy == world)
944                                 {                       
945                                         self.gun3.enemy = spawn();
946                                         Net_LinkEntity(self.gun3.enemy, true, 0, bumble_raygun_send);
947                                         self.gun3.enemy.SendFlags = BRG_SETUP;                  
948                                         self.gun3.enemy.cnt = autocvar_g_vehicle_bumblebee_raygun;                      
949                                         self.gun3.enemy.effects = EF_NODRAW | EF_LOWPRECISION;
950                                 }
951                         }
952
953                         self.vehicle_health = autocvar_g_vehicle_bumblebee_health;
954                         self.vehicle_shield = autocvar_g_vehicle_bumblebee_shield;
955                         self.solid = SOLID_BBOX;
956                         self.movetype = MOVETYPE_TOSS;
957                         self.damageforcescale = 0.025;
958                         
959                         self.PlayerPhysplug = bumblebee_pilot_frame;
960                         
961                         setorigin(self, self.origin + '0 0 25');
962                         return true;
963                 }
964                 case VR_SETUP:
965                 {
966                         if(autocvar_g_vehicle_bumblebee_energy)
967                         if(autocvar_g_vehicle_bumblebee_energy_regen)
968                                 self.vehicle_flags |= VHF_ENERGYREGEN;
969
970                         if(autocvar_g_vehicle_bumblebee_shield)
971                                 self.vehicle_flags |= VHF_HASSHIELD;
972
973                         if(autocvar_g_vehicle_bumblebee_shield_regen)
974                                 self.vehicle_flags |= VHF_SHIELDREGEN;
975
976                         if(autocvar_g_vehicle_bumblebee_health_regen)
977                                 self.vehicle_flags |= VHF_HEALTHREGEN;
978                                 
979                         self.vehicle_exit = bumblebee_exit;
980                         self.respawntime = autocvar_g_vehicle_bumblebee_respawntime;
981                         self.vehicle_health = autocvar_g_vehicle_bumblebee_health;
982                         self.max_health = self.vehicle_health;
983                         self.vehicle_shield = autocvar_g_vehicle_bumblebee_shield;
984                                 
985                         return true;
986                 }
987                 case VR_PRECACHE:
988                 {
989                         precache_model("models/vehicles/bumblebee_body.dpm");
990                         precache_model("models/vehicles/bumblebee_plasma_left.dpm");
991                         precache_model("models/vehicles/bumblebee_plasma_right.dpm");
992                         precache_model("models/vehicles/bumblebee_ray.dpm");
993                         precache_model("models/vehicles/wakizashi_cockpit.dpm");
994                         precache_model("models/vehicles/spiderbot_cockpit.dpm");
995                         precache_model("models/vehicles/raptor_cockpit.dpm");
996                         return true;
997                 }
998         }
999
1000         return true;
1001 }
1002
1003 #endif // SVQC
1004 #ifdef CSQC
1005
1006 #define bumb_ico  "gfx/vehicles/bumb.tga"
1007 #define bumb_lgun  "gfx/vehicles/bumb_lgun.tga"
1008 #define bumb_rgun  "gfx/vehicles/bumb_rgun.tga"
1009
1010 #define bumb_gun_ico  "gfx/vehicles/bumb_side.tga"
1011 #define bumb_gun_gun  "gfx/vehicles/bumb_side_gun.tga"
1012
1013 void CSQC_BUMBLE_GUN_HUD()
1014 {
1015         if(autocvar_r_letterbox)
1016                 return;
1017
1018         vector picsize, hudloc = '0 0 0', pic2size, picloc;
1019
1020         // Fetch health & ammo stats
1021         HUD_GETVEHICLESTATS
1022
1023         picsize = draw_getimagesize(hud_bg) * autocvar_cl_vehicles_hudscale;
1024         hudloc_y = vid_conheight - picsize_y;
1025         hudloc_x = vid_conwidth * 0.5 - picsize_x * 0.5;
1026
1027         drawpic(hudloc, hud_bg, picsize, '1 1 1', autocvar_cl_vehicles_hudalpha, DRAWFLAG_NORMAL);
1028
1029         shield  *= 0.01;
1030         vh_health  *= 0.01;
1031         energy  *= 0.01;
1032         reload1 *= 0.01;
1033
1034         pic2size = draw_getimagesize(bumb_gun_ico) * (autocvar_cl_vehicles_hudscale * 0.8);
1035         picloc = picsize * 0.5 - pic2size * 0.5;
1036
1037         if(vh_health < 0.25)
1038                 drawpic(hudloc + picloc, bumb_gun_ico, pic2size,  '1 0 0' + '0 1 1' * sin(time * 8),  1, DRAWFLAG_NORMAL);
1039         else
1040                 drawpic(hudloc + picloc, bumb_gun_ico, pic2size,  '1 1 1' * vh_health  + '1 0 0' * (1 - vh_health),  1, DRAWFLAG_NORMAL);
1041
1042         drawpic(hudloc + picloc, bumb_gun_gun, pic2size, '1 1 1' * energy   + '1 0 0' * (1 - energy),   1, DRAWFLAG_NORMAL);
1043         drawpic(hudloc + picloc, hud_sh, pic2size,  '1 1 1', shield, DRAWFLAG_NORMAL);
1044
1045 // Health bar
1046         picsize = draw_getimagesize(hud_hp_bar) * autocvar_cl_vehicles_hudscale;
1047         picloc = '69 69 0' * autocvar_cl_vehicles_hudscale;
1048         drawsetcliparea(hudloc_x + picloc_x + (picsize_x * (1 - vh_health)), 0, vid_conwidth, vid_conheight);
1049         drawpic(hudloc + picloc, hud_hp_bar, picsize, '1 1 1', 1 , DRAWFLAG_NORMAL);
1050         drawresetcliparea();
1051 // ..  and icon
1052         picsize = draw_getimagesize(hud_hp_ico) * autocvar_cl_vehicles_hudscale;
1053         picloc = '37 65 0' * autocvar_cl_vehicles_hudscale;
1054         if(vh_health < 0.25)
1055         {
1056                 if(alarm1time < time)
1057                 {
1058                         alarm1time = time + 2;
1059                         vehicle_alarm(self, CH_PAIN_SINGLE, "vehicles/alarm.wav");
1060                 }
1061
1062                 drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
1063         }
1064         else
1065         {
1066                 drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
1067                 if(alarm1time)
1068                 {
1069                         vehicle_alarm(self, CH_PAIN_SINGLE, "misc/null.wav");
1070                         alarm1time = 0;
1071                 }
1072         }
1073
1074 // Shield bar
1075         picsize = draw_getimagesize(hud_sh_bar) * autocvar_cl_vehicles_hudscale;
1076         picloc = '69 140 0' * autocvar_cl_vehicles_hudscale;
1077         drawsetcliparea(hudloc_x + picloc_x + (picsize_x * (1 - shield)), 0, vid_conwidth, vid_conheight);
1078         drawpic(hudloc + picloc, hud_sh_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
1079         drawresetcliparea();
1080 // ..  and icon
1081         picloc = '40 136 0' * autocvar_cl_vehicles_hudscale;
1082         picsize = draw_getimagesize(hud_sh_ico) * autocvar_cl_vehicles_hudscale;
1083         if(shield < 0.25)
1084         {
1085                 if(alarm2time < time)
1086                 {
1087                         alarm2time = time + 1;
1088                         vehicle_alarm(self, CH_TRIGGER_SINGLE, "vehicles/alarm_shield.wav");
1089                 }
1090                 drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
1091         }
1092         else
1093         {
1094                 drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
1095                 if(alarm2time)
1096                 {
1097                         vehicle_alarm(self, CH_TRIGGER_SINGLE, "misc/null.wav");
1098                         alarm2time = 0;
1099                 }
1100         }
1101
1102 // Gun bar
1103         picsize = draw_getimagesize(hud_ammo1_bar) * autocvar_cl_vehicles_hudscale;
1104         picloc = '450 69 0' * autocvar_cl_vehicles_hudscale;
1105         drawsetcliparea(hudloc_x + picloc_x, picloc_y, picsize_x * energy, vid_conheight);
1106         drawpic(hudloc + picloc, hud_ammo1_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
1107         drawresetcliparea();
1108
1109 // ..  and icon
1110         picsize = 1.5 * draw_getimagesize(hud_energy) * autocvar_cl_vehicles_hudscale;
1111         picloc = '664 60 0' * autocvar_cl_vehicles_hudscale;
1112         if(energy < 0.2)
1113                 drawpic(hudloc + picloc, hud_energy, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
1114         else
1115                 drawpic(hudloc + picloc, hud_energy, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
1116
1117         if (scoreboard_showscores)
1118                 HUD_DrawScoreboard();
1119         /*
1120         else
1121         {
1122                 picsize = draw_getimagesize(waki_xhair);
1123                 picsize_x *= 0.5;
1124                 picsize_y *= 0.5;
1125
1126
1127                 drawpic('0.5 0 0' * (vid_conwidth - picsize_x) + '0 0.5 0' * (vid_conheight - picsize_y), waki_xhair, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
1128         }
1129         */
1130 }
1131
1132 void bumble_raygun_draw()
1133 {
1134         float _len;
1135         vector _dir;
1136         vector _vtmp1, _vtmp2;
1137
1138         _len = vlen(self.origin - self.move_origin);
1139         _dir = normalize(self.move_origin - self.origin);
1140
1141         if(self.total_damages < time)
1142         {
1143                 boxparticles(self.traileffect, self, self.origin, self.origin + _dir * -64, _dir * -_len , _dir * -_len, 1, PARTICLES_USEALPHA);
1144                 boxparticles(self.lip, self, self.move_origin, self.move_origin + _dir * -64, _dir * -200 , _dir * -200, 1, PARTICLES_USEALPHA);
1145                 self.total_damages = time + 0.1;
1146         }
1147
1148         float i, df, sz, al;
1149         for(i = -0.1; i < 0.2; i += 0.1)
1150         {
1151                 df = DRAWFLAG_NORMAL; //((random() < 0.5) ? DRAWFLAG_ADDITIVE : DRAWFLAG_SCREEN);
1152                 sz = 5 + random() * 5;
1153                 al = 0.25 + random() * 0.5;
1154                 _vtmp1 = self.origin + _dir * _len * (0.25 + i);
1155                 _vtmp1 += (randomvec() * (_len * 0.2) * (frametime * 2));       //self.raygun_l1;
1156                 Draw_CylindricLine(self.origin, _vtmp1, sz, "gfx/colors/white.tga", 1, 1, self.colormod, al, df, view_origin);
1157
1158                 _vtmp2 = self.origin + _dir * _len * (0.5 + i);
1159                 _vtmp2 += (randomvec() * (_len * 0.2) * (frametime * 5));       //self.raygun_l2;
1160                 Draw_CylindricLine(_vtmp1, _vtmp2, sz, "gfx/colors/white.tga", 1, 1, self.colormod, al, df, view_origin);
1161
1162                 _vtmp1 = self.origin + _dir * _len * (0.75 + i);
1163                 _vtmp1 += randomvec() * (_len * 0.2) * (frametime * 10);     //self.raygun_l3;
1164                 Draw_CylindricLine(_vtmp2, _vtmp1, sz, "gfx/colors/white.tga", 1, 1, self.colormod, al, df, view_origin);
1165
1166                 Draw_CylindricLine(_vtmp1, self.move_origin +  randomvec() * 32, sz, "gfx/colors/white.tga", 1, 1, self.colormod, al, df, view_origin);
1167         }
1168 }
1169
1170 void bumble_raygun_read(float bIsNew)
1171 {
1172         int sf = ReadByte();
1173
1174         if(sf & BRG_SETUP)
1175         {
1176                 self.cnt  = ReadByte();
1177                 self.team = ReadByte();
1178                 self.cnt  = ReadByte();
1179
1180                 if(self.cnt)
1181                         self.colormod = '1 0 0';
1182                 else
1183                         self.colormod = '0 1 0';
1184
1185                 self.traileffect = particleeffectnum("healray_muzzleflash");
1186                 self.lip = particleeffectnum("healray_impact");
1187
1188                 self.draw = bumble_raygun_draw;
1189         }
1190
1191
1192         if(sf & BRG_START)
1193         {
1194                 self.origin_x = ReadCoord();
1195                 self.origin_y = ReadCoord();
1196                 self.origin_z = ReadCoord();
1197                 setorigin(self, self.origin);
1198         }
1199
1200         if(sf & BRG_END)
1201         {
1202                 self.move_origin_x = ReadCoord();
1203                 self.move_origin_y = ReadCoord();
1204                 self.move_origin_z = ReadCoord();
1205         }
1206 }
1207
1208 float v_bumblebee(float req)
1209 {
1210         switch(req)
1211         {
1212                 case VR_HUD:
1213                 {
1214                         if(autocvar_r_letterbox)
1215                                 return true;
1216
1217                         vector picsize, hudloc = '0 0 0', pic2size, picloc;
1218
1219                         // Fetch health & ammo stats
1220                         HUD_GETVEHICLESTATS
1221
1222                         picsize = draw_getimagesize(hud_bg) * autocvar_cl_vehicles_hudscale;
1223                         hudloc_y = vid_conheight - picsize_y;
1224                         hudloc_x = vid_conwidth * 0.5 - picsize_x * 0.5;
1225
1226                         drawpic(hudloc, hud_bg, picsize, '1 1 1', autocvar_cl_vehicles_hudalpha, DRAWFLAG_NORMAL);
1227
1228                         shield  *= 0.01;
1229                         vh_health  *= 0.01;
1230                         energy  *= 0.01;
1231                         reload1 *= 0.01;
1232
1233                         pic2size = draw_getimagesize(bumb_ico) * (autocvar_cl_vehicles_hudscale * 0.8);
1234                         picloc = picsize * 0.5 - pic2size * 0.5;
1235
1236                         if(vh_health < 0.25)
1237                                 drawpic(hudloc + picloc, bumb_ico, pic2size,  '1 0 0' + '0 1 1' * sin(time * 8),  1, DRAWFLAG_NORMAL);
1238                         else
1239                                 drawpic(hudloc + picloc, bumb_ico, pic2size,  '1 1 1' * vh_health  + '1 0 0' * (1 - vh_health),  1, DRAWFLAG_NORMAL);
1240
1241                         drawpic(hudloc + picloc, bumb_lgun, pic2size, '1 1 1' * energy   + '1 0 0' * (1 - energy),   1, DRAWFLAG_NORMAL);
1242                         drawpic(hudloc + picloc, bumb_lgun, pic2size, '1 1 1' * energy   + '1 0 0' * (1 - energy),   1, DRAWFLAG_NORMAL);
1243                         drawpic(hudloc + picloc, hud_sh, pic2size,  '1 1 1', shield, DRAWFLAG_NORMAL);
1244
1245                 // Health bar
1246                         picsize = draw_getimagesize(hud_hp_bar) * autocvar_cl_vehicles_hudscale;
1247                         picloc = '69 69 0' * autocvar_cl_vehicles_hudscale;
1248                         drawsetcliparea(hudloc_x + picloc_x + (picsize_x * (1 - vh_health)), 0, vid_conwidth, vid_conheight);
1249                         drawpic(hudloc + picloc, hud_hp_bar, picsize, '1 1 1', 1 , DRAWFLAG_NORMAL);
1250                         drawresetcliparea();
1251                 // ..  and icon
1252                         picsize = draw_getimagesize(hud_hp_ico) * autocvar_cl_vehicles_hudscale;
1253                         picloc = '37 65 0' * autocvar_cl_vehicles_hudscale;
1254                         if(vh_health < 0.25)
1255                         {
1256                                 if(alarm1time < time)
1257                                 {
1258                                         alarm1time = time + 2;
1259                                         vehicle_alarm(self, CH_PAIN_SINGLE, "vehicles/alarm.wav");
1260                                 }
1261
1262                                 drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
1263                         }
1264                         else
1265                         {
1266                                 drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
1267                                 if(alarm1time)
1268                                 {
1269                                         vehicle_alarm(self, CH_PAIN_SINGLE, "misc/null.wav");
1270                                         alarm1time = 0;
1271                                 }
1272                         }
1273
1274                 // Shield bar
1275                         picsize = draw_getimagesize(hud_sh_bar) * autocvar_cl_vehicles_hudscale;
1276                         picloc = '69 140 0' * autocvar_cl_vehicles_hudscale;
1277                         drawsetcliparea(hudloc_x + picloc_x + (picsize_x * (1 - shield)), 0, vid_conwidth, vid_conheight);
1278                         drawpic(hudloc + picloc, hud_sh_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
1279                         drawresetcliparea();
1280                 // ..  and icon
1281                         picloc = '40 136 0' * autocvar_cl_vehicles_hudscale;
1282                         picsize = draw_getimagesize(hud_sh_ico) * autocvar_cl_vehicles_hudscale;
1283                         if(shield < 0.25)
1284                         {
1285                                 if(alarm2time < time)
1286                                 {
1287                                         alarm2time = time + 1;
1288                                         vehicle_alarm(self, CH_TRIGGER_SINGLE, "vehicles/alarm_shield.wav");
1289                                 }
1290                                 drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
1291                         }
1292                         else
1293                         {
1294                                 drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
1295                                 if(alarm2time)
1296                                 {
1297                                         vehicle_alarm(self, CH_TRIGGER_SINGLE, "misc/null.wav");
1298                                         alarm2time = 0;
1299                                 }
1300                         }
1301
1302                         ammo1 *= 0.01;
1303                         ammo2 *= 0.01;
1304
1305                 // Gunner1 bar
1306                         picsize = draw_getimagesize(hud_ammo1_bar) * autocvar_cl_vehicles_hudscale;
1307                         picloc = '450 69 0' * autocvar_cl_vehicles_hudscale;
1308                         drawsetcliparea(hudloc_x + picloc_x, picloc_y, picsize_x * ammo1, vid_conheight);
1309                         drawpic(hudloc + picloc, hud_ammo1_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
1310                         drawresetcliparea();
1311
1312                 // Right gunner slot occupied?
1313                         if(!AuxiliaryXhair[1].draw2d)
1314                         {
1315                                 shield = (picsize_x * 0.5) - (0.5 * stringwidth(_("No right gunner!"), false, '1 0 0' * picsize_y + '0 1 0' * picsize_y));
1316                                 drawfill(hudloc + picloc - '0.2 0.2 0', picsize + '0.4 0.4 0', '0.25 0.25 0.25', 0.75, DRAWFLAG_NORMAL);
1317                                 drawstring(hudloc + picloc + '1 0 0' * shield, _("No right gunner!"), '1 0 0' * picsize_y + '0 1 0' * picsize_y, '1 0 0' + '0 1 1' * sin(time * 10), 1, DRAWFLAG_NORMAL);
1318                         }
1319
1320                 // ..  and icon
1321                         picsize = 1.5 * draw_getimagesize(hud_energy) * autocvar_cl_vehicles_hudscale;
1322                         picloc = '664 60 0' * autocvar_cl_vehicles_hudscale;
1323                         if(ammo1 < 0.2)
1324                                 drawpic(hudloc + picloc, hud_energy, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
1325                         else
1326                                 drawpic(hudloc + picloc, hud_energy, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
1327
1328                 // Gunner2 bar
1329                         picsize = draw_getimagesize(hud_ammo2_bar) * autocvar_cl_vehicles_hudscale;
1330                         picloc = '450 140 0' * autocvar_cl_vehicles_hudscale;
1331                         drawsetcliparea(hudloc_x + picloc_x, picloc_y, picsize_x * ammo2, vid_conheight);
1332                         drawpic(hudloc + picloc, hud_ammo2_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
1333                         drawresetcliparea();
1334                 // Left gunner slot occupied?
1335                         if(!AuxiliaryXhair[2].draw2d)
1336                         {
1337                                 shield = (picsize_x * 0.5) - (0.5 * stringwidth(_("No left gunner!"), false, '1 0 0' * picsize_y + '0 1 0' * picsize_y));
1338                                 drawfill(hudloc + picloc - '0.2 0.2 0', picsize + '0.4 0.4 0', '0.25 0.25 0.25', 0.75, DRAWFLAG_NORMAL);
1339                                 drawstring(hudloc + picloc + '1 0 0' * shield, _("No left gunner!"), '1 0 0' * picsize_y + '0 1 0' * picsize_y, '1 0 0' + '0 1 1' * sin(time * 10), 1, DRAWFLAG_NORMAL);
1340                         }
1341
1342                 // ..  and icon
1343                         picsize = 1.5 * draw_getimagesize(hud_energy) * autocvar_cl_vehicles_hudscale;
1344                         picloc = '664 130 0' * autocvar_cl_vehicles_hudscale;
1345                         if(ammo2 < 0.2)
1346                                 drawpic(hudloc + picloc, hud_energy, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
1347                         else
1348                                 drawpic(hudloc + picloc, hud_energy, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
1349
1350                         if (scoreboard_showscores)
1351                                 HUD_DrawScoreboard();
1352                         else
1353                         {
1354                                 picsize = draw_getimagesize(waki_xhair);
1355                                 picsize_x *= 0.5;
1356                                 picsize_y *= 0.5;
1357                                 drawpic('0.5 0 0' * (vid_conwidth - picsize_x) + '0 0.5 0' * (vid_conheight - picsize_y), waki_xhair, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
1358                         }
1359                         return true;
1360                 }
1361                 case VR_SETUP:
1362                 {
1363                         // raygun-locked
1364                         AuxiliaryXhair[0].axh_image   = "gfx/vehicles/axh-bracket.tga";
1365                         AuxiliaryXhair[0].axh_scale   = 0.5;
1366
1367                         // Gunner1
1368                         AuxiliaryXhair[1].axh_image   = "gfx/vehicles/axh-target.tga";
1369                         AuxiliaryXhair[1].axh_scale   = 0.75;
1370
1371                         // Gunner2
1372                         AuxiliaryXhair[2].axh_image   = "gfx/vehicles/axh-target.tga";
1373                         AuxiliaryXhair[2].axh_scale   = 0.75;
1374                         return true;
1375                 }
1376                 case VR_PRECACHE:
1377                 {
1378                         return true;
1379                 }
1380         }
1381
1382         return true;
1383 }
1384
1385 #endif // CSQC
1386 #endif // REGISTER_VEHICLE