]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/vehicles/bumblebee.qc
Make most server includes order insensitive
[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 .vector hook_start, hook_end;
327 float bumb_pilot_frame()
328 {
329         entity pilot, vehic;
330         vector newvel;
331
332         pilot = self;
333         vehic = self.vehicle;
334         self   = vehic;
335
336
337         if(vehic.deadflag != DEAD_NO)
338         {
339                 self = pilot;
340                 pilot.BUTTON_ATCK = pilot.BUTTON_ATCK2 = 0;
341                 return 1;
342         }
343
344         bumb_regen();
345
346         crosshair_trace(pilot);
347
348         vector vang;
349         float ftmp;
350
351         vang = vehic.angles;
352         newvel = vectoangles(normalize(trace_endpos - self.origin + '0 0 32'));
353         vang.x *= -1;
354         newvel.x *= -1;
355         if(newvel.x > 180)  newvel.x -= 360;
356         if(newvel.x < -180) newvel.x += 360;
357         if(newvel.y > 180)  newvel.y -= 360;
358         if(newvel.y < -180) newvel.y += 360;
359
360         ftmp = shortangle_f(pilot.v_angle.y - vang.y, vang.y);
361         if(ftmp > 180)  ftmp -= 360;
362         if(ftmp < -180) ftmp += 360;
363         vehic.avelocity_y = bound(-autocvar_g_vehicle_bumblebee_turnspeed, ftmp + vehic.avelocity.y * 0.9, autocvar_g_vehicle_bumblebee_turnspeed);
364
365         // Pitch
366         ftmp = 0;
367         if(pilot.movement.x > 0 && vang.x < autocvar_g_vehicle_bumblebee_pitchlimit)
368                 ftmp = 4;
369         else if(pilot.movement.x < 0 && vang.x > -autocvar_g_vehicle_bumblebee_pitchlimit)
370                 ftmp = -8;
371
372         newvel.x = bound(-autocvar_g_vehicle_bumblebee_pitchlimit, newvel.x , autocvar_g_vehicle_bumblebee_pitchlimit);
373         ftmp = vang.x - bound(-autocvar_g_vehicle_bumblebee_pitchlimit, newvel.x + ftmp, autocvar_g_vehicle_bumblebee_pitchlimit);
374         vehic.avelocity_x = bound(-autocvar_g_vehicle_bumblebee_pitchspeed, ftmp + vehic.avelocity.x * 0.9, autocvar_g_vehicle_bumblebee_pitchspeed);
375
376         vehic.angles_x = anglemods(vehic.angles.x);
377         vehic.angles_y = anglemods(vehic.angles.y);
378         vehic.angles_z = anglemods(vehic.angles.z);
379
380         makevectors('0 1 0' * vehic.angles.y);
381         newvel = vehic.velocity * -autocvar_g_vehicle_bumblebee_friction;
382
383         if(pilot.movement.x != 0)
384         {
385                 if(pilot.movement.x > 0)
386                         newvel += v_forward  * autocvar_g_vehicle_bumblebee_speed_forward;
387                 else if(pilot.movement.x < 0)
388                         newvel -= v_forward  * autocvar_g_vehicle_bumblebee_speed_forward;
389         }
390
391         if(pilot.movement.y != 0)
392         {
393                 if(pilot.movement.y < 0)
394                         newvel -= v_right * autocvar_g_vehicle_bumblebee_speed_strafe;
395                 else if(pilot.movement.y > 0)
396                         newvel += v_right * autocvar_g_vehicle_bumblebee_speed_strafe;
397                 ftmp = newvel * v_right;
398                 ftmp *= frametime * 0.1;
399                 vehic.angles_z = bound(-15, vehic.angles.z + ftmp, 15);
400         }
401         else
402         {
403                 vehic.angles_z *= 0.95;
404                 if(vehic.angles.z >= -1 && vehic.angles.z <= -1)
405                         vehic.angles_z = 0;
406         }
407
408         if(pilot.BUTTON_CROUCH)
409                 newvel -=   v_up * autocvar_g_vehicle_bumblebee_speed_down;
410         else if(pilot.BUTTON_JUMP)
411                 newvel +=  v_up * autocvar_g_vehicle_bumblebee_speed_up;
412
413         vehic.velocity  += newvel * frametime;
414         pilot.velocity = pilot.movement  = vehic.velocity;
415
416
417         if(autocvar_g_vehicle_bumblebee_healgun_locktime)
418         {
419                 if(vehic.tur_head.lock_time < time || vehic.tur_head.enemy.deadflag)
420                         vehic.tur_head.enemy = world;
421
422                 if(trace_ent)
423                 if(trace_ent.movetype)
424                 if(trace_ent.takedamage)
425                 if(!trace_ent.deadflag)
426                 {
427                         if(teamplay)
428                         {
429                                 if(trace_ent.team == pilot.team)
430                                 {
431                                         vehic.tur_head.enemy = trace_ent;
432                                         vehic.tur_head.lock_time = time + autocvar_g_vehicle_bumblebee_healgun_locktime;
433                                 }
434                         }
435                         else
436                         {
437                                 vehic.tur_head.enemy = trace_ent;
438                                 vehic.tur_head.lock_time = time + autocvar_g_vehicle_bumblebee_healgun_locktime;
439                         }
440                 }
441
442                 if(vehic.tur_head.enemy)
443                 {
444                         trace_endpos = real_origin(vehic.tur_head.enemy);
445                         UpdateAuxiliaryXhair(pilot, trace_endpos, '0 0.75 0', 0);
446                 }
447         }
448
449         vang = vehicle_aimturret(vehic, trace_endpos, self.gun3, "fire",
450                                           autocvar_g_vehicle_bumblebee_raygun_pitchlimit_down * -1,  autocvar_g_vehicle_bumblebee_raygun_pitchlimit_up,
451                                           autocvar_g_vehicle_bumblebee_raygun_turnlimit_sides * -1,  autocvar_g_vehicle_bumblebee_raygun_turnlimit_sides,  autocvar_g_vehicle_bumblebee_raygun_turnspeed);
452
453         if((pilot.BUTTON_ATCK || pilot.BUTTON_ATCK2) && (vehic.vehicle_energy > autocvar_g_vehicle_bumblebee_raygun_dps * sys_frametime || autocvar_g_vehicle_bumblebee_raygun == 0))
454         {
455                 vehic.gun3.enemy.realowner = pilot;
456                 vehic.gun3.enemy.effects &= ~EF_NODRAW;
457
458                 vehic.gun3.enemy.hook_start = gettaginfo(vehic.gun3, gettagindex(vehic.gun3, "fire"));
459                 vehic.gun3.enemy.SendFlags |= BRG_START;
460
461                 traceline(vehic.gun3.enemy.hook_start, vehic.gun3.enemy.hook_start + v_forward * autocvar_g_vehicle_bumblebee_raygun_range, MOVE_NORMAL, vehic);
462
463                 if(trace_ent)
464                 {
465                         if(autocvar_g_vehicle_bumblebee_raygun)
466                         {
467                                 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);
468                                 vehic.vehicle_energy -= autocvar_g_vehicle_bumblebee_raygun_aps * sys_frametime;
469                         }
470                         else
471                         {
472                                 if(trace_ent.deadflag == DEAD_NO)
473                                         if((teamplay && trace_ent.team == pilot.team) || !teamplay)
474                                         {
475
476                                                 if(trace_ent.vehicle_flags & VHF_ISVEHICLE)
477                                                 {
478                                                         if(autocvar_g_vehicle_bumblebee_healgun_sps && trace_ent.vehicle_health <= trace_ent.tur_health)
479                                                                 trace_ent.vehicle_shield = min(trace_ent.vehicle_shield + autocvar_g_vehicle_bumblebee_healgun_sps * frametime, trace_ent.tur_head.tur_health);
480
481                                                         if(autocvar_g_vehicle_bumblebee_healgun_hps)
482                                                                 trace_ent.vehicle_health = min(trace_ent.vehicle_health + autocvar_g_vehicle_bumblebee_healgun_hps * frametime, trace_ent.tur_health);
483                                                 }
484                                                 else if(IS_CLIENT(trace_ent))
485                                                 {
486                                                         if(trace_ent.health <= autocvar_g_vehicle_bumblebee_healgun_hmax && autocvar_g_vehicle_bumblebee_healgun_hps)
487                                                                 trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * frametime, autocvar_g_vehicle_bumblebee_healgun_hmax);
488
489                                                         if(trace_ent.armorvalue <= autocvar_g_vehicle_bumblebee_healgun_amax && autocvar_g_vehicle_bumblebee_healgun_aps)
490                                                                 trace_ent.armorvalue = min(trace_ent.armorvalue + autocvar_g_vehicle_bumblebee_healgun_aps * frametime, autocvar_g_vehicle_bumblebee_healgun_amax);
491
492                                                         trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * frametime, autocvar_g_vehicle_bumblebee_healgun_hmax);
493                                                 }
494                                                 else if(trace_ent.turrcaps_flags & TFL_TURRCAPS_ISTURRET)
495                                                 {
496                                                         if(trace_ent.health  <= trace_ent.tur_health && autocvar_g_vehicle_bumblebee_healgun_hps)
497                                                                 trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * frametime, trace_ent.tur_health);
498                                                         //else ..hmmm what? ammo?
499
500                                                         trace_ent.SendFlags |= TNSF_STATUS;
501                                                 }
502                                         }
503                         }
504                 }
505
506                 vehic.gun3.enemy.hook_end = trace_endpos;
507                 setorigin(vehic.gun3.enemy, trace_endpos);
508                 vehic.gun3.enemy.SendFlags |= BRG_END;
509
510                 vehic.wait = time + 1;
511         }
512         else
513                 vehic.gun3.enemy.effects |= EF_NODRAW;
514         /*{
515                 if(vehic.gun3.enemy)
516                         remove(vehic.gun3.enemy);
517
518                 vehic.gun3.enemy = world;
519         }
520         */
521
522         VEHICLE_UPDATE_PLAYER(pilot, health, bumblebee);
523         VEHICLE_UPDATE_PLAYER(pilot, energy, bumblebee);
524
525         pilot.vehicle_ammo1 = (vehic.gun1.vehicle_energy / autocvar_g_vehicle_bumblebee_cannon_ammo) * 100;
526         pilot.vehicle_ammo2 = (vehic.gun2.vehicle_energy / autocvar_g_vehicle_bumblebee_cannon_ammo) * 100;
527
528         if(vehic.vehicle_flags & VHF_HASSHIELD)
529                 VEHICLE_UPDATE_PLAYER(pilot, shield, bumblebee);
530
531         vehic.angles_x *= -1;
532         makevectors(vehic.angles);
533         vehic.angles_x *= -1;
534         setorigin(pilot, vehic.origin + v_up * 48 + v_forward * 160);
535
536         pilot.BUTTON_ATCK = pilot.BUTTON_ATCK2 = pilot.BUTTON_CROUCH = 0;
537         self = pilot;
538
539         return 1;
540 }
541
542 void bumb_think()
543 {
544         self.movetype = MOVETYPE_TOSS;
545
546                 //self.velocity = self.velocity * 0.5;
547         self.angles_z *= 0.8;
548         self.angles_x *= 0.8;
549
550         self.nextthink = time + 0.05;
551
552         if(!self.owner)
553         {
554                 entity oldself = self;
555                 if(self.gunner1)
556                 {
557                         self = self.gunner1;
558                         oldself.gun1.vehicle_exit(VHEF_EJECT);
559                         entity oldother = other;
560                         other = self;
561                         self = oldself;
562                         self.phase = 0;
563                         self.touch();
564                         other = oldother;
565                         return;
566                 }
567
568                 if(self.gunner2)
569                 {
570                         self = self.gunner2;
571                         oldself.gun2.vehicle_exit(VHEF_EJECT);
572                         entity oldother = other;
573                         other = self;
574                         self = oldself;
575                         self.phase = 0;
576                         self.touch();
577                         other = oldother;
578                         return;
579                 }
580         }
581
582 }
583
584 void bumb_enter()
585 {
586         self.touch = bumb_touch;
587         self.nextthink = 0;
588         self.movetype = MOVETYPE_BOUNCEMISSILE;
589         //setattachment(self.owner, self.vehicle_viewport, "");
590 }
591
592 void bumb_exit(float eject)
593 {
594         self.touch = vehicles_touch;
595         self.think = bumb_think;
596         self.nextthink = time;
597
598         if(!self.owner)
599                 return;
600
601         fixedmakevectors(self.angles);
602         vector spot;
603         if(vlen(self.velocity) > autocvar_g_vehicle_bumblebee_speed_forward * 0.5)
604                 spot = self.origin + v_up * 128 + v_forward * 200;
605         else
606                 spot = self.origin + v_up * 128 - v_forward * 200;
607
608         spot = vehicles_findgoodexit(spot);
609
610         // Hide beam
611         if(self.gun3.enemy || !wasfreed(self.gun3.enemy)) {
612                 self.gun3.enemy.effects |= EF_NODRAW;
613     }
614
615         self.owner.velocity = 0.75 * self.vehicle.velocity + normalize(spot - self.vehicle.origin) * 200;
616         self.owner.velocity_z += 10;
617         setorigin(self.owner, spot);
618
619         antilag_clear(self.owner);
620     self.owner = world;
621 }
622
623 void bumb_blowup()
624 {
625         RadiusDamage(self, self.enemy, autocvar_g_vehicle_bumblebee_blowup_coredamage,
626                                  autocvar_g_vehicle_bumblebee_blowup_edgedamage,
627                                  autocvar_g_vehicle_bumblebee_blowup_radius, self, world,
628                                  autocvar_g_vehicle_bumblebee_blowup_forceintensity,
629                                  DEATH_VH_BUMB_DEATH, world);
630
631         sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM);
632         pointparticles(particleeffectnum("explosion_large"), randomvec() * 80 + (self.origin + '0 0 100'), '0 0 0', 1);
633
634         if(self.owner.deadflag == DEAD_DYING)
635                 self.owner.deadflag = DEAD_DEAD;
636
637         remove(self);
638 }
639
640 void bumb_diethink()
641 {
642         if(time >= self.wait)
643                 self.think = bumb_blowup;
644
645         if(random() < 0.1)
646         {
647                 sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM);
648                 pointparticles(particleeffectnum("explosion_small"), randomvec() * 80 + (self.origin + '0 0 100'), '0 0 0', 1);
649         }
650
651         self.nextthink = time + 0.1;
652 }
653
654 void bumb_die()
655 {
656         entity oldself = self;
657
658         // Hide beam
659         if(self.gun3.enemy || !wasfreed(self.gun3.enemy))
660                 self.gun3.enemy.effects |= EF_NODRAW;
661
662         if(self.gunner1)
663         {
664                 self = self.gunner1;
665                 oldself.gun1.vehicle_exit(VHEF_EJECT);
666                 self = oldself;
667         }
668
669         if(self.gunner2)
670         {
671                 self = self.gunner2;
672                 oldself.gun2.vehicle_exit(VHEF_EJECT);
673                 self = oldself;
674         }
675
676         self.vehicle_exit(VHEF_EJECT);
677
678         fixedmakevectors(self.angles);
679         vehicle_tossgib(self.gun1, self.velocity + v_right * 300 + v_up * 100 + randomvec() * 200, "cannon_right", rint(random()), rint(random()), 6, randomvec() * 200);
680         vehicle_tossgib(self.gun2, self.velocity + v_right * -300 + v_up * 100 + randomvec() * 200, "cannon_left", rint(random()), rint(random()), 6, randomvec() * 200);
681         vehicle_tossgib(self.gun3, self.velocity + v_forward * 300 + v_up * -100 + randomvec() * 200, "raygun", rint(random()), rint(random()), 6, randomvec() * 300);
682
683         entity _body = vehicle_tossgib(self, self.velocity + randomvec() * 200, "", rint(random()), rint(random()), 6, randomvec() * 100);
684
685         if(random() > 0.5)
686                 _body.touch = bumb_blowup;
687         else
688                 _body.touch = func_null;
689
690         _body.think = bumb_diethink;
691         _body.nextthink = time;
692         _body.wait = time + 2 + (random() * 8);
693         _body.owner = self;
694         _body.enemy = self.enemy;
695
696         pointparticles(particleeffectnum("explosion_medium"), findbetterlocation(self.origin, 16), '0 0 0', 1);
697
698         self.health                     = 0;
699         self.event_damage       = func_null;
700         self.solid                      = SOLID_CORPSE;
701         self.takedamage         = DAMAGE_NO;
702         self.deadflag           = DEAD_DYING;
703         self.movetype           = MOVETYPE_NONE;
704         self.effects            = EF_NODRAW;
705         self.colormod           = '0 0 0';
706         self.avelocity          = '0 0 0';
707         self.velocity           = '0 0 0';
708         self.touch                      = func_null;
709         self.nextthink          = 0;
710
711         setorigin(self, self.pos1);
712 }
713
714 void bumb_impact()
715 {
716         if(autocvar_g_vehicle_bumblebee_bouncepain.x)
717                 vehicles_impact(autocvar_g_vehicle_bumblebee_bouncepain.x, autocvar_g_vehicle_bumblebee_bouncepain.y, autocvar_g_vehicle_bumblebee_bouncepain.z);
718 }
719
720 void bumb_spawn(float _f)
721 {
722         /*
723         float i;
724         for(i=1; gettaginfo(self.gun1, i), gettaginfo_name; ++i)
725         {
726
727             dprint(" ------- ^1gettaginfo_name^2(",ftos(i),") ^3=", gettaginfo_name, "\n");
728         }
729         */
730         if(!self.gun1)
731         {
732                 // for some reason, autosizing of the shiled entity refuses to work for this one so set it up in advance.
733                 self.vehicle_shieldent = spawn();
734                 self.vehicle_shieldent.effects = EF_LOWPRECISION;
735                 setmodel(self.vehicle_shieldent, "models/vhshield.md3");
736                 setattachment(self.vehicle_shieldent, self, "");
737                 setorigin(self.vehicle_shieldent, real_origin(self) - self.origin);
738                 self.vehicle_shieldent.scale       = 512 / vlen(self.maxs - self.mins);
739                 self.vehicle_shieldent.think       = shieldhit_think;
740                 self.vehicle_shieldent.alpha = -1;
741                 self.vehicle_shieldent.effects = EF_LOWPRECISION | EF_NODRAW;
742
743                 self.gun1 = spawn();
744                 self.gun2 = spawn();
745                 self.gun3 = spawn();
746
747                 self.vehicle_flags |= VHF_MULTISLOT;
748
749                 self.gun1.owner = self;
750                 self.gun2.owner = self;
751                 self.gun3.owner = self;
752
753                 setmodel(self.gun1, "models/vehicles/bumblebee_plasma_right.dpm");
754                 setmodel(self.gun2, "models/vehicles/bumblebee_plasma_left.dpm");
755                 setmodel(self.gun3, "models/vehicles/bumblebee_ray.dpm");
756
757                 setattachment(self.gun1, self, "cannon_right");
758                 setattachment(self.gun2, self, "cannon_left");
759
760                 // Angled bones are no fun, messes up gun-aim; so work arround it.
761                 self.gun3.pos1 = self.angles;
762                 self.angles = '0 0 0';
763                 vector ofs = gettaginfo(self, gettagindex(self, "raygun"));
764                 ofs -= self.origin;
765                 setattachment(self.gun3, self, "");
766                 setorigin(self.gun3, ofs);
767                 self.angles = self.gun3.pos1;
768
769                 vehicle_addplayerslot(self, self.gun1, HUD_BUMBLEBEE_GUN, "models/vehicles/wakizashi_cockpit.dpm", bumb_gunner_frame, bumb_gunner_exit);
770                 vehicle_addplayerslot(self, self.gun2, HUD_BUMBLEBEE_GUN, "models/vehicles/wakizashi_cockpit.dpm", bumb_gunner_frame, bumb_gunner_exit);
771
772                 setorigin(self.vehicle_hudmodel, '50 0 -5');    // Move cockpit forward - down.
773                 setorigin(self.vehicle_viewport, '5 0 2');    // Move camera forward up
774
775                 //fixme-model-bones
776                 setorigin(self.gun1.vehicle_hudmodel, '90 -27 -23');
777                 setorigin(self.gun1.vehicle_viewport, '-85 0 50');
778                 //fixme-model-bones
779                 setorigin(self.gun2.vehicle_hudmodel, '90 27 -23');
780                 setorigin(self.gun2.vehicle_viewport, '-85 0 50');
781
782                 self.scale = 1.5;
783
784                 // Raygun beam
785                 if(self.gun3.enemy == world)
786                 {
787                         self.gun3.enemy = spawn();
788                         Net_LinkEntity(self.gun3.enemy, true, 0, bumble_raygun_send);
789                         self.gun3.enemy.SendFlags = BRG_SETUP;
790                         self.gun3.enemy.cnt = autocvar_g_vehicle_bumblebee_raygun;
791                         self.gun3.enemy.effects = EF_NODRAW | EF_LOWPRECISION;
792                 }
793         }
794
795         self.vehicle_health = autocvar_g_vehicle_bumblebee_health;
796         self.vehicle_shield = autocvar_g_vehicle_bumblebee_shield;
797         self.solid          = SOLID_BBOX;
798         //self.movetype         = MOVETYPE_BOUNCEMISSILE;
799         self.movetype           = MOVETYPE_TOSS;
800         self.vehicle_impact = bumb_impact;
801         self.damageforcescale = 0.025;
802
803         setorigin(self, self.origin + '0 0 25');
804 }
805
806 void spawnfunc_vehicle_bumblebee()
807 {
808         if(!autocvar_g_vehicle_bumblebee)
809         {
810                 remove(self);
811                 return;
812         }
813
814         precache_model("models/vehicles/bumblebee_body.dpm");
815         precache_model("models/vehicles/bumblebee_plasma_left.dpm");
816         precache_model("models/vehicles/bumblebee_plasma_right.dpm");
817         precache_model("models/vehicles/bumblebee_ray.dpm");
818         precache_model("models/vehicles/wakizashi_cockpit.dpm");
819         precache_model("models/vehicles/spiderbot_cockpit.dpm");
820         precache_model("models/vehicles/raptor_cockpit.dpm");
821
822         if(autocvar_g_vehicle_bumblebee_energy)
823                 if(autocvar_g_vehicle_bumblebee_energy_regen)
824                         self.vehicle_flags |= VHF_ENERGYREGEN;
825
826         if(autocvar_g_vehicle_bumblebee_shield)
827                 self.vehicle_flags |= VHF_HASSHIELD;
828
829         if(autocvar_g_vehicle_bumblebee_shield_regen)
830                 self.vehicle_flags |= VHF_SHIELDREGEN;
831
832         if(autocvar_g_vehicle_bumblebee_health_regen)
833                 self.vehicle_flags |= VHF_HEALTHREGEN;
834
835         if(!vehicle_initialize(
836                            "Bumblebee", "models/vehicles/bumblebee_body.dpm",
837                            "", "models/vehicles/spiderbot_cockpit.dpm", "", "", "tag_viewport",
838                            HUD_BUMBLEBEE, BUMB_MIN, BUMB_MAX, false,
839                            bumb_spawn, autocvar_g_vehicle_bumblebee_respawntime,
840                            bumb_pilot_frame, bumb_enter, bumb_exit,
841                            bumb_die, bumb_think, false, autocvar_g_vehicle_bumblebee_health, autocvar_g_vehicle_bumblebee_shield))
842         {
843                 remove(self);
844                 return;
845         }
846 }
847
848 float bumble_raygun_send(entity to, int sf)
849 {
850         WriteByte(MSG_ENTITY, ENT_CLIENT_BUMBLE_RAYGUN);
851
852         WriteByte(MSG_ENTITY, sf);
853         if(sf & BRG_SETUP)
854         {
855                 WriteByte(MSG_ENTITY, num_for_edict(self.realowner));
856                 WriteByte(MSG_ENTITY, self.realowner.team);
857                 WriteByte(MSG_ENTITY, self.cnt);
858         }
859
860         if(sf & BRG_START)
861         {
862                 WriteCoord(MSG_ENTITY, self.hook_start.x);
863                 WriteCoord(MSG_ENTITY, self.hook_start.y);
864                 WriteCoord(MSG_ENTITY, self.hook_start.z);
865         }
866
867         if(sf & BRG_END)
868         {
869                 WriteCoord(MSG_ENTITY, self.hook_end.x);
870                 WriteCoord(MSG_ENTITY, self.hook_end.y);
871                 WriteCoord(MSG_ENTITY, self.hook_end.z);
872         }
873
874         return true;
875 }
876 #endif // SVQC
877
878 #ifdef CSQC
879 /*
880 .vector raygun_l1
881 .vector raygun_l2;
882 .vector raygun_l3;
883 */
884
885 void bumble_raygun_draw()
886 {
887         float _len;
888         vector _dir;
889         vector _vtmp1, _vtmp2;
890
891         _len = vlen(self.origin - self.move_origin);
892         _dir = normalize(self.move_origin - self.origin);
893
894         if(self.total_damages < time)
895         {
896                 boxparticles(self.traileffect, self, self.origin, self.origin + _dir * -64, _dir * -_len , _dir * -_len, 1, PARTICLES_USEALPHA);
897                 boxparticles(self.lip, self, self.move_origin, self.move_origin + _dir * -64, _dir * -200 , _dir * -200, 1, PARTICLES_USEALPHA);
898                 self.total_damages = time + 0.1;
899         }
900
901         float i, df, sz, al;
902         for(i = -0.1; i < 0.2; i += 0.1)
903         {
904                 df = DRAWFLAG_NORMAL; //((random() < 0.5) ? DRAWFLAG_ADDITIVE : DRAWFLAG_SCREEN);
905                 sz = 5 + random() * 5;
906                 al = 0.25 + random() * 0.5;
907                 _vtmp1 = self.origin + _dir * _len * (0.25 + i);
908                 _vtmp1 += (randomvec() * (_len * 0.2) * (frametime * 2));       //self.raygun_l1;
909                 Draw_CylindricLine(self.origin, _vtmp1, sz, "gfx/colors/white.tga", 1, 1, self.colormod, al, df, view_origin);
910
911                 _vtmp2 = self.origin + _dir * _len * (0.5 + i);
912                 _vtmp2 += (randomvec() * (_len * 0.2) * (frametime * 5));       //self.raygun_l2;
913                 Draw_CylindricLine(_vtmp1, _vtmp2, sz, "gfx/colors/white.tga", 1, 1, self.colormod, al, df, view_origin);
914
915                 _vtmp1 = self.origin + _dir * _len * (0.75 + i);
916                 _vtmp1 += randomvec() * (_len * 0.2) * (frametime * 10);     //self.raygun_l3;
917                 Draw_CylindricLine(_vtmp2, _vtmp1, sz, "gfx/colors/white.tga", 1, 1, self.colormod, al, df, view_origin);
918
919                 Draw_CylindricLine(_vtmp1, self.move_origin +  randomvec() * 32, sz, "gfx/colors/white.tga", 1, 1, self.colormod, al, df, view_origin);
920         }
921 }
922
923 void bumble_raygun_read(float bIsNew)
924 {
925         int sf = ReadByte();
926
927         if(sf & BRG_SETUP)
928         {
929                 self.cnt  = ReadByte();
930                 self.team = ReadByte();
931                 self.cnt  = ReadByte();
932
933                 if(self.cnt)
934                         self.colormod = '1 0 0';
935                 else
936                         self.colormod = '0 1 0';
937
938                 self.traileffect = particleeffectnum("healray_muzzleflash");
939                 self.lip = particleeffectnum("healray_impact");
940
941                 self.draw = bumble_raygun_draw;
942         }
943
944
945         if(sf & BRG_START)
946         {
947                 self.origin_x = ReadCoord();
948                 self.origin_y = ReadCoord();
949                 self.origin_z = ReadCoord();
950                 setorigin(self, self.origin);
951         }
952
953         if(sf & BRG_END)
954         {
955                 self.move_origin_x = ReadCoord();
956                 self.move_origin_y = ReadCoord();
957                 self.move_origin_z = ReadCoord();
958         }
959 }
960
961 void bumblebee_draw()
962 {
963
964 }
965
966 void bumblebee_draw2d()
967 {
968
969 }
970
971 void bumblebee_read_extra()
972 {
973
974 }
975
976 void vehicle_bumblebee_assemble()
977 {
978
979 }
980 #endif //CSQC