]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/vehicles/sv_vehicles.qc
Use the constants for player hitbox size when applicable (should fix observer hitbox)
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / vehicles / sv_vehicles.qc
index 3d94aa51fb694fca9327f3d4cc8aef911aa86cb6..9c8d05ce4e0fef38a8ecd06999c923f290d69804 100644 (file)
@@ -1,83 +1,62 @@
 #include "sv_vehicles.qh"
 
-#if 0
-bool vehicle_send(entity to, int sf)
+bool SendAuxiliaryXhair(entity this, entity to, int sf)
 {
-       WriteByte(MSG_ENTITY, ENT_CLIENT_VEHICLE);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_AUXILIARYXHAIR);
        WriteByte(MSG_ENTITY, sf);
 
-       if(sf & VSF_SPAWN)
-       {
-               WriteByte(MSG_ENTITY, self.vehicleid);
-       }
-
-       if(sf & VSF_SETUP)
-       {
-               // send stuff?
-       }
-
-       if(sf & VSF_ENTER)
-       {
-               // player handles the .vehicle stuff, we need only set ourselves up for driving
-
-               // send stuff?
-       }
+       WriteByte(MSG_ENTITY, this.cnt);
 
-       if(sf & VSF_EXIT)
+       if(sf & 2)
        {
-               // senf stuff?
+               WriteCoord(MSG_ENTITY, this.origin_x);
+               WriteCoord(MSG_ENTITY, this.origin_y);
+               WriteCoord(MSG_ENTITY, this.origin_z);
        }
 
-       if(sf & VSF_PRECACHE)
+       if(sf & 4)
        {
-               // send stuff?!
+               WriteByte(MSG_ENTITY, rint(this.colormod_x * 255));
+               WriteByte(MSG_ENTITY, rint(this.colormod_y * 255));
+               WriteByte(MSG_ENTITY, rint(this.colormod_z * 255));
        }
 
        return true;
 }
-#endif
-
-bool SendAuxiliaryXhair(entity this, entity to, int sf)
-{
-
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_AUXILIARYXHAIR);
 
-       WriteByte(MSG_ENTITY, this.cnt);
-
-       WriteCoord(MSG_ENTITY, this.origin_x);
-       WriteCoord(MSG_ENTITY, this.origin_y);
-       WriteCoord(MSG_ENTITY, this.origin_z);
-
-       WriteByte(MSG_ENTITY, rint(this.colormod_x * 255));
-       WriteByte(MSG_ENTITY, rint(this.colormod_y * 255));
-       WriteByte(MSG_ENTITY, rint(this.colormod_z * 255));
-
-       return true;
-}
+.vector axh_prevorigin;
+.vector axh_prevcolors;
 
 void UpdateAuxiliaryXhair(entity own, vector loc, vector clr, int axh_id)
 {
        if(!IS_REAL_CLIENT(own))
                return;
 
-       entity axh;
-
        axh_id = bound(0, axh_id, MAX_AXH);
-       axh = own.(AuxiliaryXhair[axh_id]);
+       entity axh = own.(AuxiliaryXhair[axh_id]);
 
-       if(axh == world || wasfreed(axh))  // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?)
+       if(axh == NULL || wasfreed(axh))  // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist? Mario: because of sloppy code like this)
        {
-               axh                                      = spawn();
-               axh.cnt                          = axh_id;
-               axh.drawonlytoclient    = own;
-               axh.owner                          = own;
+               axh = new(auxiliary_xhair);
+               axh.cnt = axh_id;
+               axh.drawonlytoclient = own;
+               axh.owner = own;
                Net_LinkEntity(axh, false, 0, SendAuxiliaryXhair);
        }
 
-       setorigin(axh, loc);
-       axh.colormod                    = clr;
-       axh.SendFlags              = 0x01;
-       own.(AuxiliaryXhair[axh_id]) = axh;
+       if(loc != axh.axh_prevorigin)
+       {
+               setorigin(axh, loc);
+               axh.SendFlags |= 2;
+       }
+
+       if(clr != axh.axh_prevcolors)
+       {
+               axh.colormod = clr;
+               axh.SendFlags |= 4;
+       }
+
+       own.(AuxiliaryXhair[axh_id]) = axh; // set it anyway...?
 }
 
 void CSQCVehicleSetup(entity own, int vehicle_id)
@@ -95,7 +74,7 @@ void vehicles_locktarget(entity this, float incr, float decr, float _lock_time)
 {
        if(this.lock_target && IS_DEAD(this.lock_target))
        {
-               this.lock_target        = world;
+               this.lock_target        = NULL;
                this.lock_strength  = 0;
                this.lock_time    = 0;
        }
@@ -112,22 +91,22 @@ void vehicles_locktarget(entity this, float incr, float decr, float _lock_time)
                return;
        }
 
