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