]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/vehicles/bumblebee.qc
#include this
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / vehicles / bumblebee.qc
1 #if defined(CSQC)
2         #include "../../dpdefs/csprogsdefs.qc"
3         #include "../../client/Defs.qc"
4         #include "../../common/buffs.qh"
5         #include "../../client/damage.qh"
6         #include "../../client/movetypes.qh"
7         #include "../../client/main.qh"
8         #include "../../csqcmodellib/cl_model.qh"
9         #include "../../client/weapons/projectile.qh"
10 #elif defined(MENUQC)
11 #elif defined(SVQC)
12 #endif
13
14 const float BRG_SETUP = 2;
15 const float BRG_START = 4;
16 const float BRG_END = 8;
17
18 #ifdef SVQC
19 // Auto cvars
20 float autocvar_g_vehicle_bumblebee_speed_forward;
21 float autocvar_g_vehicle_bumblebee_speed_strafe;
22 float autocvar_g_vehicle_bumblebee_speed_up;
23 float autocvar_g_vehicle_bumblebee_speed_down;
24 float autocvar_g_vehicle_bumblebee_turnspeed;
25 float autocvar_g_vehicle_bumblebee_pitchspeed;
26 float autocvar_g_vehicle_bumblebee_pitchlimit;
27 float autocvar_g_vehicle_bumblebee_friction;
28
29 float autocvar_g_vehicle_bumblebee_energy;
30 float autocvar_g_vehicle_bumblebee_energy_regen;
31 float autocvar_g_vehicle_bumblebee_energy_regen_pause;
32
33 float autocvar_g_vehicle_bumblebee_health;
34 float autocvar_g_vehicle_bumblebee_health_regen;
35 float autocvar_g_vehicle_bumblebee_health_regen_pause;
36
37 float autocvar_g_vehicle_bumblebee_shield;
38 float autocvar_g_vehicle_bumblebee_shield_regen;
39 float autocvar_g_vehicle_bumblebee_shield_regen_pause;
40
41 float autocvar_g_vehicle_bumblebee_cannon_cost;
42 float autocvar_g_vehicle_bumblebee_cannon_damage;
43 float autocvar_g_vehicle_bumblebee_cannon_radius;
44 float autocvar_g_vehicle_bumblebee_cannon_refire;
45 float autocvar_g_vehicle_bumblebee_cannon_speed;
46 float autocvar_g_vehicle_bumblebee_cannon_spread;
47 float autocvar_g_vehicle_bumblebee_cannon_force;
48
49 float autocvar_g_vehicle_bumblebee_cannon_ammo;
50 float autocvar_g_vehicle_bumblebee_cannon_ammo_regen;
51 float autocvar_g_vehicle_bumblebee_cannon_ammo_regen_pause;
52
53 float autocvar_g_vehicle_bumblebee_cannon_lock = 0;
54
55 float autocvar_g_vehicle_bumblebee_cannon_turnspeed;
56 float autocvar_g_vehicle_bumblebee_cannon_pitchlimit_down;
57 float autocvar_g_vehicle_bumblebee_cannon_pitchlimit_up;
58 float autocvar_g_vehicle_bumblebee_cannon_turnlimit_in;
59 float autocvar_g_vehicle_bumblebee_cannon_turnlimit_out;
60
61
62 float autocvar_g_vehicle_bumblebee_raygun_turnspeed;
63 float autocvar_g_vehicle_bumblebee_raygun_pitchlimit_down;
64 float autocvar_g_vehicle_bumblebee_raygun_pitchlimit_up;
65 float autocvar_g_vehicle_bumblebee_raygun_turnlimit_sides;
66
67 float autocvar_g_vehicle_bumblebee_raygun_range;
68 float autocvar_g_vehicle_bumblebee_raygun_dps;
69 float autocvar_g_vehicle_bumblebee_raygun_aps;
70 float autocvar_g_vehicle_bumblebee_raygun_fps;
71
72 float autocvar_g_vehicle_bumblebee_raygun;
73 float autocvar_g_vehicle_bumblebee_healgun_hps;
74 float autocvar_g_vehicle_bumblebee_healgun_hmax;
75 float autocvar_g_vehicle_bumblebee_healgun_aps;
76 float autocvar_g_vehicle_bumblebee_healgun_amax;
77 float autocvar_g_vehicle_bumblebee_healgun_sps;
78 float autocvar_g_vehicle_bumblebee_healgun_locktime;
79
80 float autocvar_g_vehicle_bumblebee_respawntime;
81
82 float autocvar_g_vehicle_bumblebee_blowup_radius;
83 float autocvar_g_vehicle_bumblebee_blowup_coredamage;
84 float autocvar_g_vehicle_bumblebee_blowup_edgedamage;
85 float autocvar_g_vehicle_bumblebee_blowup_forceintensity;
86 vector autocvar_g_vehicle_bumblebee_bouncepain;
87
88 float autocvar_g_vehicle_bumblebee = 0;
89
90
91 float bumble_raygun_send(entity to, float sf);
92
93 const vector BUMB_MIN = '-130 -130 -130';
94 const vector BUMB_MAX = '130 130 130';
95
96 void bumb_fire_cannon(entity _gun, string _tagname, entity _owner)
97 {
98         vector v = gettaginfo(_gun, gettagindex(_gun, _tagname));
99         vehicles_projectile("bigplasma_muzzleflash", "weapons/flacexp3.wav",
100                                                 v, normalize(v_forward + randomvec() * autocvar_g_vehicle_bumblebee_cannon_spread) * autocvar_g_vehicle_bumblebee_cannon_speed,
101                                                 autocvar_g_vehicle_bumblebee_cannon_damage, autocvar_g_vehicle_bumblebee_cannon_radius, autocvar_g_vehicle_bumblebee_cannon_force,  0,
102                                                 DEATH_VH_BUMB_GUN, PROJECTILE_BUMBLE_GUN, 0, true, true, _owner);
103 }
104
105 float bumb_gunner_frame()
106 {
107         entity vehic    = self.vehicle.owner;
108         entity gun      = self.vehicle;
109         entity gunner   = self;
110         self = vehic;
111
112
113
114
115         vehic.solid = SOLID_NOT;
116         //setorigin(gunner, vehic.origin);
117         gunner.velocity = vehic.velocity;
118
119         float _in, _out;
120         vehic.angles_x *= -1;
121         makevectors(vehic.angles);
122         vehic.angles_x *= -1;
123         if((gun == vehic.gun1))
124         {
125                 _in = autocvar_g_vehicle_bumblebee_cannon_turnlimit_in;
126                 _out = autocvar_g_vehicle_bumblebee_cannon_turnlimit_out;
127                 setorigin(gunner, vehic.origin + v_up * -16 + v_forward * -16 + v_right * 128);
128         }
129         else
130         {
131                 _in = autocvar_g_vehicle_bumblebee_cannon_turnlimit_out;
132                 _out = autocvar_g_vehicle_bumblebee_cannon_turnlimit_in;
133                 setorigin(gunner, vehic.origin + v_up * -16 + v_forward * -16 + v_right * -128);
134         }
135
136         crosshair_trace(gunner);
137         vector _ct = trace_endpos;
138         vector ad;
139
140         if(autocvar_g_vehicle_bumblebee_cannon_lock)
141         {
142                 if(gun.lock_time < time)
143                         gun.enemy = world;
144
145                 if(trace_ent)
146                         if(trace_ent.movetype)
147                                 if(trace_ent.takedamage)
148                                         if(!trace_ent.deadflag)
149                                         {
150                                                 if(teamplay)
151                                                 {
152                                                         if(trace_ent.team != gunner.team)
153                                                         {
154                                                                 gun.enemy = trace_ent;
155                                                                 gun.lock_time = time + 5;
156                                                         }
157                                                 }
158                                                 else
159                                                 {
160                                                         gun.enemy = trace_ent;
161                                                         gun.lock_time = time + 5;
162                                                 }
163                                         }
164         }
165
166         if(gun.enemy)
167         {
168                 float i, distance, impact_time;
169
170                 vector vf = real_origin(gun.enemy);
171                 vector _vel = gun.enemy.velocity;
172                 if(gun.enemy.movetype == MOVETYPE_WALK)
173                         _vel.z *= 0.1;
174
175
176                 ad = vf;
177                 for(i = 0; i < 4; ++i)
178                 {
179                         distance = vlen(ad - gunner.origin);
180                         impact_time = distance / autocvar_g_vehicle_bumblebee_cannon_speed;
181                         ad = vf + _vel * impact_time;
182                 }
183                 trace_endpos = ad;
184
185
186                 UpdateAuxiliaryXhair(gunner, ad, '1 0 1', 1);
187                 vehicle_aimturret(vehic, trace_endpos, gun, "fire",
188                                                   autocvar_g_vehicle_bumblebee_cannon_pitchlimit_down * -1, autocvar_g_vehicle_bumblebee_cannon_pitchlimit_up,
189                                                   _out * -1,  _in,  autocvar_g_vehicle_bumblebee_cannon_turnspeed);
190
191         }
192         else
193                 vehicle_aimturret(vehic, _ct, gun, "fire",
194                                                   autocvar_g_vehicle_bumblebee_cannon_pitchlimit_down * -1, autocvar_g_vehicle_bumblebee_cannon_pitchlimit_up,
195                                                   _out * -1,  _in,  autocvar_g_vehicle_bumblebee_cannon_turnspeed);
196
197         if(gunner.BUTTON_ATCK)
198                 if(time > gun.attack_finished_single)
199                         if(gun.vehicle_energy >= autocvar_g_vehicle_bumblebee_cannon_cost)
200                         {
201                                 gun.vehicle_energy -= autocvar_g_vehicle_bumblebee_cannon_cost;
202                                 bumb_fire_cannon(gun, "fire", gunner);
203                                 gun.delay = time;
204                                 gun.attack_finished_single = time + autocvar_g_vehicle_bumblebee_cannon_refire;
205                         }
206
207         VEHICLE_UPDATE_PLAYER(gunner, health, bumblebee);
208
209         if(vehic.vehicle_flags & VHF_HASSHIELD)
210                 VEHICLE_UPDATE_PLAYER(gunner, shield, bumblebee);
211
212         ad = gettaginfo(gun, gettagindex(gun, "fire"));
213         traceline(ad, ad + v_forward * MAX_SHOT_DISTANCE, MOVE_NORMAL, gun);
214
215         UpdateAuxiliaryXhair(gunner, trace_endpos, ('1 0 0' * gunner.vehicle_reload1) + ('0 1 0' *(1 - gunner.vehicle_reload1)), 0);
216
217         if(vehic.owner)
218                 UpdateAuxiliaryXhair(vehic.owner, trace_endpos, ('1 0 0' * gunner.vehicle_reload1) + ('0 1 0' *(1 - gunner.vehicle_reload1)), ((gunner == vehic.gunner1) ? 1 : 2));
219
220         vehic.solid = SOLID_BBOX;
221         gunner.BUTTON_ATCK = gunner.BUTTON_ATCK2 = gunner.BUTTON_CROUCH = 0;
222         gunner.vehicle_energy = (gun.vehicle_energy / autocvar_g_vehicle_bumblebee_cannon_ammo) * 100;
223
224         self = gunner;
225         return 1;
226 }
227
228 void bumb_gunner_exit(float _exitflag)
229 {
230         if(IS_REAL_CLIENT(self))
231         {
232                 msg_entity = self;
233                 WriteByte(MSG_ONE, SVC_SETVIEWPORT);
234                 WriteEntity(MSG_ONE, self);
235
236                 WriteByte(MSG_ONE, SVC_SETVIEWANGLES);
237                 WriteAngle(MSG_ONE, 0);
238                 WriteAngle(MSG_ONE, self.vehicle.angles.y);
239                 WriteAngle(MSG_ONE, 0);
240         }
241
242         CSQCVehicleSetup(self, HUD_NORMAL);
243         setsize(self, PL_MIN, PL_MAX);
244
245         self.takedamage     = DAMAGE_AIM;
246         self.solid          = SOLID_SLIDEBOX;
247         self.movetype       = MOVETYPE_WALK;
248         self.effects        &= ~EF_NODRAW;
249         self.alpha          = 1;
250         self.PlayerPhysplug = func_null;
251         self.view_ofs       = PL_VIEW_OFS;
252         self.event_damage   = PlayerDamage;
253         self.hud            = HUD_NORMAL;
254         self.switchweapon   = self.vehicle.switchweapon;
255
256     vh_player = self;
257     vh_vehicle = self.vehicle;
258     MUTATOR_CALLHOOK(VehicleExit);
259     self = vh_player;
260     self.vehicle = vh_vehicle;
261
262         self.vehicle.vehicle_hudmodel.viewmodelforclient = self.vehicle;
263
264         fixedmakevectors(self.vehicle.owner.angles);
265
266         if(self == self.vehicle.owner.gunner1)
267         {
268                 self.vehicle.owner.gunner1 = world;
269         }
270         else if(self == self.vehicle.owner.gunner2)
271         {
272                 self.vehicle.owner.gunner2 = world;
273                 v_right *= -1;
274         }
275         else
276                 dprint("^1self != gunner1 or gunner2, this is a BIG PROBLEM, tell tZork this happend.\n");
277
278         vector spot = self.vehicle.owner.origin + + v_up * 128 + v_right * 300;
279         spot = vehicles_findgoodexit(spot);
280         //setorigin(self , spot);
281
282         self.velocity = 0.75 * self.vehicle.owner.velocity + normalize(spot - self.vehicle.owner.origin) * 200;
283         self.velocity_z += 10;
284
285         self.vehicle.phase = time + 5;
286         self.vehicle        = world;
287 }
288
289 float bumb_gunner_enter()
290 {
291         RemoveGrapplingHook(other);
292         entity _gun, _gunner;
293         if(!self.gunner1)
294         {
295                 _gun = self.gun1;
296                 _gunner = self.gunner1;
297                 self.gunner1 = other;
298         }
299         else if(!self.gunner2)
300         {
301                 _gun = self.gun2;
302                 _gunner = self.gunner2;
303                 self.gunner2 = other;
304         }
305         else
306         {
307                 dprint("^1ERROR:^7Tried to enter a fully occupied vehicle!\n");
308                 return false;
309         }
310
311         _gunner            = other;
312         _gunner.vehicle    = _gun;
313         _gun.switchweapon  = other.switchweapon;
314         _gun.vehicle_exit  = bumb_gunner_exit;
315
316         other.angles            = self.angles;
317         other.takedamage        = DAMAGE_NO;
318         other.solid             = SOLID_NOT;
319         other.movetype          = MOVETYPE_NOCLIP;
320         other.alpha             = -1;
321         other.event_damage      = func_null;
322         other.view_ofs          = '0 0 0';
323         other.hud               = _gun.hud;
324         other.PlayerPhysplug    = _gun.PlayerPhysplug;
325         other.vehicle_ammo1     = self.vehicle_ammo1;
326         other.vehicle_ammo2     = self.vehicle_ammo2;
327         other.vehicle_reload1   = self.vehicle_reload1;
328         other.vehicle_reload2   = self.vehicle_reload2;
329         other.vehicle_energy    = self.vehicle_energy;
330         other.PlayerPhysplug    = bumb_gunner_frame;
331         other.flags             &= ~FL_ONGROUND;
332
333         msg_entity = other;
334         WriteByte(MSG_ONE, SVC_SETVIEWPORT);
335         WriteEntity(MSG_ONE, _gun.vehicle_viewport);
336         WriteByte(MSG_ONE, SVC_SETVIEWANGLES);
337         WriteAngle(MSG_ONE, _gun.angles.x + self.angles.x);    // tilt
338         WriteAngle(MSG_ONE, _gun.angles.y + self.angles.y);    // yaw
339         WriteAngle(MSG_ONE, 0);                             // roll
340         _gun.vehicle_hudmodel.viewmodelforclient = other;
341
342         CSQCVehicleSetup(other, other.hud);
343
344     vh_player = other;
345     vh_vehicle = _gun;
346     MUTATOR_CALLHOOK(VehicleEnter);
347     other = vh_player;
348     _gun = vh_vehicle;
349
350         return true;
351 }
352
353 float vehicles_valid_pilot()
354 {
355         if (!IS_PLAYER(other))
356                 return false;
357
358         if(other.deadflag != DEAD_NO)
359                 return false;
360
361         if(other.vehicle != world)
362                 return false;
363
364         if (!IS_REAL_CLIENT(other))
365                 if(!autocvar_g_vehicles_allow_bots)
366                         return false;
367
368         if(teamplay && other.team != self.team)
369                 return false;
370
371         return true;
372 }
373
374 void bumb_touch()
375 {
376
377         if(self.gunner1 != world && self.gunner2 != world)
378         {
379                 vehicles_touch();
380                 return;
381         }
382
383         if(vehicles_valid_pilot())
384         {
385                 if(self.gun1.phase <= time)
386                         if(bumb_gunner_enter())
387                                 return;
388
389                 if(self.gun2.phase <= time)
390                         if(bumb_gunner_enter())
391                                 return;
392         }
393
394         vehicles_touch();
395 }
396
397 void bumb_regen()
398 {
399         if(self.gun1.delay + autocvar_g_vehicle_bumblebee_cannon_ammo_regen_pause < time)
400                 self.gun1.vehicle_energy = min(autocvar_g_vehicle_bumblebee_cannon_ammo,
401                                                                            self.gun1.vehicle_energy + autocvar_g_vehicle_bumblebee_cannon_ammo_regen * frametime);
402
403         if(self.gun2.delay + autocvar_g_vehicle_bumblebee_cannon_ammo_regen_pause < time)
404                 self.gun2.vehicle_energy = min(autocvar_g_vehicle_bumblebee_cannon_ammo,
405                                                                            self.gun2.vehicle_energy + autocvar_g_vehicle_bumblebee_cannon_ammo_regen * frametime);
406
407         if(self.vehicle_flags  & VHF_SHIELDREGEN)
408                 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);
409
410         if(self.vehicle_flags  & VHF_HEALTHREGEN)
411                 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);
412
413         if(self.vehicle_flags  & VHF_ENERGYREGEN)
414                 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);
415
416 }
417
418 float bumb_pilot_frame()
419 {
420         entity pilot, vehic;
421         vector newvel;
422
423         pilot = self;
424         vehic = self.vehicle;
425         self   = vehic;
426
427
428         if(vehic.deadflag != DEAD_NO)
429         {
430                 self = pilot;
431                 pilot.BUTTON_ATCK = pilot.BUTTON_ATCK2 = 0;
432                 return 1;
433         }
434
435         bumb_regen();
436
437         crosshair_trace(pilot);
438
439         vector vang;
440         float ftmp;
441
442         vang = vehic.angles;
443         newvel = vectoangles(normalize(trace_endpos - self.origin + '0 0 32'));
444         vang.x *= -1;
445         newvel.x *= -1;
446         if(newvel.x > 180)  newvel.x -= 360;
447         if(newvel.x < -180) newvel.x += 360;
448         if(newvel.y > 180)  newvel.y -= 360;
449         if(newvel.y < -180) newvel.y += 360;
450
451         ftmp = shortangle_f(pilot.v_angle.y - vang.y, vang.y);
452         if(ftmp > 180)  ftmp -= 360;
453         if(ftmp < -180) ftmp += 360;
454         vehic.avelocity_y = bound(-autocvar_g_vehicle_bumblebee_turnspeed, ftmp + vehic.avelocity.y * 0.9, autocvar_g_vehicle_bumblebee_turnspeed);
455
456         // Pitch
457         ftmp = 0;
458         if(pilot.movement.x > 0 && vang.x < autocvar_g_vehicle_bumblebee_pitchlimit)
459                 ftmp = 4;
460         else if(pilot.movement.x < 0 && vang.x > -autocvar_g_vehicle_bumblebee_pitchlimit)
461                 ftmp = -8;
462
463         newvel_x = bound(-autocvar_g_vehicle_bumblebee_pitchlimit, newvel.x , autocvar_g_vehicle_bumblebee_pitchlimit);
464         ftmp = vang.x - bound(-autocvar_g_vehicle_bumblebee_pitchlimit, newvel.x + ftmp, autocvar_g_vehicle_bumblebee_pitchlimit);
465         vehic.avelocity_x = bound(-autocvar_g_vehicle_bumblebee_pitchspeed, ftmp + vehic.avelocity.x * 0.9, autocvar_g_vehicle_bumblebee_pitchspeed);
466
467         vehic.angles_x = anglemods(vehic.angles.x);
468         vehic.angles_y = anglemods(vehic.angles.y);
469         vehic.angles_z = anglemods(vehic.angles.z);
470
471         makevectors('0 1 0' * vehic.angles.y);
472         newvel = vehic.velocity * -autocvar_g_vehicle_bumblebee_friction;
473
474         if(pilot.movement.x != 0)
475         {
476                 if(pilot.movement.x > 0)
477                         newvel += v_forward  * autocvar_g_vehicle_bumblebee_speed_forward;
478                 else if(pilot.movement.x < 0)
479                         newvel -= v_forward  * autocvar_g_vehicle_bumblebee_speed_forward;
480         }
481
482         if(pilot.movement.y != 0)
483         {
484                 if(pilot.movement.y < 0)
485                         newvel -= v_right * autocvar_g_vehicle_bumblebee_speed_strafe;
486                 else if(pilot.movement.y > 0)
487                         newvel += v_right * autocvar_g_vehicle_bumblebee_speed_strafe;
488                 ftmp = newvel * v_right;
489                 ftmp *= frametime * 0.1;
490                 vehic.angles_z = bound(-15, vehic.angles.z + ftmp, 15);
491         }
492         else
493         {
494                 vehic.angles_z *= 0.95;
495                 if(vehic.angles.z >= -1 && vehic.angles.z <= -1)
496                         vehic.angles_z = 0;
497         }
498
499         if(pilot.BUTTON_CROUCH)
500                 newvel -=   v_up * autocvar_g_vehicle_bumblebee_speed_down;
501         else if(pilot.BUTTON_JUMP)
502                 newvel +=  v_up * autocvar_g_vehicle_bumblebee_speed_up;
503
504         vehic.velocity  += newvel * frametime;
505         pilot.velocity = pilot.movement  = vehic.velocity;
506
507
508         if(autocvar_g_vehicle_bumblebee_healgun_locktime)
509         {
510                 if(vehic.tur_head.lock_time < time || vehic.tur_head.enemy.deadflag)
511                         vehic.tur_head.enemy = world;
512
513                 if(trace_ent)
514                 if(trace_ent.movetype)
515                 if(trace_ent.takedamage)
516                 if(!trace_ent.deadflag)
517                 {
518                         if(teamplay)
519                         {
520                                 if(trace_ent.team == pilot.team)
521                                 {
522                                         vehic.tur_head.enemy = trace_ent;
523                                         vehic.tur_head.lock_time = time + autocvar_g_vehicle_bumblebee_healgun_locktime;
524                                 }
525                         }
526                         else
527                         {
528                                 vehic.tur_head.enemy = trace_ent;
529                                 vehic.tur_head.lock_time = time + autocvar_g_vehicle_bumblebee_healgun_locktime;
530                         }
531                 }
532
533                 if(vehic.tur_head.enemy)
534                 {
535                         trace_endpos = real_origin(vehic.tur_head.enemy);
536                         UpdateAuxiliaryXhair(pilot, trace_endpos, '0 0.75 0', 0);
537                 }
538         }
539
540         vang = vehicle_aimturret(vehic, trace_endpos, self.gun3, "fire",
541                                           autocvar_g_vehicle_bumblebee_raygun_pitchlimit_down * -1,  autocvar_g_vehicle_bumblebee_raygun_pitchlimit_up,
542                                           autocvar_g_vehicle_bumblebee_raygun_turnlimit_sides * -1,  autocvar_g_vehicle_bumblebee_raygun_turnlimit_sides,  autocvar_g_vehicle_bumblebee_raygun_turnspeed);
543
544         if((pilot.BUTTON_ATCK || pilot.BUTTON_ATCK2) && (vehic.vehicle_energy > autocvar_g_vehicle_bumblebee_raygun_dps * sys_frametime || autocvar_g_vehicle_bumblebee_raygun == 0))
545         {
546                 vehic.gun3.enemy.realowner = pilot;
547                 vehic.gun3.enemy.effects &= ~EF_NODRAW;
548
549                 vehic.gun3.enemy.hook_start = gettaginfo(vehic.gun3, gettagindex(vehic.gun3, "fire"));
550                 vehic.gun3.enemy.SendFlags |= BRG_START;
551
552                 traceline(vehic.gun3.enemy.hook_start, vehic.gun3.enemy.hook_start + v_forward * autocvar_g_vehicle_bumblebee_raygun_range, MOVE_NORMAL, vehic);
553
554                 if(trace_ent)
555                 {
556                         if(autocvar_g_vehicle_bumblebee_raygun)
557                         {
558                                 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);
559                                 vehic.vehicle_energy -= autocvar_g_vehicle_bumblebee_raygun_aps * sys_frametime;
560                         }
561                         else
562                         {
563                                 if(trace_ent.deadflag == DEAD_NO)
564                                         if((teamplay && trace_ent.team == pilot.team) || !teamplay)
565                                         {
566
567                                                 if(trace_ent.vehicle_flags & VHF_ISVEHICLE)
568                                                 {
569                                                         if(autocvar_g_vehicle_bumblebee_healgun_sps && trace_ent.vehicle_health <= trace_ent.tur_health)
570                                                                 trace_ent.vehicle_shield = min(trace_ent.vehicle_shield + autocvar_g_vehicle_bumblebee_healgun_sps * frametime, trace_ent.tur_head.tur_health);
571
572                                                         if(autocvar_g_vehicle_bumblebee_healgun_hps)
573                                                                 trace_ent.vehicle_health = min(trace_ent.vehicle_health + autocvar_g_vehicle_bumblebee_healgun_hps * frametime, trace_ent.tur_health);
574                                                 }
575                                                 else if(IS_CLIENT(trace_ent))
576                                                 {
577                                                         if(trace_ent.health <= autocvar_g_vehicle_bumblebee_healgun_hmax && autocvar_g_vehicle_bumblebee_healgun_hps)
578                                                                 trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * frametime, autocvar_g_vehicle_bumblebee_healgun_hmax);
579
580                                                         if(trace_ent.armorvalue <= autocvar_g_vehicle_bumblebee_healgun_amax && autocvar_g_vehicle_bumblebee_healgun_aps)
581                                                                 trace_ent.armorvalue = min(trace_ent.armorvalue + autocvar_g_vehicle_bumblebee_healgun_aps * frametime, autocvar_g_vehicle_bumblebee_healgun_amax);
582
583                                                         trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * frametime, autocvar_g_vehicle_bumblebee_healgun_hmax);
584                                                 }
585                                                 else if(trace_ent.turrcaps_flags & TFL_TURRCAPS_ISTURRET)
586                                                 {
587                                                         if(trace_ent.health  <= trace_ent.tur_health && autocvar_g_vehicle_bumblebee_healgun_hps)
588                                                                 trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * frametime, trace_ent.tur_health);
589                                                         //else ..hmmm what? ammo?
590
591                                                         trace_ent.SendFlags |= TNSF_STATUS;
592                                                 }
593                                         }
594                         }
595                 }
596
597                 vehic.gun3.enemy.hook_end = trace_endpos;
598                 setorigin(vehic.gun3.enemy, trace_endpos);
599                 vehic.gun3.enemy.SendFlags |= BRG_END;
600
601                 vehic.wait = time + 1;
602         }
603         else
604                 vehic.gun3.enemy.effects |= EF_NODRAW;
605         /*{
606                 if(vehic.gun3.enemy)
607                         remove(vehic.gun3.enemy);
608
609                 vehic.gun3.enemy = world;
610         }
611         */
612
613         VEHICLE_UPDATE_PLAYER(pilot, health, bumblebee);
614         VEHICLE_UPDATE_PLAYER(pilot, energy, bumblebee);
615
616         pilot.vehicle_ammo1 = (vehic.gun1.vehicle_energy / autocvar_g_vehicle_bumblebee_cannon_ammo) * 100;
617         pilot.vehicle_ammo2 = (vehic.gun2.vehicle_energy / autocvar_g_vehicle_bumblebee_cannon_ammo) * 100;
618
619         if(vehic.vehicle_flags & VHF_HASSHIELD)
620                 VEHICLE_UPDATE_PLAYER(pilot, shield, bumblebee);
621
622         vehic.angles_x *= -1;
623         makevectors(vehic.angles);
624         vehic.angles_x *= -1;
625         setorigin(pilot, vehic.origin + v_up * 48 + v_forward * 160);
626
627         pilot.BUTTON_ATCK = pilot.BUTTON_ATCK2 = pilot.BUTTON_CROUCH = 0;
628         self = pilot;
629
630         return 1;
631 }
632
633 void bumb_think()
634 {
635         self.movetype = MOVETYPE_TOSS;
636
637                 //self.velocity = self.velocity * 0.5;
638         self.angles_z *= 0.8;
639         self.angles_x *= 0.8;
640
641         self.nextthink = time + 0.05;
642
643         if(!self.owner)
644         {
645                 entity oldself = self;
646                 if(self.gunner1)
647                 {
648                         self = self.gunner1;
649                         oldself.gun1.vehicle_exit(VHEF_EJECT);
650                         entity oldother = other;
651                         other = self;
652                         self = oldself;
653                         self.phase = 0;
654                         self.touch();
655                         other = oldother;
656                         return;
657                 }
658
659                 if(self.gunner2)
660                 {
661                         self = self.gunner2;
662                         oldself.gun2.vehicle_exit(VHEF_EJECT);
663                         entity oldother = other;
664                         other = self;
665                         self = oldself;
666                         self.phase = 0;
667                         self.touch();
668                         other = oldother;
669                         return;
670                 }
671         }
672
673 }
674
675 void bumb_enter()
676 {
677         self.touch = bumb_touch;
678         self.nextthink = 0;
679         self.movetype = MOVETYPE_BOUNCEMISSILE;
680         //setattachment(self.owner, self.vehicle_viewport, "");
681 }
682
683 void bumb_exit(float eject)
684 {
685         self.touch = vehicles_touch;
686         self.think = bumb_think;
687         self.nextthink = time;
688
689         if(!self.owner)
690                 return;
691
692         fixedmakevectors(self.angles);
693         vector spot;
694         if(vlen(self.velocity) > autocvar_g_vehicle_bumblebee_speed_forward * 0.5)
695                 spot = self.origin + v_up * 128 + v_forward * 200;
696         else
697                 spot = self.origin + v_up * 128 - v_forward * 200;
698
699         spot = vehicles_findgoodexit(spot);
700
701         // Hide beam
702         if(self.gun3.enemy || !wasfreed(self.gun3.enemy)) {
703                 self.gun3.enemy.effects |= EF_NODRAW;
704     }
705
706         self.owner.velocity = 0.75 * self.vehicle.velocity + normalize(spot - self.vehicle.origin) * 200;
707         self.owner.velocity_z += 10;
708         setorigin(self.owner, spot);
709
710         antilag_clear(self.owner);
711     self.owner = world;
712 }
713
714 void bumb_blowup()
715 {
716         RadiusDamage(self, self.enemy, autocvar_g_vehicle_bumblebee_blowup_coredamage,
717                                  autocvar_g_vehicle_bumblebee_blowup_edgedamage,
718                                  autocvar_g_vehicle_bumblebee_blowup_radius, self, world,
719                                  autocvar_g_vehicle_bumblebee_blowup_forceintensity,
720                                  DEATH_VH_BUMB_DEATH, world);
721
722         sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM);
723         pointparticles(particleeffectnum("explosion_large"), randomvec() * 80 + (self.origin + '0 0 100'), '0 0 0', 1);
724
725         if(self.owner.deadflag == DEAD_DYING)
726                 self.owner.deadflag = DEAD_DEAD;
727
728         remove(self);
729 }
730
731 void bumb_diethink()
732 {
733         if(time >= self.wait)
734                 self.think = bumb_blowup;
735
736         if(random() < 0.1)
737         {
738                 sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM);
739                 pointparticles(particleeffectnum("explosion_small"), randomvec() * 80 + (self.origin + '0 0 100'), '0 0 0', 1);
740         }
741
742         self.nextthink = time + 0.1;
743 }
744
745 void bumb_die()
746 {
747         entity oldself = self;
748
749         // Hide beam
750         if(self.gun3.enemy || !wasfreed(self.gun3.enemy))
751                 self.gun3.enemy.effects |= EF_NODRAW;
752
753         if(self.gunner1)
754         {
755                 self = self.gunner1;
756                 oldself.gun1.vehicle_exit(VHEF_EJECT);
757                 self = oldself;
758         }
759
760         if(self.gunner2)
761         {
762                 self = self.gunner2;
763                 oldself.gun2.vehicle_exit(VHEF_EJECT);
764                 self = oldself;
765         }
766
767         self.vehicle_exit(VHEF_EJECT);
768
769         fixedmakevectors(self.angles);
770         vehicle_tossgib(self.gun1, self.velocity + v_right * 300 + v_up * 100 + randomvec() * 200, "cannon_right", rint(random()), rint(random()), 6, randomvec() * 200);
771         vehicle_tossgib(self.gun2, self.velocity + v_right * -300 + v_up * 100 + randomvec() * 200, "cannon_left", rint(random()), rint(random()), 6, randomvec() * 200);
772         vehicle_tossgib(self.gun3, self.velocity + v_forward * 300 + v_up * -100 + randomvec() * 200, "raygun", rint(random()), rint(random()), 6, randomvec() * 300);
773
774         entity _body = vehicle_tossgib(self, self.velocity + randomvec() * 200, "", rint(random()), rint(random()), 6, randomvec() * 100);
775
776         if(random() > 0.5)
777                 _body.touch = bumb_blowup;
778         else
779                 _body.touch = func_null;
780
781         _body.think = bumb_diethink;
782         _body.nextthink = time;
783         _body.wait = time + 2 + (random() * 8);
784         _body.owner = self;
785         _body.enemy = self.enemy;
786
787         pointparticles(particleeffectnum("explosion_medium"), findbetterlocation(self.origin, 16), '0 0 0', 1);
788
789         self.health                     = 0;
790         self.event_damage       = func_null;
791         self.solid                      = SOLID_CORPSE;
792         self.takedamage         = DAMAGE_NO;
793         self.deadflag           = DEAD_DYING;
794         self.movetype           = MOVETYPE_NONE;
795         self.effects            = EF_NODRAW;
796         self.colormod           = '0 0 0';
797         self.avelocity          = '0 0 0';
798         self.velocity           = '0 0 0';
799         self.touch                      = func_null;
800         self.nextthink          = 0;
801
802         setorigin(self, self.pos1);
803 }
804
805 void bumb_impact()
806 {
807         if(autocvar_g_vehicle_bumblebee_bouncepain.x)
808                 vehicles_impact(autocvar_g_vehicle_bumblebee_bouncepain.x, autocvar_g_vehicle_bumblebee_bouncepain.y, autocvar_g_vehicle_bumblebee_bouncepain.z);
809 }
810
811 void bumb_spawn(float _f)
812 {
813         /*
814         float i;
815         for(i=1; gettaginfo(self.gun1, i), gettaginfo_name; ++i)
816         {
817
818             dprint(" ------- ^1gettaginfo_name^2(",ftos(i),") ^3=", gettaginfo_name, "\n");
819         }
820         */
821         if(!self.gun1)
822         {
823                 // for some reason, autosizing of the shiled entity refuses to work for this one so set it up in advance.
824                 self.vehicle_shieldent = spawn();
825                 self.vehicle_shieldent.effects = EF_LOWPRECISION;
826                 setmodel(self.vehicle_shieldent, "models/vhshield.md3");
827                 setattachment(self.vehicle_shieldent, self, "");
828                 setorigin(self.vehicle_shieldent, real_origin(self) - self.origin);
829                 self.vehicle_shieldent.scale       = 512 / vlen(self.maxs - self.mins);
830                 self.vehicle_shieldent.think       = shieldhit_think;
831                 self.vehicle_shieldent.alpha = -1;
832                 self.vehicle_shieldent.effects = EF_LOWPRECISION | EF_NODRAW;
833
834                 self.gun1 = spawn();
835                 self.gun2 = spawn();
836                 self.gun3 = spawn();
837
838                 self.vehicle_flags |= VHF_MULTISLOT;
839
840                 self.gun1.owner = self;
841                 self.gun2.owner = self;
842                 self.gun3.owner = self;
843
844                 setmodel(self.gun1, "models/vehicles/bumblebee_plasma_right.dpm");
845                 setmodel(self.gun2, "models/vehicles/bumblebee_plasma_left.dpm");
846                 setmodel(self.gun3, "models/vehicles/bumblebee_ray.dpm");
847
848                 setattachment(self.gun1, self, "cannon_right");
849                 setattachment(self.gun2, self, "cannon_left");
850
851                 // Angled bones are no fun, messes up gun-aim; so work arround it.
852                 self.gun3.pos1 = self.angles;
853                 self.angles = '0 0 0';
854                 vector ofs = gettaginfo(self, gettagindex(self, "raygun"));
855                 ofs -= self.origin;
856                 setattachment(self.gun3, self, "");
857                 setorigin(self.gun3, ofs);
858                 self.angles = self.gun3.pos1;
859
860                 vehicle_addplayerslot(self, self.gun1, HUD_BUMBLEBEE_GUN, "models/vehicles/wakizashi_cockpit.dpm", bumb_gunner_frame, bumb_gunner_exit);
861                 vehicle_addplayerslot(self, self.gun2, HUD_BUMBLEBEE_GUN, "models/vehicles/wakizashi_cockpit.dpm", bumb_gunner_frame, bumb_gunner_exit);
862
863                 setorigin(self.vehicle_hudmodel, '50 0 -5');    // Move cockpit forward - down.
864                 setorigin(self.vehicle_viewport, '5 0 2');    // Move camera forward up
865
866                 //fixme-model-bones
867                 setorigin(self.gun1.vehicle_hudmodel, '90 -27 -23');
868                 setorigin(self.gun1.vehicle_viewport, '-85 0 50');
869                 //fixme-model-bones
870                 setorigin(self.gun2.vehicle_hudmodel, '90 27 -23');
871                 setorigin(self.gun2.vehicle_viewport, '-85 0 50');
872
873                 self.scale = 1.5;
874
875                 // Raygun beam
876                 if(self.gun3.enemy == world)
877                 {
878                         self.gun3.enemy = spawn();
879                         Net_LinkEntity(self.gun3.enemy, true, 0, bumble_raygun_send);
880                         self.gun3.enemy.SendFlags = BRG_SETUP;
881                         self.gun3.enemy.cnt = autocvar_g_vehicle_bumblebee_raygun;
882                         self.gun3.enemy.effects = EF_NODRAW | EF_LOWPRECISION;
883                 }
884         }
885
886         self.vehicle_health = autocvar_g_vehicle_bumblebee_health;
887         self.vehicle_shield = autocvar_g_vehicle_bumblebee_shield;
888         self.solid          = SOLID_BBOX;
889         //self.movetype         = MOVETYPE_BOUNCEMISSILE;
890         self.movetype           = MOVETYPE_TOSS;
891         self.vehicle_impact = bumb_impact;
892         self.damageforcescale = 0.025;
893
894         setorigin(self, self.origin + '0 0 25');
895 }
896
897 void spawnfunc_vehicle_bumblebee()
898 {
899         if(!autocvar_g_vehicle_bumblebee)
900         {
901                 remove(self);
902                 return;
903         }
904
905         precache_model("models/vehicles/bumblebee_body.dpm");
906         precache_model("models/vehicles/bumblebee_plasma_left.dpm");
907         precache_model("models/vehicles/bumblebee_plasma_right.dpm");
908         precache_model("models/vehicles/bumblebee_ray.dpm");
909         precache_model("models/vehicles/wakizashi_cockpit.dpm");
910         precache_model("models/vehicles/spiderbot_cockpit.dpm");
911         precache_model("models/vehicles/raptor_cockpit.dpm");
912
913         if(autocvar_g_vehicle_bumblebee_energy)
914                 if(autocvar_g_vehicle_bumblebee_energy_regen)
915                         self.vehicle_flags |= VHF_ENERGYREGEN;
916
917         if(autocvar_g_vehicle_bumblebee_shield)
918                 self.vehicle_flags |= VHF_HASSHIELD;
919
920         if(autocvar_g_vehicle_bumblebee_shield_regen)
921                 self.vehicle_flags |= VHF_SHIELDREGEN;
922
923         if(autocvar_g_vehicle_bumblebee_health_regen)
924                 self.vehicle_flags |= VHF_HEALTHREGEN;
925
926         if(!vehicle_initialize(
927                            "Bumblebee", "models/vehicles/bumblebee_body.dpm",
928                            "", "models/vehicles/spiderbot_cockpit.dpm", "", "", "tag_viewport",
929                            HUD_BUMBLEBEE, BUMB_MIN, BUMB_MAX, false,
930                            bumb_spawn, autocvar_g_vehicle_bumblebee_respawntime,
931                            bumb_pilot_frame, bumb_enter, bumb_exit,
932                            bumb_die, bumb_think, false, autocvar_g_vehicle_bumblebee_health, autocvar_g_vehicle_bumblebee_shield))
933         {
934                 remove(self);
935                 return;
936         }
937 }
938
939 float bumble_raygun_send(entity to, float sf)
940 {
941         WriteByte(MSG_ENTITY, ENT_CLIENT_BUMBLE_RAYGUN);
942
943         WriteByte(MSG_ENTITY, sf);
944         if(sf & BRG_SETUP)
945         {
946                 WriteByte(MSG_ENTITY, num_for_edict(self.realowner));
947                 WriteByte(MSG_ENTITY, self.realowner.team);
948                 WriteByte(MSG_ENTITY, self.cnt);
949         }
950
951         if(sf & BRG_START)
952         {
953                 WriteCoord(MSG_ENTITY, self.hook_start.x);
954                 WriteCoord(MSG_ENTITY, self.hook_start.y);
955                 WriteCoord(MSG_ENTITY, self.hook_start.z);
956         }
957
958         if(sf & BRG_END)
959         {
960                 WriteCoord(MSG_ENTITY, self.hook_end.x);
961                 WriteCoord(MSG_ENTITY, self.hook_end.y);
962                 WriteCoord(MSG_ENTITY, self.hook_end.z);
963         }
964
965         return true;
966 }
967 #endif // SVQC
968
969 #ifdef CSQC
970 /*
971 .vector raygun_l1
972 .vector raygun_l2;
973 .vector raygun_l3;
974 */
975
976 void bumble_raygun_draw()
977 {
978         float _len;
979         vector _dir;
980         vector _vtmp1, _vtmp2;
981
982         _len = vlen(self.origin - self.move_origin);
983         _dir = normalize(self.move_origin - self.origin);
984
985         if(self.total_damages < time)
986         {
987                 boxparticles(self.traileffect, self, self.origin, self.origin + _dir * -64, _dir * -_len , _dir * -_len, 1, PARTICLES_USEALPHA);
988                 boxparticles(self.lip, self, self.move_origin, self.move_origin + _dir * -64, _dir * -200 , _dir * -200, 1, PARTICLES_USEALPHA);
989                 self.total_damages = time + 0.1;
990         }
991
992         float i, df, sz, al;
993         for(i = -0.1; i < 0.2; i += 0.1)
994         {
995                 df = DRAWFLAG_NORMAL; //((random() < 0.5) ? DRAWFLAG_ADDITIVE : DRAWFLAG_SCREEN);
996                 sz = 5 + random() * 5;
997                 al = 0.25 + random() * 0.5;
998                 _vtmp1 = self.origin + _dir * _len * (0.25 + i);
999                 _vtmp1 += (randomvec() * (_len * 0.2) * (frametime * 2));       //self.raygun_l1;
1000                 Draw_CylindricLine(self.origin, _vtmp1, sz, "gfx/colors/white.tga", 1, 1, self.colormod, al, df, view_origin);
1001
1002                 _vtmp2 = self.origin + _dir * _len * (0.5 + i);
1003                 _vtmp2 += (randomvec() * (_len * 0.2) * (frametime * 5));       //self.raygun_l2;
1004                 Draw_CylindricLine(_vtmp1, _vtmp2, sz, "gfx/colors/white.tga", 1, 1, self.colormod, al, df, view_origin);
1005
1006                 _vtmp1 = self.origin + _dir * _len * (0.75 + i);
1007                 _vtmp1 += randomvec() * (_len * 0.2) * (frametime * 10);     //self.raygun_l3;
1008                 Draw_CylindricLine(_vtmp2, _vtmp1, sz, "gfx/colors/white.tga", 1, 1, self.colormod, al, df, view_origin);
1009
1010                 Draw_CylindricLine(_vtmp1, self.move_origin +  randomvec() * 32, sz, "gfx/colors/white.tga", 1, 1, self.colormod, al, df, view_origin);
1011         }
1012 }
1013
1014 void bumble_raygun_read(float bIsNew)
1015 {
1016         int sf = ReadByte();
1017
1018         if(sf & BRG_SETUP)
1019         {
1020                 self.cnt  = ReadByte();
1021                 self.team = ReadByte();
1022                 self.cnt  = ReadByte();
1023
1024                 if(self.cnt)
1025                         self.colormod = '1 0 0';
1026                 else
1027                         self.colormod = '0 1 0';
1028
1029                 self.traileffect = particleeffectnum("healray_muzzleflash");
1030                 self.lip = particleeffectnum("healray_impact");
1031
1032                 self.draw = bumble_raygun_draw;
1033         }
1034
1035
1036         if(sf & BRG_START)
1037         {
1038                 self.origin_x = ReadCoord();
1039                 self.origin_y = ReadCoord();
1040                 self.origin_z = ReadCoord();
1041                 setorigin(self, self.origin);
1042         }
1043
1044         if(sf & BRG_END)
1045         {
1046                 self.move_origin_x = ReadCoord();
1047                 self.move_origin_y = ReadCoord();
1048                 self.move_origin_z = ReadCoord();
1049         }
1050 }
1051
1052 void bumblebee_draw()
1053 {
1054
1055 }
1056
1057 void bumblebee_draw2d()
1058 {
1059
1060 }
1061
1062 void bumblebee_read_extra()
1063 {
1064
1065 }
1066
1067 void vehicle_bumblebee_assemble()
1068 {
1069
1070 }
1071 #endif //CSQC