-       if(trace_ent != world)
+       if(trace_ent != NULL)
        {
                if(SAME_TEAM(trace_ent, this))
-                       trace_ent = world;
+                       trace_ent = NULL;
 
                if(IS_DEAD(trace_ent))
-                       trace_ent = world;
+                       trace_ent = NULL;
 
                if(!(IS_VEHICLE(trace_ent) || IS_TURRET(trace_ent)))
-                       trace_ent = world;
+                       trace_ent = NULL;
 
                if(trace_ent.alpha <= 0.5 && trace_ent.alpha != 0)
-                       trace_ent = world; // invisible
+                       trace_ent = NULL; // invisible
        }
 
-       if(this.lock_target == world && trace_ent != world)
+       if(this.lock_target == NULL && trace_ent != NULL)
                this.lock_target = trace_ent;
 
        if(this.lock_target && trace_ent == this.lock_target)
@@ -146,7 +125,7 @@ void vehicles_locktarget(entity this, float incr, float decr, float _lock_time)
 
        // Have a locking target
        // Trace hit current target
-       if(trace_ent == this.lock_target && trace_ent != world)
+       if(trace_ent == this.lock_target && trace_ent != NULL)
        {
                this.lock_strength = min(this.lock_strength + incr, 1);
                if(this.lock_strength == 1)
@@ -160,10 +139,16 @@ void vehicles_locktarget(entity this, float incr, float decr, float _lock_time)
                        this.lock_strength = max(this.lock_strength - decr, 0);
 
                if(this.lock_strength == 0)
-                       this.lock_target = world;
+                       this.lock_target = NULL;
        }
 }
 
+float vehicle_altitude(entity this, float amax)
+{
+       tracebox(this.origin, this.mins, this.maxs, this.origin - ('0 0 1' * amax), MOVE_WORLDONLY, this);
+       return vlen(this.origin - trace_endpos);
+}
+
 vector vehicles_force_fromtag_hover(entity this, string tag_name, float spring_length, float max_power)
 {
        force_fromtag_origin = gettaginfo(this, gettagindex(this, tag_name));
@@ -213,28 +198,33 @@ void vehicles_projectile_damage(entity this, entity inflictor, entity attacker,
        }
 }
 
