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