]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/vehicles/vehicles.qc
Merge remote-tracking branch 'origin/master' into samual/mutator_ctf
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / vehicles / vehicles.qc
index 963f1875c1913d5ee9bceeecee2b76be7acfeeac..87ceecc0c61fd2688a5a6243fdf34f59d5561798 100644 (file)
@@ -3,6 +3,14 @@ float autocvar_g_vehicles_crush_force;
 float autocvar_g_vehicles_delayspawn;
 float autocvar_g_vehicles_delayspawn_jitter;
 
+var float autocvar_g_vehicles_nex_damagerate = 0.5;
+var float autocvar_g_vehicles_uzi_damagerate = 0.5;
+var float autocvar_g_vehicles_rifle_damagerate = 0.75;
+var float autocvar_g_vehicles_minstanex_damagerate = 0.001;
+var float autocvar_g_vehicles_tag_damagerate = 5;
+
+float autocvar_g_vehicles;
+
 void vehicles_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force);
 void vehicles_return();
 void vehicles_enter();
@@ -38,6 +46,9 @@ float SendAuxiliaryXhair(entity to, float sf)
 
 void UpdateAuxiliaryXhair(entity own, vector loc, vector clr, float axh_id)
 {
+    if (clienttype(own) != CLIENTTYPE_REAL)
+        return;
+
     entity axh;
 
     axh_id = bound(0, axh_id, MAX_AXH);
@@ -63,7 +74,7 @@ void UpdateAuxiliaryXhair(entity own, vector loc, vector clr, float axh_id)
 // WriteByte(MSG_ONE, SVC_TEMPENTITY) uses reliable messagess, never use for thinsg that need continous updates.
 void SendAuxiliaryXhair2(entity own, vector loc, vector clr, float axh_id)
 {
-       msg_entity = own;
+       msgexntity = own;
 
        WriteByte(MSG_ONE, SVC_TEMPENTITY);
        WriteByte(MSG_ONE, TE_CSQC_AUXILIARYXHAIR);
@@ -83,18 +94,24 @@ void SendAuxiliaryXhair2(entity own, vector loc, vector clr, float axh_id)
 // End AuxiliaryXhair
 
 /**
-    Notifies the client that he enterd a vehicle, and sends 
+    Notifies the client that he enterd a vehicle, and sends
     realavent data.
-    
+
     only sends vehicle_id atm (wich is a HUD_* constant, ex. HUD_SPIDERBOT)
 **/
 void CSQCVehicleSetup(entity own, float vehicle_id)
 {
+    if (clienttype(own) != CLIENTTYPE_REAL)
+        return;
+       
        msg_entity = own;
 
        WriteByte(MSG_ONE, SVC_TEMPENTITY);
        WriteByte(MSG_ONE, TE_CSQC_VEHICLESETUP);
-       WriteByte(MSG_ONE, vehicle_id);
+       if(vehicle_id != 0)
+           WriteByte(MSG_ONE, vehicle_id);        
+       else
+        WriteByte(MSG_ONE, 1 + own.vehicle.vehicle_weapon2mode + HUD_VEHICLE_LAST);
 }
 
 /** vehicles_locktarget
@@ -114,6 +131,121 @@ void CSQCVehicleSetup(entity own, float vehicle_id)
 .float  lock_strength;
 .float  lock_time;
 .float  lock_soundtime;
+float  DAMAGE_TARGETDRONE = 10;
+
+vector targetdrone_getnewspot()
+{
+
+       vector spot;
+       float i;
+       for(i = 0; i < 100; ++i)
+       {
+               spot = self.origin + randomvec() * 1024;
+               tracebox(spot, self.mins, self.maxs, spot, MOVE_NORMAL, self);
+               if(trace_fraction == 1.0 && trace_startsolid == 0 && trace_allsolid == 0)
+                       return spot;
+       }
+       return self.origin;
+}
+
+#if 0
+void targetdrone_think();
+void targetdrone_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force);
+void targetdrone_renwe()
+{
+       self.think = targetdrone_think;
+       self.nextthink = time + 0.1;
+       setorigin(self, targetdrone_getnewspot());
+       self.health = 200;
+       self.takedamage = DAMAGE_TARGETDRONE;
+       self.event_damage = targetdrone_damage;
+       self.solid = SOLID_BBOX;
+       setmodel(self, "models/runematch/rune.mdl");
+       self.effects = EF_LOWPRECISION;
+       self.scale = 10;
+       self.movetype = MOVETYPE_BOUNCEMISSILE;
+       setsize(self, '-100 -100 -100', '100 100 100');
+
+}
+void targetdrone_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+{
+       self.health -= damage;
+       if(self.health <= 0)
+       {
+               pointparticles(particleeffectnum("explosion_medium"), self.origin, '0 0 0', 1);
+
+               if(!self.cnt)
+                       remove(self);
+               else
+               {
+                       self.think = targetdrone_renwe;
+                       self.nextthink = time + 1 + random() * 2;
+                       self.solid = SOLID_NOT;
+                       setmodel(self, "");
+               }
+       }
+}
+entity targetdrone_getfear()
+{
+       entity fear;
+       float i;
+
+       for(i = 64; i <= 1024; i += 64)
+       {
+               fear = findradius(self.origin, i);
+               while(fear)
+               {
+                       if(fear.bot_dodge)
+                               return fear;
+
+                       fear = fear.chain;
+               }
+       }
+
+       return world;
+}
+void targetdrone_think()
+{
+       self.nextthink = time + 0.1;
+
+       if(self.wp00)
+       if(self.wp00.deadflag != DEAD_NO)
+               self.wp00 = targetdrone_getfear();
+
+       if(!self.wp00)
+               self.wp00 = targetdrone_getfear();
+
+       vector newdir;
+
+       if(self.wp00)
+               newdir = steerlib_push(self.wp00.origin) + randomvec() * 0.75;
+       else
+               newdir = randomvec() * 0.75;
+
+       newdir = newdir * 0.5 + normalize(self.velocity) * 0.5;
+
+       if(self.wp00)
+               self.velocity = normalize(newdir) * (500 + (1024 / min(vlen(self.wp00.origin - self.origin), 1024)) * 700);
+       else
+               self.velocity = normalize(newdir) * 750;
+
+       tracebox(self.origin, self.mins, self.maxs, self.origin + self.velocity * 2, MOVE_NORMAL, self);
+       if(trace_fraction != 1.0)
+               self.velocity = self.velocity * -1;
+
+       //normalize((normalize(self.velocity) * 0.5 + newdir * 0.5)) * 750;
+}
+
+void targetdrone_spawn(vector _where, float _autorenew)
+{
+       entity drone = spawn();
+       setorigin(drone, _where);
+       drone.think = targetdrone_renwe;
+       drone.nextthink = time + 0.1;
+       drone.cnt = _autorenew;
+}
+#endif
+
 void vehicles_locktarget(float incr, float decr, float _lock_time)
 {
     if(self.lock_target && self.lock_target.deadflag != DEAD_NO)
@@ -131,7 +263,7 @@ void vehicles_locktarget(float incr, float decr, float _lock_time)
             self.lock_soundtime = time + 0.5;
             play2(self.owner, "vehicles/locked.wav");
         }
-        
+
         return;
     }
 
@@ -143,28 +275,30 @@ void vehicles_locktarget(float incr, float decr, float _lock_time)
         if(trace_ent.deadflag != DEAD_NO)
             trace_ent = world;
 
-        if not (trace_ent.vehicle_flags & VHF_ISVEHICLE || trace_ent.turrcaps_flags & TFL_TURRCAPS_ISTURRET)
+        if not (trace_ent.vehicle_flags & VHF_ISVEHICLE ||
+                               trace_ent.turrcaps_flags & TFL_TURRCAPS_ISTURRET ||
+                               trace_ent.takedamage == DAMAGE_TARGETDRONE)
             trace_ent = world;
     }
 
     if(self.lock_target == world && trace_ent != world)
         self.lock_target = trace_ent;
-    
-    if(self.lock_target && trace_ent == self.lock_target) 
-    {            
+
+    if(self.lock_target && trace_ent == self.lock_target)
+    {
         if(self.lock_strength != 1 && self.lock_strength + incr >= 1)
         {
             play2(self.owner, "vehicles/lock.wav");
             self.lock_soundtime = time + 0.8;
-        }        
+        }
         else if (self.lock_strength != 1 && self.lock_soundtime < time)
-        {            
+        {
             play2(self.owner, "vehicles/locking.wav");
             self.lock_soundtime = time + 0.3;
         }
-        
-    }    
-        
+
+    }
+
     // Have a locking target
     // Trace hit current target
     if(trace_ent == self.lock_target && trace_ent != world)
@@ -185,8 +319,8 @@ void vehicles_locktarget(float incr, float decr, float _lock_time)
     }
 }
 
-#define VEHICLE_UPDATE_PLAYER(fld,vhname) \
-self.owner.vehicle_##fld = (self.vehicle_##fld / autocvar_g_vehicle_##vhname##_##fld) * 100
+#define VEHICLE_UPDATE_PLAYER(ply,fld,vhname) \
+ply.vehicle_##fld = (self.vehicle_##fld / autocvar_g_vehicle_##vhname##_##fld) * 100
 
 #define vehicles_sweap_collision(orig,vel,dt,acm,mult) \
 traceline(orig, orig + vel * dt, MOVE_NORMAL, self); \
@@ -236,8 +370,8 @@ void vehicles_projectile_damage(entity inflictor, entity attacker, float damage,
 {
     // Ignore damage from oterh projectiles from my owner (dont mess up volly's)
     if(inflictor.owner == self.owner)
-        return; 
-    
+        return;
+
     self.health -= damage;
     self.velocity += force;
     if(self.health < 1)
@@ -247,7 +381,6 @@ void vehicles_projectile_damage(entity inflictor, entity attacker, float damage,
         self.think = self.use;
         self.nextthink = time;
     }
-
 }
 
 void vehicles_projectile_explode()
@@ -273,7 +406,7 @@ entity vehicles_projectile(string _mzlfx, string _mzlsound,
                            vector _org, vector _vel,
                            float _dmg, float _radi, float _force,  float _size,
                            float _deahtype, float _projtype, float _health,
-                           float _cull, float _clianim)
+                           float _cull, float _clianim, entity _owner)
 {
     entity proj;
 
@@ -295,7 +428,7 @@ entity vehicles_projectile(string _mzlfx, string _mzlsound,
     proj.touch            = vehicles_projectile_explode;
     proj.use              = vehicles_projectile_explode;
     proj.owner            = self;
-    proj.realowner        = self.owner;
+    proj.realowner        = _owner;
     proj.think            = SUB_Remove;
     proj.nextthink        = time + 30;
 
@@ -359,9 +492,12 @@ void vehicles_spawn()
     setorigin(self, self.pos1 + '0 0 0');
     // Show it
     pointparticles(particleeffectnum("teleport"), self.origin + '0 0 64', '0 0 0', 1);
-
+    
+    if(self.vehicle_controller)
+        self.team = self.vehicle_controller.team;
+       
     vehicles_reset_colors();
-    self.vehicle_spawn();
+    self.vehicle_spawn(VHSF_NORMAL);
 }
 
 // Better way of determening whats crushable needed! (fl_crushable?)
@@ -377,21 +513,21 @@ float vehicles_crushable(entity e)
 }
 
 void vehilces_impact(float _minspeed, float _speedfac, float _maxpain)
-{    
+{
     if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
         return;
-    
+
     if(self.play_time < time)
-    {                    
+    {
         float wc = vlen(self.velocity - self.oldvelocity);
         //dprint("oldvel: ", vtos(self.oldvelocity), "\n");
         //dprint("vel: ", vtos(self.velocity), "\n");
         if(_minspeed < wc)
         {
-            float take = take = min(_speedfac * wc, _maxpain);
+            float take = min(_speedfac * wc, _maxpain);
             Damage (self, world, world, take, DEATH_FALL, self.origin, '0 0 0');
             self.play_time = time + 0.25;
-            
+
             //dprint("wc: ", ftos(wc), "\n");
             //dprint("take: ", ftos(take), "\n");
         }
@@ -409,14 +545,14 @@ void vehicles_touch()
         {
             if(vlen(self.velocity) != 0)
                 Damage(other, self, self.owner, autocvar_g_vehicles_crush_dmg, DEATH_VHCRUSH, '0 0 0', normalize(other.origin - self.origin) * autocvar_g_vehicles_crush_force);
-            
+
             return; // Dont do selfdamage when hitting "soft targets".
         }
-        
+
         if(self.play_time < time)
         if(self.vehicle_impact)
             self.vehicle_impact();
-        
+
         return;
     }
 
@@ -429,18 +565,18 @@ void vehicles_touch()
     if(other.vehicle != world)
         return;
 
-    // Remove this when bots know how to use vehicles.
-    if (clienttype(other) != CLIENTTYPE_REAL)
-        return;
-
     vehicles_enter();
 }
-
+var float autocvar_g_vehicles_allow_bots = 0;
 void vehicles_enter()
 {
    // Remove this when bots know how to use vehicles
-    if (clienttype(other) != CLIENTTYPE_REAL)
-        return;
+   
+    if (clienttype(other) == CLIENTTYPE_BOT)    
+        if (autocvar_g_vehicles_allow_bots)
+            dprint("Bot enters vehicle\n"); // This is where we need to disconnect (some, all?) normal bot AI and hand over to vehicle's _aiframe()
+        else
+            return;
 
     if(self.phase > time)
         return;
@@ -449,7 +585,7 @@ void vehicles_enter()
     if(self.team)
     if(self.team != other.team)
         return;
-        
+
     RemoveGrapplingHook(other);
 
     self.vehicle_ammo1   = 0;
@@ -497,23 +633,26 @@ void vehicles_enter()
 
     self.team                 = self.owner.team;
     self.flags               -= FL_NOTARGET;
-
-    msg_entity = other;
-    WriteByte (MSG_ONE, SVC_SETVIEWPORT);
-    WriteEntity(MSG_ONE, self.vehicle_viewport);
-
-    WriteByte (MSG_ONE, SVC_SETVIEWANGLES);
-    if(self.tur_head)
-    {
-        WriteAngle(MSG_ONE, self.tur_head.angles_x + self.angles_x); // tilt
-        WriteAngle(MSG_ONE, self.tur_head.angles_y + self.angles_y); // yaw
-        WriteAngle(MSG_ONE, 0);                                      // roll
-    }
-    else
+    
+    if (clienttype(other) == CLIENTTYPE_REAL)
     {
-        WriteAngle(MSG_ONE,  self.angles_x * -1); // tilt
-        WriteAngle(MSG_ONE,  self.angles_y);      // yaw
-        WriteAngle(MSG_ONE,  0);                  // roll
+        msg_entity = other;
+        WriteByte (MSG_ONE, SVC_SETVIEWPORT);
+        WriteEntity(MSG_ONE, self.vehicle_viewport);
+                
+        WriteByte (MSG_ONE, SVC_SETVIEWANGLES);
+        if(self.tur_head)
+        {
+            WriteAngle(MSG_ONE, self.tur_head.angles_x + self.angles_x); // tilt
+            WriteAngle(MSG_ONE, self.tur_head.angles_y + self.angles_y); // yaw
+            WriteAngle(MSG_ONE, 0);                                      // roll
+        }
+        else
+        {
+            WriteAngle(MSG_ONE,  self.angles_x * -1); // tilt
+            WriteAngle(MSG_ONE,  self.angles_y);      // yaw
+            WriteAngle(MSG_ONE,  0);                  // roll
+        }
     }
 
     vehicles_clearrturn();
@@ -521,7 +660,7 @@ void vehicles_enter()
     CSQCVehicleSetup(self.owner, self.hud);
     
     MUTATOR_CALLHOOK(VehicleEnter);
-    
+
     self.vehicle_enter();
     antilag_clear(other);
 }
@@ -535,17 +674,17 @@ vector vehicles_findgoodexit(vector prefer_spot)
 {
     //vector exitspot;
     float mysize;
-    
+
     tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, prefer_spot, MOVE_NORMAL, self.owner);
     if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
         return prefer_spot;
-    
-    mysize = vlen(self.maxs - self.mins);
+
+    mysize = 1.5 * vlen(self.maxs - self.mins);
     float i;
     vector v, v2;
     v2 = 0.5 * (self.absmin + self.absmax);
     for(i = 0; i < 100; ++i)
-    {        
+    {
         v = randomvec();
         v_z = 0;
         v = v2 + normalize(v) * mysize;
@@ -553,13 +692,13 @@ vector vehicles_findgoodexit(vector prefer_spot)
         if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
             return v;
     }
-    
+
     /*
     exitspot = (self.origin + '0 0 48') + v_forward * mysize;
     tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, self.owner);
     if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
         return exitspot;
-    
+
     exitspot = (self.origin + '0 0 48') - v_forward * mysize;
     tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, self.owner);
     if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
@@ -569,13 +708,13 @@ vector vehicles_findgoodexit(vector prefer_spot)
     tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, self.owner);
     if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
         return exitspot;
-    
+
     exitspot = (self.origin + '0 0 48') - v_right * mysize;
     tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, self.owner);
     if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
         return exitspot;
     */
-    
+
     return self.origin;
 }
 
@@ -583,77 +722,108 @@ vector vehicles_findgoodexit(vector prefer_spot)
     Standarrd vehicle release fucntion.
     custom code goes in self.vehicle_exit
 **/
+float vehicles_exit_running;
 void vehicles_exit(float eject)
-{      
-    entity oldself;
+{
+    entity _vehicle;
+    entity _player;
+    entity _oldself = self;
+    
+    if(vehicles_exit_running)
+    {
+        dprint("^1vehicles_exit allready running! this is not good..\n");
+        return;
+    }
+    
+    vehicles_exit_running = TRUE;
     if(self.flags & FL_CLIENT)
     {
-        oldself = self;
-        self = self.vehicle;
+        _vehicle = self.vehicle;
+            
+        if (_vehicle.vehicle_flags & VHF_PLAYERSLOT)
+        {
+            _vehicle.vehicle_exit(eject);
+            self = _oldself;
+            vehicles_exit_running = FALSE;
+            return;            
+        }
     }
+    else
+        _vehicle = self;
     
-       self.flags |= FL_NOTARGET;
+    _player = _vehicle.owner;
+    
+    self = _vehicle;
 
-    if (self.owner)
+    if (_player)
     {
-        msg_entity = self.owner;
-        WriteByte (MSG_ONE, SVC_SETVIEWPORT);
-        WriteEntity( MSG_ONE, self.owner);
-
-        WriteByte (MSG_ONE, SVC_SETVIEWANGLES);
-        WriteAngle(MSG_ONE, 0);                 // pich
-        WriteAngle(MSG_ONE, self.angles_y);     // yaw
-        WriteAngle(MSG_ONE, 0);                 // roll
-
-        setsize(self.owner, PL_MIN,PL_MAX);
-
-        self.owner.takedamage     = DAMAGE_AIM;
-        self.owner.solid          = SOLID_SLIDEBOX;
-        self.owner.movetype       = MOVETYPE_WALK;
-        self.owner.effects        &~= EF_NODRAW;
-        self.owner.alpha          = 1;
-        self.owner.PlayerPhysplug = SUB_Null;
-        self.owner.vehicle        = world;
-        self.owner.view_ofs       = PL_VIEW_OFS;
-        self.owner.event_damage   = PlayerDamage;
-        self.owner.hud            = HUD_NORMAL;
-        self.owner.switchweapon   = self.switchweapon;
-        //self.owner.BUTTON_USE     = 0;
+        if (clienttype(_player) == CLIENTTYPE_REAL)
+        {
+            msg_entity = _player;
+            WriteByte (MSG_ONE, SVC_SETVIEWPORT);
+            WriteEntity( MSG_ONE, _player);
+
+            WriteByte (MSG_ONE, SVC_SETVIEWANGLES);
+            WriteAngle(MSG_ONE, 0);
+            WriteAngle(MSG_ONE, _vehicle.angles_y);
+            WriteAngle(MSG_ONE, 0);
+        }
         
-        CSQCVehicleSetup(self.owner, HUD_NORMAL);
-    }
-
-    if(self.deadflag == DEAD_NO)
-        self.avelocity          = '0 0 0';
-
-    self.vehicle_hudmodel.viewmodelforclient = self;
-       self.tur_head.nodrawtoclient             = world;
-    vehicles_setreturn();
-
-    self.phase = time + 1;
+        setsize(_player, PL_MIN,PL_MAX);
+
+        _player.takedamage     = DAMAGE_AIM;
+        _player.solid          = SOLID_SLIDEBOX;
+        _player.movetype       = MOVETYPE_WALK;
+        _player.effects        &~= EF_NODRAW;
+        _player.alpha          = 1;
+        _player.PlayerPhysplug = SUB_Null;
+        _player.vehicle        = world;
+        _player.view_ofs       = PL_VIEW_OFS;
+        _player.event_damage   = PlayerDamage;
+        _player.hud            = HUD_NORMAL;
+        _player.switchweapon   = _vehicle.switchweapon;
+
+        if(_player.flagcarried)
+        {
+            _player.flagcarried.scale = 0.6;
+            setattachment(_player.flagcarried, _player, "");
+            setorigin(_player.flagcarried, FLAG_CARRY_POS);
+        }
 
+        CSQCVehicleSetup(_player, HUD_NORMAL);
+    }
+    _vehicle.flags |= FL_NOTARGET;
+    
+    if(_vehicle.deadflag == DEAD_NO)
+        _vehicle.avelocity          = '0 0 0';
+    
+    _vehicle.tur_head.nodrawtoclient             = world;
+    
     if(!teamplay)
-        self.team = 0;
+        _vehicle.team = 0;
     else
-        self.team = self.tur_head.team;
+    
+    self.team = self.tur_head.team;
    
     MUTATOR_CALLHOOK(VehicleExit);
     
-    sound (self, CH_TRIGGER_SINGLE, "misc/null.wav", 1, ATTN_NORM);
-    self.vehicle_exit(eject);
-    self.owner = world;
-    vehicles_reset_colors();
+    vehicles_setreturn();
+    vehicles_reset_colors();        
+    _vehicle.owner = world;
+    self = _oldself;
     
-    if(oldself)
-        self = oldself;
+    vehicles_exit_running = FALSE;
 }
 
 
-void vehicles_regen(.float timer, .float regen_field, float field_max, float rpause, float regen, float delta_time)
+void vehicles_regen(float timer, .float regen_field, float field_max, float rpause, float regen, float delta_time, float _healthscale)
 {
     if(self.regen_field < field_max)
-    if(self.timer + rpause < time)
+    if(timer + rpause < time)
     {
+        if(_healthscale)
+            regen = regen * (self.vehicle_health / self.tur_health);
+            
         self.regen_field = min(self.regen_field + regen * delta_time, field_max);
 
         if(self.owner)
@@ -668,6 +838,7 @@ void shieldhit_think()
     {
         //setmodel(self, "");
         self.alpha = -1;
+        self.effects |= EF_NODRAW;
     }
     else
     {
@@ -676,31 +847,48 @@ void shieldhit_think()
 }
 
 void vehicles_painframe()
-{    
+{
     if(self.owner.vehicle_health <= 50)
     if(self.pain_frame < time)
-    {  
-        float _ftmp;  
+    {
+        float _ftmp;
         _ftmp = self.owner.vehicle_health / 50;
         self.pain_frame = time + 0.1 + (random() * 0.5 * _ftmp);
         pointparticles(particleeffectnum("smoke_small"), (self.origin + (randomvec() * 80)), '0 0 0', 1);
-        
+
         if(self.vehicle_flags & VHF_DMGSHAKE)
             self.velocity += randomvec() * 30;
-        
+
         if(self.vehicle_flags & VHF_DMGROLL)
             if(self.vehicle_flags & VHF_DMGHEADROLL)
                 self.tur_head.angles += randomvec();
             else
                 self.angles += randomvec();
-        
-    }    
+
+    }
 }
 
 void vehicles_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
 {
     self.dmg_time = time;
+    
+    if(DEATH_ISWEAPON(deathtype, WEP_NEX))
+        damage *= autocvar_g_vehicles_nex_damagerate;
+        
+    if(DEATH_ISWEAPON(deathtype, WEP_UZI))
+        damage *= autocvar_g_vehicles_uzi_damagerate;
+        
+    if(DEATH_ISWEAPON(deathtype, WEP_RIFLE))
+        damage *= autocvar_g_vehicles_rifle_damagerate;
+        
+    if(DEATH_ISWEAPON(deathtype, WEP_MINSTANEX))
+        damage *= autocvar_g_vehicles_minstanex_damagerate;
 
+    if(DEATH_ISWEAPON(deathtype, WEP_SEEKER))
+        damage *= autocvar_g_vehicles_tag_damagerate;
+    
+    self.enemy = attacker;
+    
     if((self.vehicle_flags & VHF_HASSHIELD) && (self.vehicle_shield > 0))
     {
         if (wasfreed(self.vehicle_shieldent) || self.vehicle_shieldent == world)
@@ -719,6 +907,7 @@ void vehicles_damage(entity inflictor, entity attacker, float damage, float deat
         self.vehicle_shieldent.alpha       = 0.45;
         self.vehicle_shieldent.angles      = vectoangles(normalize(hitloc - (self.origin + self.vehicle_shieldent.origin))) - self.angles;
         self.vehicle_shieldent.nextthink   = time;
+        self.vehicle_shieldent.effects &~= EF_NODRAW;
 
         self.vehicle_shield -= damage;
 
@@ -728,7 +917,7 @@ void vehicles_damage(entity inflictor, entity attacker, float damage, float deat
             self.vehicle_shieldent.colormod = '2 0 0';
             self.vehicle_shield             = 0;
             self.vehicle_shieldent.alpha    = 0.75;
-            
+
                if(sound_allowed(MSG_BROADCAST, attacker))
                 spamsound (self, CH_PAIN, "onslaught/ons_hit2.wav", VOL_BASE, ATTN_NORM);   // FIXME: PLACEHOLDER
         }
@@ -744,8 +933,11 @@ void vehicles_damage(entity inflictor, entity attacker, float damage, float deat
         if(sound_allowed(MSG_BROADCAST, attacker))
             spamsound (self, CH_PAIN, "onslaught/ons_hit2.wav", VOL_BASE, ATTN_NORM);  // FIXME: PLACEHOLDER
     }
-
-    self.velocity += force; // * (vlen(force) / self.mass);
+    
+       if(self.damageforcescale < 1 && self.damageforcescale > 0)
+               self.velocity += force * self.damageforcescale;
+       else
+               self.velocity += force;
 
     if(self.vehicle_health <= 0)
     {
@@ -755,6 +947,9 @@ void vehicles_damage(entity inflictor, entity attacker, float damage, float deat
             else
                 vehicles_exit(VHEF_RELESE);
 
+
+        antilag_clear(self);
+
         self.vehicle_die();
         vehicles_setreturn();
     }
@@ -767,15 +962,15 @@ void vehicles_clearrturn()
     ret = findchain(classname, "vehicle_return");
     while(ret)
     {
-        if(ret.enemy == self)
+        if(ret.wp00 == self)
         {
             ret.classname   = "";
             ret.think       = SUB_Remove;
-            ret.nextthink   = time + 0.1;            
-            
+            ret.nextthink   = time + 0.1;
+
             if(ret.waypointsprite_attached)
                 WaypointSprite_Kill(ret.waypointsprite_attached);
-            
+
             return;
         }
         ret = ret.chain;
@@ -784,14 +979,14 @@ void vehicles_clearrturn()
 
 void vehicles_return()
 {
-    pointparticles(particleeffectnum("teleport"), self.enemy.origin + '0 0 64', '0 0 0', 1);
+    pointparticles(particleeffectnum("teleport"), self.wp00.origin + '0 0 64', '0 0 0', 1);
 
-    self.enemy.think     = vehicles_spawn;
-    self.enemy.nextthink = time;
+    self.wp00.think     = vehicles_spawn;
+    self.wp00.nextthink = time;
 
     if(self.waypointsprite_attached)
         WaypointSprite_Kill(self.waypointsprite_attached);
-            
+
     remove(self);
 }
 
@@ -799,50 +994,50 @@ void vehicles_showwp_goaway()
 {
     if(self.waypointsprite_attached)
         WaypointSprite_Kill(self.waypointsprite_attached);
-            
+
     remove(self);
-    
+
 }
 
 void vehicles_showwp()
 {
     entity oldself;
     vector rgb;
-    
+
     if(self.cnt)
-    {        
+    {
         self.think      = vehicles_return;
         self.nextthink  = self.cnt;
-    }    
+    }
     else
     {
         self.think      = vehicles_return;
         self.nextthink  = time +1;
-        
+
         oldself = self;
         self = spawn();
         setmodel(self, "null");
-        self.team = oldself.enemy.team;
-        self.enemy = oldself.enemy;
-        setorigin(self, oldself.enemy.pos1);
-        
+        self.team = oldself.wp00.team;
+        self.wp00 = oldself.wp00;
+        setorigin(self, oldself.wp00.pos1);
+
         self.nextthink = time + 5;
         self.think = vehicles_showwp_goaway;
     }
-    
+
     if(teamplay && self.team)
            rgb = TeamColor(self.team);
     else
            rgb = '1 1 1';
     WaypointSprite_Spawn("vehicle", 0, 0, self, '0 0 64', world, 0, self, waypointsprite_attached, TRUE, RADARICON_POWERUP, rgb);
     if(self.waypointsprite_attached)
-    {        
-        WaypointSprite_UpdateRule(self.waypointsprite_attached, self.enemy.team, SPRITERULE_DEFAULT);        
+    {
+        WaypointSprite_UpdateRule(self.waypointsprite_attached, self.wp00.team, SPRITERULE_DEFAULT);
         if(oldself == world)
-            WaypointSprite_UpdateBuildFinished(self.waypointsprite_attached, self.nextthink);        
+            WaypointSprite_UpdateBuildFinished(self.waypointsprite_attached, self.nextthink);
         WaypointSprite_Ping(self.waypointsprite_attached);
-    }    
-    
+    }
+
     if(oldself != world)
         self = oldself;
 }
@@ -850,34 +1045,28 @@ void vehicles_showwp()
 void vehicles_setreturn()
 {
     entity ret;
-    
+
     vehicles_clearrturn();
 
     ret = spawn();
     ret.classname   = "vehicle_return";
-    ret.enemy       = self;    
+    ret.wp00       = self;
     ret.team        = self.team;
     ret.think       = vehicles_showwp;
-    
+
     if(self.deadflag != DEAD_NO)
     {
         ret.cnt         = time + self.vehicle_respawntime;
-        ret.nextthink   = min(time + self.vehicle_respawntime, time + self.vehicle_respawntime - 5);        
-    }        
+        ret.nextthink   = min(time + self.vehicle_respawntime, time + self.vehicle_respawntime - 5);
+    }
     else
     {
-        ret.nextthink   = min(time + self.vehicle_respawntime, time + self.vehicle_respawntime - 1);        
+        ret.nextthink   = min(time + self.vehicle_respawntime, time + self.vehicle_respawntime - 1);
     }
-    
+
     setmodel(ret, "null");
     setorigin(ret, self.pos1 + '0 0 96');
-       
-}
 
-void vehicles_configcheck(string  configname, float check_cvar)
-{
-    if(check_cvar == 0)
-        localcmd(strcat("exec ", configname, "\n"));
 }
 
 void vehicles_reset_colors()
@@ -925,6 +1114,57 @@ void vehicles_reset_colors()
     self.effects   = _effects;
 }
 
+void vehicle_use()
+{
+    dprint("vehicle ",self.netname, " used by ", activator.classname, "\n");
+
+    self.tur_head.team = activator.team;
+
+    if(self.tur_head.team == 0)
+        self.active = ACTIVE_NOT;
+    else
+        self.active = ACTIVE_ACTIVE;
+    
+    if(self.active == ACTIVE_ACTIVE && self.deadflag == DEAD_NO)
+    {
+        dprint("^3Eat shit yall!\n");
+        vehicles_setreturn();
+        vehicles_reset_colors();
+    }
+    else if(self.active == ACTIVE_NOT && self.deadflag != DEAD_NO)
+    {
+        
+    }
+}
+
+float vehicle_addplayerslot(    entity _owner, 
+                                entity _slot, 
+                                float _hud, 
+                                string _hud_model,
+                                float() _framefunc, 
+                                void(float) _exitfunc)
+{
+    if not (_owner.vehicle_flags & VHF_MULTISLOT)
+        _owner.vehicle_flags |= VHF_MULTISLOT;
+
+    _slot.PlayerPhysplug = _framefunc;
+    _slot.vehicle_exit = _exitfunc;
+    _slot.hud = _hud;
+    _slot.vehicle_flags = VHF_PLAYERSLOT;
+    _slot.vehicle_viewport = spawn();
+    _slot.vehicle_hudmodel = spawn();
+    _slot.vehicle_hudmodel.viewmodelforclient = _slot;
+    _slot.vehicle_viewport.effects = (EF_ADDITIVE | EF_DOUBLESIDED | EF_FULLBRIGHT | EF_NODEPTHTEST | EF_NOGUNBOB | EF_NOSHADOW | EF_LOWPRECISION | EF_SELECTABLE | EF_TELEPORT_BIT);
+    
+    setmodel(_slot.vehicle_hudmodel, _hud_model);
+    setmodel(_slot.vehicle_viewport, "null");
+    
+    setattachment(_slot.vehicle_hudmodel, _slot, "");
+    setattachment(_slot.vehicle_viewport, _slot.vehicle_hudmodel, "");
+    
+    return TRUE;
+}
+
 float vehicle_initialize(string  net_name,
                          string  bodymodel,
                          string  topmodel,
@@ -936,24 +1176,55 @@ float vehicle_initialize(string  net_name,
                          vector  min_s,
                          vector  max_s,
                          float   nodrop,
-                         void()  spawnproc,
+                         void(float _spawnflag)  spawnproc,
                          float   _respawntime,
                          float() physproc,
                          void()  enterproc,
                          void(float extflag) exitfunc,
                          void() dieproc,
                          void() thinkproc,
-                         float  use_csqc)
+                         float  use_csqc,
+                         float _max_health,
+                         float _max_shield)
 {
+       if(!autocvar_g_vehicles)
+               return FALSE;
+       
+    if(self.targetname)
+    {
+        self.vehicle_controller = find(world, target, self.targetname);
+        if(!self.vehicle_controller)
+        {
+            bprint("^1WARNING: ^7Vehicle with invalid .targetname\n");
+        }
+        else
+        {
+            self.team = self.vehicle_controller.team;        
+            self.use = vehicle_use;
+            
+            if(teamplay)
+            {
+                if(self.vehicle_controller.team == 0)
+                    self.active = ACTIVE_NOT;
+                else
+                    self.active = ACTIVE_ACTIVE;                
+            }
+        }
+    }
+    
+    precache_sound("onslaught/ons_hit2.wav");
+    precache_sound("onslaught/electricity_explode.wav");
+
+
     addstat(STAT_HUD, AS_INT,  hud);
        addstat(STAT_VEHICLESTAT_HEALTH,  AS_INT, vehicle_health);
        addstat(STAT_VEHICLESTAT_SHIELD,  AS_INT, vehicle_shield);
        addstat(STAT_VEHICLESTAT_ENERGY,  AS_INT, vehicle_energy);
 
-       addstat(STAT_VEHICLESTAT_AMMO1,   AS_INT,   vehicle_ammo1);
+       addstat(STAT_VEHICLESTAT_AMMO1,   AS_INT, vehicle_ammo1);
        addstat(STAT_VEHICLESTAT_RELOAD1, AS_INT, vehicle_reload1);
 
-       addstat(STAT_VEHICLESTAT_AMMO2,   AS_INT,   vehicle_ammo2);
+       addstat(STAT_VEHICLESTAT_AMMO2,   AS_INT, vehicle_ammo2);
        addstat(STAT_VEHICLESTAT_RELOAD2, AS_INT, vehicle_reload2);
 
     if(bodymodel == "")
@@ -969,9 +1240,9 @@ float vehicle_initialize(string  net_name,
 
     if(self.team && !teamplay)
         self.team = 0;
-        
+
     self.vehicle_flags |= VHF_ISVEHICLE;
-    
+
     setmodel(self, bodymodel);
 
     self.vehicle_viewport   = spawn();
@@ -984,17 +1255,24 @@ float vehicle_initialize(string  net_name,
     self.teleportable       = FALSE; // no teleporting for vehicles, too buggy
     self.damagedbycontents     = TRUE;
     self.hud                = vhud;
-
+    self.tur_health          = _max_health;
+    self.tur_head.tur_health = _max_shield;
     self.vehicle_die         = dieproc;
     self.vehicle_exit        = exitfunc;
     self.vehicle_enter       = enterproc;
     self.PlayerPhysplug      = physproc;
     self.event_damage        = vehicles_damage;
     self.touch               = vehicles_touch;
-    self.think               = vehicles_spawn;    
-    self.nextthink           = time;        
+    self.think               = vehicles_spawn;
+    self.nextthink           = time;
     self.vehicle_respawntime = _respawntime;
     self.vehicle_spawn       = spawnproc;
+    self.effects             = EF_NODRAW;
+    if(g_assault || !autocvar_g_vehicles_delayspawn)
+        self.nextthink = time + 0.5;
+    else
+        self.nextthink = time + _respawntime + (random() * autocvar_g_vehicles_delayspawn_jitter);
+
 
     if(autocvar_g_nodepthtestplayers)
         self.effects = self.effects | EF_NODEPTHTEST;
@@ -1005,7 +1283,6 @@ float vehicle_initialize(string  net_name,
     setmodel(self.vehicle_hudmodel, hudmodel);
     setmodel(self.vehicle_viewport, "null");
 
-
     if(topmodel != "")
     {
         setmodel(self.tur_head, topmodel);
@@ -1027,19 +1304,98 @@ float vehicle_initialize(string  net_name,
         tracebox(self.origin + '0 0 100', min_s, max_s, self.origin - '0 0 10000', MOVE_WORLDONLY, self);
         setorigin(self, trace_endpos);
     }
-
+    
     self.pos1 = self.origin;
     self.pos2 = self.angles;
     self.tur_head.team = self.team;
-    
+
     return TRUE;
 }
 
-void bugmenot()
+vector vehicle_aimturret(entity _vehic, vector _target, entity _turrret, string _tagname, 
+                         float _pichlimit_min, float _pichlimit_max, 
+                         float _rotlimit_min, float _rotlimit_max, float _aimspeed)
 {
-    self.vehicle_exit       = self.vehicle_exit;
-    self.vehicle_enter      = self.vehicle_exit;
-    self.vehicle_die        = self.vehicle_exit;
-    self.vehicle_spawn      = self.vehicle_exit;
-    self.AuxiliaryXhair     = self.AuxiliaryXhair;
+    vector vtmp, vtag;
+    float ftmp;
+    vtag = gettaginfo(_turrret, gettagindex(_turrret, _tagname));
+    vtmp = vectoangles(normalize(_target - vtag));
+    vtmp = AnglesTransform_ToAngles(AnglesTransform_LeftDivide(AnglesTransform_FromAngles(_vehic.angles), AnglesTransform_FromAngles(vtmp))) - _turrret.angles;
+    vtmp = AnglesTransform_Normalize(vtmp, TRUE);
+    ftmp = _aimspeed * frametime;
+    vtmp_y = bound(-ftmp, vtmp_y, ftmp);
+    vtmp_x = bound(-ftmp, vtmp_x, ftmp);
+    _turrret.angles_y = bound(_rotlimit_min, _turrret.angles_y + vtmp_y, _rotlimit_max);    
+    _turrret.angles_x = bound(_pichlimit_min, _turrret.angles_x + vtmp_x, _pichlimit_max);
+    return vtag;
 }
+
+void vehicles_gib_explode()
+{
+       sound (self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
+       pointparticles(particleeffectnum("explosion_small"), randomvec() * 80 + (self.origin + '0 0 100'), '0 0 0', 1);
+       remove(self);
+}
+
+void vehicles_gib_think()
+{
+       self.alpha -= 0.1;
+       if(self.cnt >= time)
+               remove(self);
+       else
+               self.nextthink = time + 0.1;
+}
+
+entity vehicle_tossgib(entity _template, vector _vel, string _tag, float _burn, float _explode, float _maxtime, vector _rot)
+{
+       entity _gib = spawn();
+       setmodel(_gib, _template.model);
+       setorigin(_gib, gettaginfo(self, gettagindex(self, _tag)));
+       _gib.velocity = _vel;
+       _gib.movetype = MOVETYPE_TOSS;
+       _gib.solid = SOLID_CORPSE;
+       _gib.colormod = '-0.5 -0.5 -0.5';
+       _gib.effects = EF_LOWPRECISION; 
+       _gib.avelocity = _rot;
+       
+       if(_burn)
+               _gib.effects |= EF_FLAME;
+       
+       if(_explode)
+       {
+               _gib.think = vehicles_gib_explode; 
+               _gib.nextthink = time + random() * _explode;
+               _gib.touch = vehicles_gib_explode;
+       }
+       else
+       {
+               _gib.cnt = time + _maxtime;
+               _gib.think = vehicles_gib_think; 
+               _gib.nextthink = time + _maxtime - 1;           
+               _gib.alpha = 1;
+       }
+       return _gib;
+}
+
+/*
+vector predict_target(entity _targ, vector _from, float _shot_speed)
+{
+    float i;                // loop
+    float _distance;        // How far to target
+    float _impact_time;     // How long untill projectile impacts
+    vector _predict_pos;    // Predicted enemy location
+    vector _original_origin;// Where target is before predicted
+
+     _original_origin = real_origin(_targ); // Typicaly center of target BBOX
+
+    _predict_pos = _original_origin;
+    for(i = 0; i < 4; ++i)  // Loop a few times to increase prediction accuracy (increase loop count if accuracy is to low)
+    {
+        _distance = vlen(_predict_pos - _from); // Get distance to previos predicted location
+        _impact_time = _distance / _shot_speed; // Calculate impact time
+        _predict_pos = _original_origin + _targ.velocity * _impact_time; // Calculate new predicted location
+    }
+
+    return _predict_pos;
+}
+*/