-void vehicles_projectile_explode(entity this)
+void vehicles_projectile_explode(entity this, entity toucher)
 {
-       if(self.owner && other != world)
+       if(this.owner && toucher != NULL)
        {
-               if(other == self.owner.vehicle)
+               if(toucher == this.owner.vehicle)
                        return;
 
-               if(other == self.owner.vehicle.tur_head)
+               if(toucher == this.owner.vehicle.tur_head)
                        return;
        }
 
-       PROJECTILE_TOUCH(this);
+       PROJECTILE_TOUCH(this, toucher);
 
-       self.event_damage = func_null;
-       RadiusDamage (self, self.realowner, self.shot_dmg, 0, self.shot_radius, self, world, self.shot_force, self.totalfrags, other);
+       this.event_damage = func_null;
+       RadiusDamage (this, this.realowner, this.shot_dmg, 0, this.shot_radius, this, NULL, this.shot_force, this.totalfrags, toucher);
 
-       remove (self);
+       delete (this);
+}
+
+void vehicles_projectile_explode_think(entity this)
+{
+       vehicles_projectile_explode(this, NULL);
 }
 
 void vehicles_projectile_explode_use(entity this, entity actor, entity trigger)
 {
-       WITHSELF(this, vehicles_projectile_explode(this));
+       vehicles_projectile_explode(this, trigger);
 }
 
 entity vehicles_projectile(entity this, string _mzlfx, Sound _mzlsound,
@@ -256,8 +246,10 @@ entity vehicles_projectile(entity this, string _mzlfx, Sound _mzlsound,
        proj.shot_force    = _force;
        proj.totalfrags    = _deahtype;
        proj.solid                      = SOLID_BBOX;
-       proj.movetype            = MOVETYPE_FLYMISSILE;
-       proj.flags                      = FL_PROJECTILE;
+       set_movetype(proj, MOVETYPE_FLYMISSILE);
+       proj.flags = FL_PROJECTILE;
+       IL_PUSH(g_projectiles, proj);
+       IL_PUSH(g_bot_dodge, proj);
        proj.bot_dodge          = true;
        proj.bot_dodgerating  = _dmg;
        proj.velocity            = _vel;
@@ -275,7 +267,7 @@ entity vehicles_projectile(entity this, string _mzlfx, Sound _mzlsound,
                proj.health                = _health;
        }
        else
-               proj.flags                 = FL_PROJECTILE | FL_NOTARGET;
+               proj.flags |= FL_NOTARGET;
 
        if(_mzlsound != SND_Null)
                sound (this, CH_WEAPON_A, _mzlsound, VOL_BASE, ATTEN_NORM);
@@ -292,19 +284,24 @@ entity vehicles_projectile(entity this, string _mzlfx, Sound _mzlsound,
 
 void vehicles_gib_explode(entity this)
 {
-       sound (self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
-       Send_Effect(EFFECT_EXPLOSION_SMALL, randomvec() * 80 + (self.origin + '0 0 100'), '0 0 0', 1);
-       Send_Effect(EFFECT_EXPLOSION_SMALL, self.wp00.origin + '0 0 64', '0 0 0', 1);
-       remove(self);
+       sound (this, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+       Send_Effect(EFFECT_EXPLOSION_SMALL, randomvec() * 80 + (this.origin + '0 0 100'), '0 0 0', 1);
+       Send_Effect(EFFECT_EXPLOSION_SMALL, this.wp00.origin + '0 0 64', '0 0 0', 1);
+       delete(this);
+}
+
+void vehicles_gib_touch(entity this, entity toucher)
+{
+       vehicles_gib_explode(this);
 }
 
 void vehicles_gib_think(entity this)
 {
-       self.alpha -= 0.1;
-       if(self.cnt >= time)
-               remove(self);
+       this.alpha -= 0.1;
+       if(this.cnt >= time)
+               delete(this);
        else
-               self.nextthink = time + 0.1;
+               this.nextthink = time + 0.1;
 }
 
 entity vehicle_tossgib(entity this, entity _template, vector _vel, string _tag, bool _burn, bool _explode, float _maxtime, vector _rot)
@@ -314,7 +311,7 @@ entity vehicle_tossgib(entity this, entity _template, vector _vel, string _tag,
        vector org = gettaginfo(this, gettagindex(this, _tag));
        setorigin(_gib, org);
        _gib.velocity = _vel;
-       _gib.movetype = MOVETYPE_TOSS;
+       set_movetype(_gib, MOVETYPE_TOSS);
        _gib.solid = SOLID_CORPSE;
        _gib.colormod = '-0.5 -0.5 -0.5';
        _gib.effects = EF_LOWPRECISION;
@@ -327,7 +324,7 @@ entity vehicle_tossgib(entity this, entity _template, vector _vel, string _tag,
        {
                setthink(_gib, vehicles_gib_explode);
                _gib.nextthink = time + random() * _explode;
-               settouch(_gib, vehicles_gib_explode);
+               settouch(_gib, vehicles_gib_touch);
        }
        else
        {
@@ -343,7 +340,7 @@ bool vehicle_addplayerslot( entity _owner,
                                                                entity _slot,
                                                                int _hud,
                                                                Model _hud_model,
-                                                               bool(entity) _framefunc,
+                                                               bool(entity,float) _framefunc,
                                                                void(entity,bool) _exitfunc, float(entity, entity) _enterfunc)
 {
        if(!(_owner.vehicle_flags & VHF_MULTISLOT))
@@ -436,50 +433,43 @@ void vehicles_reset_colors(entity this)
 
 void vehicles_clearreturn(entity veh)
 {
-       // Remove "return helper", if any.
-       for (entity ret = findchain(classname, "vehicle_return"); ret; ret = ret.chain)
+       // Remove "return helper" entities, if any.
+       IL_EACH(g_vehicle_returners, it.wp00 == veh,
        {
-               if(ret.wp00 == veh)
-               {
-                       ret.classname   = "";
-                       setthink(ret, SUB_Remove);
-                       ret.nextthink   = time + 0.1;
-
-                       if(ret.waypointsprite_attached)
-                               WaypointSprite_Kill(ret.waypointsprite_attached);
+               it.classname = "";
+               setthink(it, SUB_Remove);
+               it.nextthink = time + 0.1;
+               IL_REMOVE(g_vehicle_returners, it);
 
-                       return;
-               }
-       }
+               if(it.waypointsprite_attached)
+                       WaypointSprite_Kill(it.waypointsprite_attached);
+       });
 }
 
 void vehicles_spawn(entity this);
 void vehicles_return(entity this)
 {
-       Send_Effect(EFFECT_TELEPORT, self.wp00.origin + '0 0 64', '0 0 0', 1);
+       Send_Effect(EFFECT_TELEPORT, this.wp00.origin + '0 0 64', '0 0 0', 1);
 
-       setthink(self.wp00, vehicles_spawn);
-       self.wp00.nextthink = time;
+       setthink(this.wp00, vehicles_spawn);
+       this.wp00.nextthink = time;
 
-       if(self.waypointsprite_attached)
-               WaypointSprite_Kill(self.waypointsprite_attached);
+       if(this.waypointsprite_attached)
+               WaypointSprite_Kill(this.waypointsprite_attached);
 
-       remove(self);
+       delete(this);
 }
 
 void vehicles_showwp_goaway(entity this)
 {
-       if(self.waypointsprite_attached)
-               WaypointSprite_Kill(self.waypointsprite_attached);
-
-       remove(self);
+       if(this.waypointsprite_attached)
+               WaypointSprite_Kill(this.waypointsprite_attached);
 
+       delete(this);
 }
 
 void vehicles_showwp(entity this)
 {
-       vector rgb;
-
        entity ent = this;
 
        if(ent.cnt)
@@ -493,7 +483,6 @@ void vehicles_showwp(entity this)
                ent.nextthink  = time + 1;
 
                ent = spawn();
-               setmodel(ent, MDL_Null);
                ent.team = this.wp00.team;
                ent.wp00 = this.wp00;
                setorigin(ent, this.wp00.pos1);
@@ -502,11 +491,12 @@ void vehicles_showwp(entity this)
                setthink(ent, vehicles_showwp_goaway);
        }
 
+       vector rgb;
        if(teamplay && ent.team)
                rgb = Team_ColorRGB(ent.team);
        else
                rgb = '1 1 1';
-       entity wp = WaypointSprite_Spawn(WP_Vehicle, 0, 0, ent, '0 0 64', world, 0, ent, waypointsprite_attached, true, RADARICON_Vehicle);
+       entity wp = WaypointSprite_Spawn(WP_Vehicle, 0, 0, ent, '0 0 64', NULL, 0, ent, waypointsprite_attached, true, RADARICON_Vehicle);
        wp.colormod = rgb;
        if(ent.waypointsprite_attached)
        {
@@ -519,11 +509,10 @@ void vehicles_showwp(entity this)
 
 void vehicles_setreturn(entity veh)
 {
-       entity ret;
-
        vehicles_clearreturn(veh);
 
-       ret = new(vehicle_return);
+       entity ret = new(vehicle_return);
+       IL_PUSH(g_vehicle_returners, ret);
        ret.wp00           = veh;
        ret.team                = veh.team;
        setthink(ret, vehicles_showwp);
@@ -538,14 +527,12 @@ void vehicles_setreturn(entity veh)
                ret.nextthink   = min(time + veh.respawntime, time + veh.respawntime - 1);
        }
 
-       setmodel(ret, MDL_Null);
        setorigin(ret, veh.pos1 + '0 0 96');
-
 }
 
 void vehicle_use(entity this, entity actor, entity trigger)
 {
-       LOG_TRACE("vehicle ",this.netname, " used by ", actor.classname, "\n");
+       LOG_DEBUG("vehicle ", this.netname, " used by ", actor.classname);
 
        this.tur_head.team = actor.team;
 
@@ -556,7 +543,7 @@ void vehicle_use(entity this, entity actor, entity trigger)
 
        if(this.active == ACTIVE_ACTIVE && !IS_DEAD(this) && !gameover)
        {
-               LOG_TRACE("Respawning vehicle: ", this.netname, "\n");
+               LOG_DEBUG("Respawning vehicle: ", this.netname);
                if(this.effects & EF_NODRAW)
                {
                        setthink(this, vehicles_spawn);
@@ -587,16 +574,16 @@ void vehicles_regen(entity this, float timer, .float regen_field, float field_ma
 
 void shieldhit_think(entity this)
 {
-       self.alpha -= 0.1;
-       if (self.alpha <= 0)
+       this.alpha -= 0.1;
+       if (this.alpha <= 0)
        {
-               // setmodel(self, MDL_Null);
-               self.alpha = -1;
-               self.effects |= EF_NODRAW;
+               // setmodel(this, MDL_Null);
+               this.alpha = -1;
+               this.effects |= EF_NODRAW;
        }
        else
        {
-               self.nextthink = time + 0.1;
+               this.nextthink = time + 0.1;
        }
 }
 
@@ -634,20 +621,15 @@ void vehicles_damage(entity this, entity inflictor, entity attacker, float damag
        // WEAPONTODO
        if(DEATH_ISWEAPON(deathtype, WEP_VORTEX))
                damage *= autocvar_g_vehicles_vortex_damagerate;
-
-       if(DEATH_ISWEAPON(deathtype, WEP_MACHINEGUN))
+       else if(DEATH_ISWEAPON(deathtype, WEP_MACHINEGUN))
                damage *= autocvar_g_vehicles_machinegun_damagerate;
-
-       if(DEATH_ISWEAPON(deathtype, WEP_RIFLE))
+       else if(DEATH_ISWEAPON(deathtype, WEP_RIFLE))
                damage *= autocvar_g_vehicles_rifle_damagerate;
-
-       if(DEATH_ISWEAPON(deathtype, WEP_VAPORIZER))
+       else if(DEATH_ISWEAPON(deathtype, WEP_VAPORIZER))
                damage *= autocvar_g_vehicles_vaporizer_damagerate;
-
-       if(DEATH_ISWEAPON(deathtype, WEP_SEEKER))
+       else if(DEATH_ISWEAPON(deathtype, WEP_SEEKER))
                damage *= autocvar_g_vehicles_tag_damagerate;
-
-       if(DEATH_WEAPONOF(deathtype) != WEP_Null)
+       else if(DEATH_WEAPONOF(deathtype) != WEP_Null)
                damage *= autocvar_g_vehicles_weapon_damagerate;
 
        this.enemy = attacker;
@@ -656,7 +638,7 @@ void vehicles_damage(entity this, entity inflictor, entity attacker, float damag
 
        if((this.vehicle_flags & VHF_HASSHIELD) && (this.vehicle_shield > 0))
        {
-               if (wasfreed(this.vehicle_shieldent) || this.vehicle_shieldent == world)
+               if (wasfreed(this.vehicle_shieldent) || this.vehicle_shieldent == NULL)
                {
                        this.vehicle_shieldent = spawn();
                        this.vehicle_shieldent.effects = EF_LOWPRECISION;
@@ -721,7 +703,7 @@ void vehicles_damage(entity this, entity inflictor, entity attacker, float damag
        }
 }
 
-float vehicles_crushable(entity e)
+bool vehicles_crushable(entity e)
 {
        if(IS_PLAYER(e) && time >= e.vehicle_enter_delay)
                return true;
@@ -745,7 +727,7 @@ void vehicles_impact(entity this, float _minspeed, float _speedfac, float _maxpa
                if(_minspeed < wc)
                {
                        float take = min(_speedfac * wc, _maxpain);
-                       Damage (this, world, world, take, DEATH_FALL.m_id, this.origin, '0 0 0');
+                       Damage (this, NULL, NULL, take, DEATH_FALL.m_id, this.origin, '0 0 0');
                        this.play_time = time + 0.25;
 
                        //dprint("wc: ", ftos(wc), "\n");
@@ -757,49 +739,24 @@ void vehicles_impact(entity this, float _minspeed, float _speedfac, float _maxpa
 // vehicle enter/exit handling
 vector vehicles_findgoodexit(entity this, vector prefer_spot)
 {
-       //vector exitspot;
-       float mysize;
-
-       tracebox(this.origin + '0 0 32', STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), prefer_spot, MOVE_NORMAL, this.owner);
+       // TODO: we actually want the player's size here
+       tracebox(this.origin + '0 0 32', PL_MIN_CONST, PL_MAX_CONST, prefer_spot, MOVE_NORMAL, this.owner);
        if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
                return prefer_spot;
 
-       mysize = 1.5 * vlen(this.maxs - this.mins);
-       float i;
-       vector v, v2;
-       v2 = 0.5 * (this.absmin + this.absmax);
-       for(i = 0; i < 100; ++i)
+       float mysize = 1.5 * vlen(this.maxs - this.mins);
+       vector v;
+       vector v2 = 0.5 * (this.absmin + this.absmax);
+       for(int i = 0; i < autocvar_g_vehicles_exit_attempts; ++i)
        {
                v = randomvec();
                v_z = 0;
                v = v2 + normalize(v) * mysize;
-               tracebox(v2, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), v, MOVE_NORMAL, this.owner);
+               tracebox(v2, PL_MIN_CONST, PL_MAX_CONST, v, MOVE_NORMAL, this.owner);
                if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
                        return v;
        }
 
-       /*
-       exitspot = (this.origin + '0 0 48') + v_forward * mysize;
-       tracebox(this.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, this.owner);
-       if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
-               return exitspot;
-
-       exitspot = (this.origin + '0 0 48') - v_forward * mysize;
-       tracebox(this.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, this.owner);
-       if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
-               return exitspot;
-
-       exitspot = (this.origin + '0 0 48') + v_right * mysize;
-       tracebox(this.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, this.owner);
-       if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
-               return exitspot;
-
-       exitspot = (this.origin + '0 0 48') - v_right * mysize;
-       tracebox(this.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, this.owner);
-       if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
-               return exitspot;
-       */
-
        return this.origin;
 }
 
@@ -809,7 +766,7 @@ void vehicles_exit(entity vehic, bool eject)
 
        if(vehicles_exit_running)
        {
-               LOG_TRACE("^1vehicles_exit already running! this is not good...\n");
+               LOG_TRACE("^1vehicles_exit already running! this is not good...");
                return;
        }
 
@@ -837,17 +794,17 @@ void vehicles_exit(entity vehic, bool eject)
                        WriteAngle(MSG_ONE, 0);
                }
 
-               setsize(player, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL));
+               setsize(player, STAT(PL_MIN,player), STAT(PL_MAX, player));
 
                player.takedamage               = DAMAGE_AIM;
                player.solid                    = SOLID_SLIDEBOX;
-               player.movetype         = MOVETYPE_WALK;
+               set_movetype(player, MOVETYPE_WALK);
                player.effects             &= ~EF_NODRAW;
                player.teleportable     = TELEPORT_NORMAL;
                player.alpha                    = 1;
                player.PlayerPhysplug   = func_null;
-               player.vehicle                  = world;
-               player.view_ofs         = STAT(PL_VIEW_OFS, NULL);
+               player.vehicle                  = NULL;
+               player.view_ofs         = STAT(PL_VIEW_OFS, player);
                player.event_damage     = PlayerDamage;
                player.hud                              = HUD_NORMAL;
                PS(player).m_switchweapon = vehic.m_switchweapon;
@@ -865,7 +822,7 @@ void vehicles_exit(entity vehic, bool eject)
        if(!IS_DEAD(vehic))
                vehic.avelocity = '0 0 0';
 
-       vehic.tur_head.nodrawtoclient = world;
+       vehic.tur_head.nodrawtoclient = NULL;
 
        if(!teamplay)
                vehic.team = 0;
@@ -884,35 +841,35 @@ void vehicles_exit(entity vehic, bool eject)
 
        vehicles_setreturn(vehic);
        vehicles_reset_colors(vehic);
-       vehic.owner = world;
+       vehic.owner = NULL;
 
        CSQCMODEL_AUTOINIT(vehic);
 
        vehicles_exit_running = false;
 }
 
-void vehicles_touch(entity this)
+void vehicles_touch(entity this, entity toucher)
 {
-       if(MUTATOR_CALLHOOK(VehicleTouch, self, other))
+       if(MUTATOR_CALLHOOK(VehicleTouch, this, toucher))
                return;
 
        // Vehicle currently in use
-       if(self.owner)
+       if(this.owner)
        {
-               if(!forbidWeaponUse(self.owner))
-               if(other != world)
-               if((self.origin_z + self.maxs_z) > (other.origin_z))
-               if(vehicles_crushable(other))
+               if(!forbidWeaponUse(this.owner))
+               if(toucher != NULL)
+               if((this.origin_z + this.maxs_z) > (toucher.origin_z))
+               if(vehicles_crushable(toucher))
                {
-                       if(vdist(self.velocity, >=, 30))
-                               Damage(other, self, self.owner, autocvar_g_vehicles_crush_dmg, DEATH_VH_CRUSH.m_id, '0 0 0', normalize(other.origin - self.origin) * autocvar_g_vehicles_crush_force);
+                       if(vdist(this.velocity, >=, 30))
+                               Damage(toucher, this, this.owner, autocvar_g_vehicles_crush_dmg, DEATH_VH_CRUSH.m_id, '0 0 0', normalize(toucher.origin - this.origin) * autocvar_g_vehicles_crush_force);
 
                        return; // Dont do selfdamage when hitting "soft targets".
                }
 
-               if(self.play_time < time) {
-                       Vehicle info = Vehicles_from(self.vehicleid);
-                       info.vr_impact(info, self);
+               if(this.play_time < time) {
+                       Vehicle info = Vehicles_from(this.vehicleid);
+                       info.vr_impact(info, this);
                }
 
                return;
@@ -921,7 +878,7 @@ void vehicles_touch(entity this)
        if(autocvar_g_vehicles_enter)
                return;
 
-       vehicles_enter(other, self);
+       vehicles_enter(toucher, this);
 }
 
 bool vehicle_impulse(entity this, int imp)
@@ -935,7 +892,7 @@ bool vehicle_impulse(entity this, int imp)
        {
                case IMP_weapon_drop.impulse:
                {
-                       stuffcmd(self, "\ntoggle cl_eventchase_vehicle\nset _vehicles_shownchasemessage 1\n");
+                       stuffcmd(this, "\ntoggle cl_eventchase_vehicle\nset _vehicles_shownchasemessage 1\n");
                        return true;
                }
        }
@@ -956,23 +913,20 @@ void vehicles_enter(entity pl, entity veh)
        || (pl.vehicle)
        ) { return; }
 
+       Vehicle info = Vehicles_from(veh.vehicleid);
+
        if(autocvar_g_vehicles_enter) // vehicle's touch function should handle this if entering via use key is disabled (TODO)
        if(veh.vehicle_flags & VHF_MULTISLOT)
-       if(veh.owner)
+       if(veh.owner && SAME_TEAM(pl, veh))
        {
-               if(!veh.gunner1)
-               if(time >= veh.gun1.phase)
-               if(veh.gun1.vehicle_enter)
-               if(veh.gun1.vehicle_enter(veh, pl))
-                       return;
-
-               if(!veh.gunner2)
-               if(time >= veh.gun2.phase)
-               if(veh.gun2.vehicle_enter)
-               if(veh.gun2.vehicle_enter(veh, pl))
-                       return;
+               // we don't need a return value or anything here
+               // if successful the owner check below will prevent anything weird
+               info.vr_gunner_enter(info, veh, pl);
        }
 
+       if(veh.owner)
+               return; // got here and didn't enter the gunner, return
+
        if(teamplay)
        if(veh.team)
        if(DIFF_TEAM(pl, veh))
@@ -983,7 +937,7 @@ void vehicles_enter(entity pl, entity veh)
                Send_Notification(NOTIF_ONE, pl, MSG_CENTER, CENTER_VEHICLE_STEAL_SELF);
 
                if (autocvar_g_vehicles_steal_show_waypoint) {
-                       entity wp = WaypointSprite_Spawn(WP_VehicleIntruder, 0, 0, pl, '0 0 68', world, veh.team, veh, wps_intruder, true, RADARICON_DANGER);
+                       entity wp = WaypointSprite_Spawn(WP_VehicleIntruder, 0, 0, pl, '0 0 68', NULL, veh.team, veh, wps_intruder, true, RADARICON_DANGER);
                        wp.colormod = Team_ColorRGB(pl.team);
                }
        }
@@ -1005,17 +959,17 @@ void vehicles_enter(entity pl, entity veh)
 
        veh.vehicle_hudmodel.viewmodelforclient = pl;
 
-       tracebox(pl.origin, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), pl.origin, false, pl);
        pl.crouch = false;
-       pl.view_ofs = STAT(PL_VIEW_OFS, NULL);
-       setsize (pl, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL));
+       pl.view_ofs = STAT(PL_VIEW_OFS, pl);
+       setsize (pl, STAT(PL_MIN, pl), STAT(PL_MAX, pl));
 
        veh.event_damage        = vehicles_damage;
        veh.nextthink           = 0;
        pl.angles                       = veh.angles;
        pl.takedamage           = DAMAGE_NO;
        pl.solid                        = SOLID_NOT;
-       pl.movetype                     = MOVETYPE_NOCLIP;
+       pl.disableclientprediction = 1; // physics is no longer run, so this won't be reset
+       set_movetype(pl, MOVETYPE_NOCLIP);
        pl.teleportable         = false;
        pl.alpha                        = -1;
        pl.event_damage         = func_null;
@@ -1073,74 +1027,87 @@ void vehicles_enter(entity pl, entity veh)
        MUTATOR_CALLHOOK(VehicleEnter, pl, veh);
 
        CSQCModel_UnlinkEntity(veh);
-       Vehicle info = Vehicles_from(veh.vehicleid);
-       WITHSELF(veh, info.vr_enter(info, veh));
+       info.vr_enter(info, veh);
 
        antilag_clear(pl, CS(pl));
 }
 
 void vehicles_think(entity this)
 {
-       self.nextthink = time;
+       this.nextthink = time + autocvar_g_vehicles_thinkrate;
+
+       if(this.owner)
+               this.owner.vehicle_weapon2mode = this.vehicle_weapon2mode;
+
+       Vehicle info = Vehicles_from(this.vehicleid);
+       info.vr_think(info, this);
+
+       vehicles_painframe(this);
 
-       if(self.owner)
-               self.owner.vehicle_weapon2mode = self.vehicle_weapon2mode;
+       CSQCMODEL_AUTOUPDATE(this);
+}
 
-       Vehicle info = Vehicles_from(self.vehicleid);
-       info.vr_think(info, self);
+void vehicles_reset(entity this)
+{
+       if(this.owner)
+               vehicles_exit(this, VHEF_RELEASE);
 
-       vehicles_painframe(self);
+       vehicles_clearreturn(this);
 
-       CSQCMODEL_AUTOUPDATE(self);
+       if(this.active != ACTIVE_NOT)
+               vehicles_spawn(this);
 }
 
 // initialization
 void vehicles_spawn(entity this)
 {
-       LOG_TRACE("Spawning vehicle: ", self.classname, "\n");
+       LOG_DEBUG("Spawning vehicle: ", this.classname);
 
        // disown & reset
-       self.vehicle_hudmodel.viewmodelforclient = self;
-
-       self.owner                              = world;
-       settouch(self, vehicles_touch);
-       self.event_damage               = vehicles_damage;
-       self.iscreature                 = true;
-       self.teleportable               = false; // no teleporting for vehicles, too buggy
-       self.damagedbycontents  = true;
-       self.movetype                   = MOVETYPE_WALK;
-       self.solid                              = SOLID_SLIDEBOX;
-       self.takedamage                 = DAMAGE_AIM;
-       self.deadflag                   = DEAD_NO;
-       self.bot_attack                 = true;
-       self.flags                              = FL_NOTARGET;
-       self.avelocity                  = '0 0 0';
-       self.velocity                   = '0 0 0';
-       setthink(self, vehicles_think);
-       self.nextthink                  = time;
+       this.vehicle_hudmodel.viewmodelforclient = this;
+
+       this.owner                              = NULL;
+       settouch(this, vehicles_touch);
+       this.event_damage               = vehicles_damage;
+       this.reset                              = vehicles_reset;
+       this.iscreature                 = true;
+       this.teleportable               = false; // no teleporting for vehicles, too buggy
+       this.damagedbycontents  = true;
+       set_movetype(this, MOVETYPE_WALK);
+       this.solid                              = SOLID_SLIDEBOX;
+       this.takedamage                 = DAMAGE_AIM;
+       this.deadflag                   = DEAD_NO;
+       if(!this.bot_attack)
+               IL_PUSH(g_bot_targets, this);
+       this.bot_attack                 = true;
+       this.flags                              = FL_NOTARGET;
+       this.avelocity                  = '0 0 0';
+       this.velocity                   = '0 0 0';
+       setthink(this, vehicles_think);
+       this.nextthink                  = time;
 
        // Reset locking
-       self.lock_strength = 0;
-       self.lock_target = world;
-       self.misc_bulletcounter = 0;
+       this.lock_strength = 0;
+       this.lock_target = NULL;
+       this.misc_bulletcounter = 0;
 
        // Return to spawn
-       self.angles = self.pos2;
-       setorigin(self, self.pos1);
+       this.angles = this.pos2;
+       setorigin(this, this.pos1);
        // Show it
-       Send_Effect(EFFECT_TELEPORT, self.origin + '0 0 64', '0 0 0', 1);
+       Send_Effect(EFFECT_TELEPORT, this.origin + '0 0 64', '0 0 0', 1);
 
-       if(self.vehicle_controller)
-               self.team = self.vehicle_controller.team;
+       if(this.vehicle_controller)
+               this.team = this.vehicle_controller.team;
 
-       FOREACH_CLIENT(IS_PLAYER(it) && it.hook.aiment == self, RemoveGrapplingHook(it));
+       FOREACH_CLIENT(IS_PLAYER(it) && it.hook.aiment == this, RemoveGrapplingHook(it));
 
-       vehicles_reset_colors(self);
+       vehicles_reset_colors(this);
 
-       Vehicle info = Vehicles_from(self.vehicleid);
-       info.vr_spawn(info, self);
+       Vehicle info = Vehicles_from(this.vehicleid);
+       info.vr_spawn(info, this);
 
-       CSQCMODEL_AUTOINIT(self);
+       CSQCMODEL_AUTOINIT(this);
 }
 
 bool vehicle_initialize(entity this, Vehicle info, bool nodrop)
@@ -1152,14 +1119,17 @@ bool vehicle_initialize(entity this, Vehicle info, bool nodrop)
                return false;
 
        if(!this.tur_head)
+       {
                info.vr_precache(info);
+               IL_PUSH(g_vehicles, this);
+       }
 
        if(this.targetname && this.targetname != "")
        {
-               this.vehicle_controller = find(world, target, this.targetname);
+               this.vehicle_controller = find(NULL, target, this.targetname);
                if(!this.vehicle_controller)
                {
-                       bprint("^1WARNING: ^7Vehicle with invalid .targetname\n");
+                       LOG_DEBUG("^1WARNING: ^7Vehicle with invalid .targetname");
                        this.active = ACTIVE_ACTIVE;
                }
                else
@@ -1194,9 +1164,11 @@ bool vehicle_initialize(entity this, Vehicle info, bool nodrop)
        this.tur_head.owner                     = this;
        this.takedamage                         = DAMAGE_NO;
        this.bot_attack                         = true;
+       IL_PUSH(g_bot_targets, this);
        this.iscreature                         = true;
        this.teleportable                       = false; // no teleporting for vehicles, too buggy
        this.damagedbycontents          = true;
+       IL_PUSH(g_damagedbycontents, this);
        this.vehicleid                          = info.vehicleid;
        this.PlayerPhysplug                     = info.PlayerPhysplug;
        this.event_damage                       = func_null;
@@ -1234,6 +1206,8 @@ bool vehicle_initialize(entity this, Vehicle info, bool nodrop)
 
        setsize(this, info.mins, info.maxs);
 
+       info.vr_setup(info, this);
+
        if(!nodrop)
        {
                setorigin(this, this.origin);
@@ -1245,8 +1219,6 @@ bool vehicle_initialize(entity this, Vehicle info, bool nodrop)
        this.pos2 = this.angles;
        this.tur_head.team = this.team;
 
-       info.vr_setup(info, this);
-
        if(this.active == ACTIVE_NOT)
                this.nextthink = 0; // wait until activated
        else if(autocvar_g_vehicles_delayspawn)
@@ -1254,7 +1226,7 @@ bool vehicle_initialize(entity this, Vehicle info, bool nodrop)
        else
                this.nextthink = time + game_starttime;
 
-       if(MUTATOR_CALLHOOK(VehicleSpawn, this))
+       if(MUTATOR_CALLHOOK(VehicleInit, this))
                return false;
 
        return true;