]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/mutators/gamemode_ctf.qc
Merge branch 'master' into Mario/qc_physics_prehax
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / mutators / gamemode_ctf.qc
index 967d8d656fdf72b43a54e7fdff077c3d111c4d50..c8aa595bced3351e1bbd2f8ca17a532c5aff2e8d 100644 (file)
@@ -1,7 +1,4 @@
-// ================================================================
-//  Official capture the flag game mode coding, reworked by Samual
-//  Last updated: September, 2012
-// ================================================================
+#include "../../common/movetypes/movetypes.qh"
 
 void ctf_FakeTimeLimit(entity e, float t)
 {
@@ -43,7 +40,7 @@ void ctf_CaptureRecord(entity flag, entity player)
 
 void ctf_FlagcarrierWaypoints(entity player)
 {
-       WaypointSprite_Spawn("flagcarrier", 0, 0, player, FLAG_WAYPOINT_OFFSET, world, player.team, player, wps_flagcarrier, TRUE, RADARICON_FLAG, WPCOLOR_FLAGCARRIER(player.team));
+       WaypointSprite_Spawn("flagcarrier", 0, 0, player, FLAG_WAYPOINT_OFFSET, world, player.team, player, wps_flagcarrier, true, RADARICON_FLAG, WPCOLOR_FLAGCARRIER(player.team));
        WaypointSprite_UpdateMaxHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(start_health, start_armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON) * 2);
        WaypointSprite_UpdateHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(player.health, player.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON));
        WaypointSprite_UpdateTeamRadar(player.wps_flagcarrier, RADARICON_FLAGCARRIER, WPCOLOR_FLAGCARRIER(player.team));
@@ -51,7 +48,7 @@ void ctf_FlagcarrierWaypoints(entity player)
 
 void ctf_CalculatePassVelocity(entity flag, vector to, vector from, float turnrate)
 {
-       float current_distance = vlen((('1 0 0' * to_x) + ('0 1 0' * to_y)) - (('1 0 0' * from_x) + ('0 1 0' * from_y))); // for the sake of this check, exclude Z axis
+       float current_distance = vlen((('1 0 0' * to.x) + ('0 1 0' * to.y)) - (('1 0 0' * from.x) + ('0 1 0' * from.y))); // for the sake of this check, exclude Z axis
        float initial_height = min(autocvar_g_ctf_pass_arc_max, (flag.pass_distance * tanh(autocvar_g_ctf_pass_arc)));
        float current_height = (initial_height * min(1, (current_distance / flag.pass_distance)));
        //print("current_height = ", ftos(current_height), ", initial_height = ", ftos(initial_height), ".\n");
@@ -60,24 +57,24 @@ void ctf_CalculatePassVelocity(entity flag, vector to, vector from, float turnra
        if(current_height) // make sure we can actually do this arcing path
        {
                targpos = (to + ('0 0 1' * current_height));
-               WarpZone_TraceLine(flag.origin, targpos, MOVE_NOMONSTERS, flag);
+               WarpZone_TraceLine(flag.move_origin, targpos, MOVE_NOMONSTERS, flag);
                if(trace_fraction < 1)
                {
                        //print("normal arc line failed, trying to find new pos...");
                        WarpZone_TraceLine(to, targpos, MOVE_NOMONSTERS, flag);
                        targpos = (trace_endpos + FLAG_PASS_ARC_OFFSET);
-                       WarpZone_TraceLine(flag.origin, targpos, MOVE_NOMONSTERS, flag);
+                       WarpZone_TraceLine(flag.move_origin, targpos, MOVE_NOMONSTERS, flag);
                        if(trace_fraction < 1) { targpos = to; /* print(" ^1FAILURE^7, reverting to original direction.\n"); */ }
                        /*else { print(" ^3SUCCESS^7, using new arc line.\n"); } */
                }
        }
        else { targpos = to; }
 
-       //flag.angles = normalize(('0 1 0' * to_y) - ('0 1 0' * from_y));
+       //flag.move_angles = normalize(('0 1 0' * to_y) - ('0 1 0' * from_y));
 
        vector desired_direction = normalize(targpos - from);
-       if(turnrate) { flag.velocity = (normalize(normalize(flag.velocity) + (desired_direction * autocvar_g_ctf_pass_turnrate)) * autocvar_g_ctf_pass_velocity); }
-       else { flag.velocity = (desired_direction * autocvar_g_ctf_pass_velocity); }
+       if(turnrate) { flag.move_velocity = (normalize(normalize(flag.move_velocity) + (desired_direction * autocvar_g_ctf_pass_turnrate)) * autocvar_g_ctf_pass_velocity); }
+       else { flag.move_velocity = (desired_direction * autocvar_g_ctf_pass_velocity); }
 }
 
 float ctf_CheckPassDirection(vector head_center, vector passer_center, vector passer_angle, vector nearest_to_passer)
@@ -89,13 +86,11 @@ float ctf_CheckPassDirection(vector head_center, vector passer_center, vector pa
                makevectors(passer_angle);
 
                // find the closest point on the enemy to the center of the attack
-               float ang; // angle between shotdir and h
                float h; // hypotenuse, which is the distance between attacker to head
                float a; // adjacent side, which is the distance between attacker and the point on w_shotdir that is closest to head.origin
 
                h = vlen(head_center - passer_center);
-               ang = acos(dotproduct(normalize(head_center - passer_center), v_forward));
-               a = h * cos(ang);
+               a = h * (normalize(head_center - passer_center) * v_forward);
 
                vector nearest_on_line = (passer_center + a * v_forward);
                float distance_from_line = vlen(nearest_to_passer - nearest_on_line);
@@ -104,11 +99,11 @@ float ctf_CheckPassDirection(vector head_center, vector passer_center, vector pa
                spreadlimit = (autocvar_g_ctf_pass_directional_min * (1 - spreadlimit) + autocvar_g_ctf_pass_directional_max * spreadlimit);
 
                if(spreadlimit && (distance_from_line <= spreadlimit) && ((vlen(normalize(head_center - passer_center) - v_forward) * RAD2DEG) <= 90))
-                       { return TRUE; }
+                       { return true; }
                else
-                       { return FALSE; }
+                       { return false; }
        }
-       else { return TRUE; }
+       else { return true; }
 }
 
 
@@ -123,11 +118,11 @@ float ctf_CaptureShield_CheckStatus(entity p)
        float players_worseeq, players_total;
 
        if(ctf_captureshield_max_ratio <= 0)
-               return FALSE;
+               return false;
 
        s = PlayerScore_Add(p, SP_SCORE, 0);
        if(s >= -ctf_captureshield_min_negscore)
-               return FALSE;
+               return false;
 
        players_total = players_worseeq = 0;
        FOR_EACH_PLAYER(e)
@@ -144,9 +139,9 @@ float ctf_CaptureShield_CheckStatus(entity p)
        // use this rule here
 
        if(players_worseeq >= players_total * ctf_captureshield_max_ratio)
-               return FALSE;
+               return false;
 
-       return TRUE;
+       return true;
 }
 
 void ctf_CaptureShield_Update(entity player, float wanted_status)
@@ -161,10 +156,10 @@ void ctf_CaptureShield_Update(entity player, float wanted_status)
 
 float ctf_CaptureShield_Customize()
 {
-       if(!other.ctf_captureshielded) { return FALSE; }
-       if(SAME_TEAM(self, other)) { return FALSE; }
+       if(!other.ctf_captureshielded) { return false; }
+       if(SAME_TEAM(self, other)) { return false; }
 
-       return TRUE;
+       return true;
 }
 
 void ctf_CaptureShield_Touch()
@@ -176,7 +171,7 @@ void ctf_CaptureShield_Touch()
        vector othermid = (other.absmin + other.absmax) * 0.5;
 
        Damage(other, self, self, 0, DEATH_HURTTRIGGER, mymid, normalize(othermid - mymid) * ctf_captureshield_force);
-       Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_CTF_CAPTURESHIELD_SHIELDED);
+       if(IS_REAL_CLIENT(other)) { Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_CTF_CAPTURESHIELD_SHIELDED); }
 }
 
 void ctf_CaptureShield_Spawn(entity flag)
@@ -210,9 +205,9 @@ void ctf_Handle_Drop(entity flag, entity player, float droptype)
        player = (player ? player : flag.pass_sender);
 
        // main
-       flag.movetype = MOVETYPE_TOSS;
+       flag.move_movetype = MOVETYPE_TOSS;
        flag.takedamage = DAMAGE_YES;
-       flag.angles = '0 0 0';
+       flag.move_angles = '0 0 0';
        flag.health = flag.max_flag_health;
        flag.ctf_droptime = time;
        flag.ctf_dropper = player;
@@ -229,7 +224,7 @@ void ctf_Handle_Drop(entity flag, entity player, float droptype)
 
        // waypoints
        if(autocvar_g_ctf_flag_dropped_waypoint)
-               WaypointSprite_Spawn("flagdropped", 0, 0, flag, FLAG_WAYPOINT_OFFSET, world, ((autocvar_g_ctf_flag_dropped_waypoint == 2) ? 0 : player.team), flag, wps_flagdropped, TRUE, RADARICON_FLAG, WPCOLOR_DROPPEDFLAG(flag.team));
+               WaypointSprite_Spawn("flagdropped", 0, 0, flag, FLAG_WAYPOINT_OFFSET, world, ((autocvar_g_ctf_flag_dropped_waypoint == 2) ? 0 : player.team), flag, wps_flagdropped, true, RADARICON_FLAG, WPCOLOR_DROPPEDFLAG(flag.team));
 
        if(autocvar_g_ctf_flag_return_time || (autocvar_g_ctf_flag_return_damage && autocvar_g_ctf_flag_health))
        {
@@ -257,12 +252,21 @@ void ctf_Handle_Retrieve(entity flag, entity player)
        flag.owner.flagcarried = flag;
 
        // reset flag
-       setattachment(flag, player, "");
-       setorigin(flag, FLAG_CARRY_OFFSET);
-       flag.movetype = MOVETYPE_NONE;
+       if(player.vehicle)
+       {
+               setattachment(flag, player.vehicle, "");
+               flag.move_origin = VEHICLE_FLAG_OFFSET;
+               flag.scale = VEHICLE_FLAG_SCALE;
+       }
+       else
+       {
+               setattachment(flag, player, "");
+               flag.move_origin = VEHICLE_FLAG_OFFSET;
+       }
+       flag.move_movetype = MOVETYPE_NONE;
        flag.takedamage = DAMAGE_NO;
        flag.solid = SOLID_NOT;
-       flag.angles = '0 0 0';
+       flag.move_angles = '0 0 0';
        flag.ctf_status = FLAG_CARRY;
 
        // messages and sounds
@@ -302,14 +306,15 @@ void ctf_Handle_Throw(entity player, entity receiver, float droptype)
 
        // reset the flag
        setattachment(flag, world, "");
-       setorigin(flag, player.origin + FLAG_DROP_OFFSET);
+       flag.move_origin = player.origin + FLAG_DROP_OFFSET;
        flag.owner.flagcarried = world;
        flag.owner = world;
        flag.solid = SOLID_TRIGGER;
        flag.ctf_dropper = player;
        flag.ctf_droptime = time;
 
-       flag.flags = FL_ITEM | FL_NOTARGET; // clear FL_ONGROUND for MOVETYPE_TOSS
+       flag.move_flags = FL_ITEM | FL_NOTARGET; // clear FL_ONGROUND for MOVETYPE_TOSS
+       flag.flags = flag.move_flags;
 
        switch(droptype)
        {
@@ -322,11 +327,11 @@ void ctf_Handle_Throw(entity player, entity receiver, float droptype)
                        WarpZone_RefSys_AddInverse(flag, receiver); // wz1^-1 ... wzn^-1 receiver
                        targ_origin = WarpZone_RefSys_TransformOrigin(receiver, flag, (0.5 * (receiver.absmin + receiver.absmax))); // this is target origin as seen by the flag
 
-                       flag.pass_distance = vlen((('1 0 0' * targ_origin_x) + ('0 1 0' * targ_origin_y)) - (('1 0 0' *  player.origin_x) + ('0 1 0' *  player.origin_y))); // for the sake of this check, exclude Z axis
-                       ctf_CalculatePassVelocity(flag, targ_origin, player.origin, FALSE);
+                       flag.pass_distance = vlen((('1 0 0' * targ_origin.x) + ('0 1 0' * targ_origin.y)) - (('1 0 0' *  player.origin.x) + ('0 1 0' *  player.origin.y))); // for the sake of this check, exclude Z axis
+                       ctf_CalculatePassVelocity(flag, targ_origin, player.origin, false);
 
                        // main
-                       flag.movetype = MOVETYPE_FLY;
+                       flag.move_movetype = MOVETYPE_FLY;
                        flag.takedamage = DAMAGE_NO;
                        flag.pass_sender = player;
                        flag.pass_target = receiver;
@@ -341,24 +346,24 @@ void ctf_Handle_Throw(entity player, entity receiver, float droptype)
 
                case DROP_THROW:
                {
-                       makevectors((player.v_angle_y * '0 1 0') + (bound(autocvar_g_ctf_throw_angle_min, player.v_angle_x, autocvar_g_ctf_throw_angle_max) * '1 0 0'));
+                       makevectors((player.v_angle.y * '0 1 0') + (bound(autocvar_g_ctf_throw_angle_min, player.v_angle.x, autocvar_g_ctf_throw_angle_max) * '1 0 0'));
 
                        flag_velocity = (('0 0 1' * autocvar_g_ctf_throw_velocity_up) + ((v_forward * autocvar_g_ctf_throw_velocity_forward) * ((player.items & IT_STRENGTH) ? autocvar_g_ctf_throw_strengthmultiplier : 1)));
-                       flag.velocity = W_CalculateProjectileVelocity(player.velocity, flag_velocity, FALSE);
+                       flag.move_velocity = W_CalculateProjectileVelocity(player.velocity, flag_velocity, false);
                        ctf_Handle_Drop(flag, player, droptype);
                        break;
                }
 
                case DROP_RESET:
                {
-                       flag.velocity = '0 0 0'; // do nothing
+                       flag.move_velocity = '0 0 0'; // do nothing
                        break;
                }
 
                default:
                case DROP_NORMAL:
                {
-                       flag.velocity = W_CalculateProjectileVelocity(player.velocity, (('0 0 1' * autocvar_g_ctf_drop_velocity_up) + ((('0 1 0' * crandom()) + ('1 0 0' * crandom())) * autocvar_g_ctf_drop_velocity_side)), FALSE);
+                       flag.move_velocity = W_CalculateProjectileVelocity(player.velocity, (('0 0 1' * autocvar_g_ctf_drop_velocity_up) + ((('0 1 0' * crandom()) + ('1 0 0' * crandom())) * autocvar_g_ctf_drop_velocity_side)), false);
                        ctf_Handle_Drop(flag, player, droptype);
                        break;
                }
@@ -412,8 +417,8 @@ void ctf_Handle_Capture(entity flag, entity toucher, float capturetype)
                PlayerScore_Add(player, SP_CTF_CAPTIME, new_time - old_time);
 
        // effects
-       pointparticles(particleeffectnum(flag.capeffect), flag.origin, '0 0 0', 1);
-       //shockwave_spawn("models/ctf/shockwavetransring.md3", flag.origin - '0 0 15', -0.8, 0, 1);
+       pointparticles(particleeffectnum(flag.capeffect), flag.move_origin, '0 0 0', 1);
+       //shockwave_spawn("models/ctf/shockwavetransring.md3", flag.move_origin - '0 0 15', -0.8, 0, 1);
 
        // other
        if(capturetype == CAPTURE_NORMAL)
@@ -475,14 +480,23 @@ void ctf_Handle_Pickup(entity flag, entity player, float pickuptype)
        // attach the flag to the player
        flag.owner = player;
        player.flagcarried = flag;
-       setattachment(flag, player, "");
-       setorigin(flag, FLAG_CARRY_OFFSET);
+       if(player.vehicle)
+       {
+               setattachment(flag, player.vehicle, "");
+               flag.move_origin = VEHICLE_FLAG_OFFSET;
+               flag.scale = VEHICLE_FLAG_SCALE;
+       }
+       else
+       {
+               setattachment(flag, player, "");
+               flag.move_origin = FLAG_CARRY_OFFSET;
+       }
 
        // flag setup
-       flag.movetype = MOVETYPE_NONE;
+       flag.move_movetype = MOVETYPE_NONE;
        flag.takedamage = DAMAGE_NO;
        flag.solid = SOLID_NOT;
-       flag.angles = '0 0 0';
+       flag.move_angles = '0 0 0';
        flag.ctf_status = FLAG_CARRY;
 
        switch(pickuptype)
@@ -602,11 +616,11 @@ void ctf_CheckStalemate(void)
        }
 
        if(stale_red_flags && stale_blue_flags)
-               ctf_stalemate = TRUE;
+               ctf_stalemate = true;
        else if((!stale_red_flags && !stale_blue_flags) && autocvar_g_ctf_stalemate_endcondition == 2)
-               { ctf_stalemate = FALSE; wpforenemy_announced = FALSE; }
+               { ctf_stalemate = false; wpforenemy_announced = false; }
        else if((!stale_red_flags || !stale_blue_flags) && autocvar_g_ctf_stalemate_endcondition == 1)
-               { ctf_stalemate = FALSE; wpforenemy_announced = FALSE; }
+               { ctf_stalemate = false; wpforenemy_announced = false; }
 
        // if sufficient stalemate, then set up the waypointsprite and announce the stalemate if necessary
        if(ctf_stalemate)
@@ -614,7 +628,7 @@ void ctf_CheckStalemate(void)
                for(tmp_entity = ctf_staleflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_staleflagnext)
                {
                        if((tmp_entity.owner) && (!tmp_entity.owner.wps_enemyflagcarrier))
-                               WaypointSprite_Spawn("enemyflagcarrier", 0, 0, tmp_entity.owner, FLAG_WAYPOINT_OFFSET, world, tmp_entity.team, tmp_entity.owner, wps_enemyflagcarrier, TRUE, RADARICON_FLAG, WPCOLOR_ENEMYFC(tmp_entity.owner.team));
+                               WaypointSprite_Spawn("enemyflagcarrier", 0, 0, tmp_entity.owner, FLAG_WAYPOINT_OFFSET, world, tmp_entity.team, tmp_entity.owner, wps_enemyflagcarrier, true, RADARICON_FLAG, WPCOLOR_ENEMYFC(tmp_entity.owner.team));
                }
 
                if (!wpforenemy_announced)
@@ -622,13 +636,14 @@ void ctf_CheckStalemate(void)
                        FOR_EACH_REALPLAYER(tmp_entity)
                                Send_Notification(NOTIF_ONE, tmp_entity, MSG_CENTER, ((tmp_entity.flagcarried) ? CENTER_CTF_STALEMATE_CARRIER : CENTER_CTF_STALEMATE_OTHER));
 
-                       wpforenemy_announced = TRUE;
+                       wpforenemy_announced = true;
                }
        }
 }
 
-void ctf_FlagDamage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void ctf_FlagDamage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
 {
+       self.move_velocity = self.velocity;
        if(ITEM_DAMAGE_NEEDKILL(deathtype))
        {
                // automatically kill the flag and return it
@@ -645,13 +660,11 @@ void ctf_FlagDamage(entity inflictor, entity attacker, float damage, float death
        }
 }
 
-void ctf_FlagThink()
+void ctf_FlagUpdate()
 {
        // declarations
        entity tmp_entity;
 
-       self.nextthink = time + FLAG_THINKRATE; // only 5 fps, more is unnecessary.
-
        // captureshield
        if(self == ctf_worldflaglist) // only for the first flag
                FOR_EACH_CLIENT(tmp_entity)
@@ -660,7 +673,7 @@ void ctf_FlagThink()
        // sanity checks
        if(self.mins != FLAG_MIN || self.maxs != FLAG_MAX) { // reset the flag boundaries in case it got squished
                dprint("wtf the flag got squashed?\n");
-               tracebox(self.origin, FLAG_MIN, FLAG_MAX, self.origin, MOVE_NOMONSTERS, self);
+               tracebox(self.move_origin, FLAG_MIN, FLAG_MAX, self.move_origin, MOVE_NOMONSTERS, self);
                if(!trace_startsolid || self.noalign) // can we resize it without getting stuck?
                        setsize(self, FLAG_MIN, FLAG_MAX); }
 
@@ -668,7 +681,7 @@ void ctf_FlagThink()
        {
                case FLAG_DROPPED:
                {
-                       self.angles = '0 0 0';
+                       self.move_angles = '0 0 0';
                        break;
                }
 
@@ -684,7 +697,7 @@ void ctf_FlagThink()
                        {
                                for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext)
                                        if(tmp_entity.ctf_status == FLAG_DROPPED)
-                                       if(vlen(self.origin - tmp_entity.origin) < autocvar_g_ctf_dropped_capture_radius)
+                                       if(vlen(self.move_origin - tmp_entity.move_origin) < autocvar_g_ctf_dropped_capture_radius)
                                        if(time > tmp_entity.ctf_droptime + autocvar_g_ctf_dropped_capture_delay)
                                                ctf_Handle_Capture(self, tmp_entity, CAPTURE_DROPPED);
                        }
@@ -698,18 +711,18 @@ void ctf_FlagThink()
                                vector midpoint = ((self.absmin + self.absmax) * 0.5);
                                if(pointcontents(midpoint) == CONTENT_WATER)
                                {
-                                       self.velocity = self.velocity * 0.5;
+                                       self.move_velocity = self.move_velocity * 0.5;
 
                                        if(pointcontents(midpoint + FLAG_FLOAT_OFFSET) == CONTENT_WATER)
-                                               { self.velocity_z = autocvar_g_ctf_flag_dropped_floatinwater; }
+                                               { self.move_velocity_z = autocvar_g_ctf_flag_dropped_floatinwater; }
                                        else
-                                               { self.movetype = MOVETYPE_FLY; }
+                                               { self.move_movetype = MOVETYPE_FLY; }
                                }
-                               else if(self.movetype == MOVETYPE_FLY) { self.movetype = MOVETYPE_TOSS; }
+                               else if(self.move_movetype == MOVETYPE_FLY) { self.move_movetype = MOVETYPE_TOSS; }
                        }
                        if(autocvar_g_ctf_flag_return_dropped)
                        {
-                               if((vlen(self.origin - self.ctf_spawnorigin) <= autocvar_g_ctf_flag_return_dropped) || (autocvar_g_ctf_flag_return_dropped == -1))
+                               if((vlen(self.move_origin - self.ctf_spawnorigin) <= autocvar_g_ctf_flag_return_dropped) || (autocvar_g_ctf_flag_return_dropped == -1))
                                {
                                        self.health = 0;
                                        ctf_CheckFlagReturn(self, RETURN_DROPPED);
@@ -753,11 +766,12 @@ void ctf_FlagThink()
                {
                        vector targ_origin = ((self.pass_target.absmin + self.pass_target.absmax) * 0.5);
                        targ_origin = WarpZone_RefSys_TransformOrigin(self.pass_target, self, targ_origin); // origin of target as seen by the flag (us)
-                       WarpZone_TraceLine(self.origin, targ_origin, MOVE_NOMONSTERS, self);
+                       WarpZone_TraceLine(self.move_origin, targ_origin, MOVE_NOMONSTERS, self);
 
                        if((self.pass_target == world)
                                || (self.pass_target.deadflag != DEAD_NO)
-                               || (vlen(self.origin - targ_origin) > autocvar_g_ctf_pass_radius)
+                               || (self.pass_target.flagcarried)
+                               || (vlen(self.move_origin - targ_origin) > autocvar_g_ctf_pass_radius)
                                || ((trace_fraction < 1) && (trace_ent != self.pass_target))
                                || (time > self.ctf_droptime + autocvar_g_ctf_pass_timelimit))
                        {
@@ -767,7 +781,7 @@ void ctf_FlagThink()
                        else
                        {
                                // still a viable target, go for it
-                               ctf_CalculatePassVelocity(self, targ_origin, self.origin, TRUE);
+                               ctf_CalculatePassVelocity(self, targ_origin, self.move_origin, true);
                        }
                        return;
                }
@@ -780,9 +794,24 @@ void ctf_FlagThink()
        }
 }
 
+void ctf_FlagThink()
+{
+       self.nextthink = time;
+
+       if(time >= self.ctf_thinkrate)
+       {
+               self.ctf_thinkrate = time + FLAG_THINKRATE;
+               ctf_FlagUpdate();
+       }
+
+       //Movetype_Physics_NoMatchServer();
+       Movetype_Physics_MatchTicrate(sys_frametime, 0);
+}
+
 void ctf_FlagTouch()
 {
        if(gameover) { return; }
+       if(trace_dphitcontents & (DPCONTENTS_PLAYERCLIP | DPCONTENTS_MONSTERCLIP)) { return; }
 
        entity toucher = other;
        float is_not_monster = (!(toucher.flags & FL_MONSTER));
@@ -813,7 +842,7 @@ void ctf_FlagTouch()
        {
                if(time > self.wait) // if we haven't in a while, play a sound/effect
                {
-                       pointparticles(particleeffectnum(self.toucheffect), self.origin, '0 0 0', 1);
+                       pointparticles(particleeffectnum(self.toucheffect), self.move_origin, '0 0 0', 1);
                        sound(self, CH_TRIGGER, self.snd_flag_touch, VOL_BASE, ATTEN_NORM);
                        self.wait = time + FLAG_TOUCHRATE;
                }
@@ -884,20 +913,24 @@ void ctf_RespawnFlag(entity flag)
                        ctf_FakeTimeLimit(flag.owner, -1);
        }
 
+       if((flag.owner) && (flag.owner.vehicle))
+               flag.scale = FLAG_SCALE;
+
        if((flag.ctf_status == FLAG_DROPPED) && (flag.wps_flagdropped))
                { WaypointSprite_Kill(flag.wps_flagdropped); }
 
        // reset the flag
        setattachment(flag, world, "");
-       setorigin(flag, flag.ctf_spawnorigin);
+       flag.move_origin = flag.ctf_spawnorigin;
 
-       flag.movetype = ((flag.noalign) ? MOVETYPE_NONE : MOVETYPE_TOSS);
+       flag.move_movetype = ((flag.noalign) ? MOVETYPE_NONE : MOVETYPE_TOSS);
        flag.takedamage = DAMAGE_NO;
        flag.health = flag.max_flag_health;
        flag.solid = SOLID_TRIGGER;
-       flag.velocity = '0 0 0';
-       flag.angles = flag.mangle;
-       flag.flags = FL_ITEM | FL_NOTARGET;
+       flag.move_velocity = '0 0 0';
+       flag.move_angles = flag.mangle;
+       flag.move_flags = FL_ITEM | FL_NOTARGET;
+       flag.flags = flag.move_flags;
 
        flag.ctf_status = FLAG_BASE;
        flag.owner = world;
@@ -907,6 +940,8 @@ void ctf_RespawnFlag(entity flag)
        flag.ctf_dropper = world;
        flag.ctf_pickuptime = 0;
        flag.ctf_droptime = 0;
+
+       ctf_CheckStalemate();
 }
 
 void ctf_Reset()
@@ -926,11 +961,16 @@ void ctf_DelayedFlagSetup(void) // called after a flag is placed on a map by ctf
        self.bot_basewaypoint = self.nearestwaypoint;
 
        // waypointsprites
-       WaypointSprite_SpawnFixed(((self.team == NUM_TEAM_1) ? "redbase" : "bluebase"), self.origin + FLAG_WAYPOINT_OFFSET, self, wps_flagbase, RADARICON_FLAG, colormapPaletteColor(self.team - 1, FALSE));
-       WaypointSprite_UpdateTeamRadar(self.wps_flagbase, RADARICON_FLAG, colormapPaletteColor(self.team - 1, FALSE));
+       // move_origin isnt accessible just yet
+       WaypointSprite_SpawnFixed(((self.team == NUM_TEAM_1) ? "redbase" : "bluebase"), self.origin + FLAG_WAYPOINT_OFFSET, self, wps_flagbase, RADARICON_FLAG, colormapPaletteColor(self.team - 1, false));
+       WaypointSprite_UpdateTeamRadar(self.wps_flagbase, RADARICON_FLAG, colormapPaletteColor(self.team - 1, false));
 
        // captureshield setup
        ctf_CaptureShield_Spawn(self);
+
+       self.move_origin = self.origin;
+       self.move_angles = self.angles;
+       self.move_velocity = self.velocity;
 }
 
 void ctf_FlagSetup(float teamnumber, entity flag) // called when spawning a flag entity on the map as a spawnfunc
@@ -950,24 +990,27 @@ void ctf_FlagSetup(float teamnumber, entity flag) // called when spawning a flag
        flag.items = ((teamnumber) ? IT_KEY2 : IT_KEY1); // IT_KEY2: gold key (redish enough) - IT_KEY1: silver key (bluish enough)
        flag.classname = "item_flag_team";
        flag.target = "###item###"; // wut?
-       flag.flags = FL_ITEM | FL_NOTARGET;
+       flag.move_flags = FL_ITEM | FL_NOTARGET;
+       flag.flags = flag.move_flags;
        flag.solid = SOLID_TRIGGER;
        flag.takedamage = DAMAGE_NO;
        flag.damageforcescale = autocvar_g_ctf_flag_damageforcescale;
        flag.max_flag_health = ((autocvar_g_ctf_flag_return_damage && autocvar_g_ctf_flag_health) ? autocvar_g_ctf_flag_health : 100);
        flag.health = flag.max_flag_health;
        flag.event_damage = ctf_FlagDamage;
-       flag.pushable = TRUE;
+       flag.pushable = true;
        flag.teleportable = TELEPORT_NORMAL;
        flag.damagedbytriggers = autocvar_g_ctf_flag_return_when_unreachable;
        flag.damagedbycontents = autocvar_g_ctf_flag_return_when_unreachable;
-       flag.velocity = '0 0 0';
+       flag.move_velocity = '0 0 0';
        flag.mangle = flag.angles;
        flag.reset = ctf_Reset;
        flag.touch = ctf_FlagTouch;
+       flag.move_touch = flag.touch;
        flag.think = ctf_FlagThink;
        flag.nextthink = time + FLAG_THINKRATE;
        flag.ctf_status = FLAG_BASE;
+       flag.move_time = time;
 
        // appearence
        if(flag.model == "")       { flag.model = ((teamnumber) ? autocvar_g_ctf_flag_red_model : autocvar_g_ctf_flag_blue_model); }
@@ -1018,15 +1061,15 @@ void ctf_FlagSetup(float teamnumber, entity flag) // called when spawning a flag
        if((flag.spawnflags & 1) || flag.noalign) // don't drop to floor, just stay at fixed location
        {
                flag.dropped_origin = flag.origin;
-               flag.noalign = TRUE;
-               flag.movetype = MOVETYPE_NONE;
+               flag.noalign = true;
+               flag.move_movetype = MOVETYPE_NONE;
        }
        else // drop to floor, automatically find a platform and set that as spawn origin
        {
-               flag.noalign = FALSE;
+               flag.noalign = false;
                self = flag;
                droptofloor();
-               flag.movetype = MOVETYPE_TOSS;
+               flag.move_movetype = MOVETYPE_TOSS;
        }
 
        InitializeEntity(flag, ctf_DelayedFlagSetup, INITPRIO_SETLOCATION);
@@ -1049,7 +1092,7 @@ void havocbot_calculate_middlepoint()
        f = ctf_worldflaglist;
        while (f)
        {
-               fo = f.origin;
+               fo = f.move_origin;
                s = s + fo;
                f = f.ctf_worldflagnext;
        }
@@ -1193,7 +1236,7 @@ void havocbot_goalrating_ctf_droppedflags(float ratingscale, vector org, float d
                {
                        if(df_radius)
                        {
-                               if(vlen(org-head.origin)<df_radius)
+                               if(vlen(org-head.move_origin)<df_radius)
                                        navigation_routerating(head, ratingscale, 10000);
                        }
                        else
@@ -1208,7 +1251,7 @@ void havocbot_goalrating_ctf_carrieritems(float ratingscale, vector org, float s
 {
        entity head;
        float t;
-       head = findchainfloat(bot_pickup, TRUE);
+       head = findchainfloat(bot_pickup, true);
        while (head)
        {
                // gather health and armor only
@@ -1264,7 +1307,7 @@ void havocbot_ctf_reset_role(entity bot)
        // if there is only me on the team switch to offense
        c = 0;
        FOR_EACH_PLAYER(head)
-       if(head.team==bot.team)
+       if(SAME_TEAM(head, bot))
                ++c;
 
        if(c==1)
@@ -1357,7 +1400,7 @@ void havocbot_role_ctf_escort()
        // If the flag carrier reached the base switch to defense
        mf = havocbot_ctf_find_flag(self);
        if(mf.ctf_status!=FLAG_BASE)
-       if(vlen(ef.origin - mf.dropped_origin) < 300)
+       if(vlen(ef.move_origin - mf.dropped_origin) < 300)
        {
                havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_DEFENSE);
                return;
@@ -1416,7 +1459,7 @@ void havocbot_role_ctf_offense()
                if(mf.tag_entity)
                        pos = mf.tag_entity.origin;
                else
-                       pos = mf.origin;
+                       pos = mf.move_origin;
 
                // Try to get it if closer than the enemy base
                if(vlen(self.origin-ef.dropped_origin)>vlen(self.origin-pos))
@@ -1432,7 +1475,7 @@ void havocbot_role_ctf_offense()
                if(ef.tag_entity)
                        pos = ef.tag_entity.origin;
                else
-                       pos = ef.origin;
+                       pos = ef.move_origin;
 
                if(vlen(pos-mf.dropped_origin)>700)
                {
@@ -1556,7 +1599,7 @@ void havocbot_role_ctf_middle()
                vector org;
 
                org = havocbot_ctf_middlepoint;
-               org_z = self.origin_z;
+               org.z = self.origin.z;
 
                self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
                navigation_goalrating_start();
@@ -1630,7 +1673,7 @@ void havocbot_role_ctf_defense()
                }
 
                if(closestplayer)
-               if(closestplayer.team!=self.team)
+               if(DIFF_TEAM(closestplayer, self))
                if(vlen(org - self.origin)>1000)
                if(checkpvs(self.origin,closestplayer)||random()<0.5)
                        havocbot_goalrating_ctf_ourbase(30000);
@@ -1732,7 +1775,7 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerPreThink)
        if(self.wps_flagcarrier)
                WaypointSprite_UpdateHealth(self.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(self.health, self.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON));
 
-       return FALSE;
+       return false;
 }
 
 MUTATOR_HOOKFUNCTION(ctf_PlayerDamage) // for changing damage and force values that are applied to players in g_damage.qc
@@ -1760,7 +1803,7 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerDamage) // for changing damage and force values t
                }
                // todo: add notification for when flag carrier needs help?
        }
-       return FALSE;
+       return false;
 }
 
 MUTATOR_HOOKFUNCTION(ctf_PlayerDies)
@@ -1774,7 +1817,7 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerDies)
        if(frag_target.flagcarried)
                { ctf_Handle_Throw(frag_target, world, DROP_NORMAL); }
 
-       return FALSE;
+       return false;
 }
 
 MUTATOR_HOOKFUNCTION(ctf_GiveFragsForKill)
@@ -1797,7 +1840,7 @@ MUTATOR_HOOKFUNCTION(ctf_RemovePlayer)
                if(flag.ctf_dropper == self) { flag.ctf_dropper = world; }
        }
 
-       return FALSE;
+       return false;
 }
 
 MUTATOR_HOOKFUNCTION(ctf_PortalTeleport)
@@ -1806,12 +1849,12 @@ MUTATOR_HOOKFUNCTION(ctf_PortalTeleport)
        if(!autocvar_g_ctf_portalteleport)
                { ctf_Handle_Throw(self, world, DROP_NORMAL); }
 
-       return FALSE;
+       return false;
 }
 
 MUTATOR_HOOKFUNCTION(ctf_PlayerUseKey)
 {
-       if(MUTATOR_RETURNVALUE || gameover) { return FALSE; }
+       if(MUTATOR_RETURNVALUE || gameover) { return false; }
 
        entity player = self;
 
@@ -1821,7 +1864,7 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerUseKey)
                if(autocvar_g_ctf_pass)
                {
                        entity head, closest_target = world;
-                       head = WarpZone_FindRadius(player.origin, autocvar_g_ctf_pass_radius, TRUE);
+                       head = WarpZone_FindRadius(player.origin, autocvar_g_ctf_pass_radius, true);
 
                        while(head) // find the closest acceptable target to pass to
                        {
@@ -1848,7 +1891,7 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerUseKey)
                                                                Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PASS_REQUESTING, head.netname);
                                                        }
                                                        player.throw_antispam = time + autocvar_g_ctf_pass_wait;
-                                                       return TRUE;
+                                                       return true;
                                                }
                                                else if(player.flagcarried)
                                                {
@@ -1865,7 +1908,7 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerUseKey)
                                head = head.chain;
                        }
 
-                       if(closest_target) { ctf_Handle_Throw(player, closest_target, DROP_PASS); return TRUE; }
+                       if(closest_target) { ctf_Handle_Throw(player, closest_target, DROP_PASS); return true; }
                }
 
                // throw the flag in front of you
@@ -1878,12 +1921,12 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerUseKey)
                                        player.throw_prevtime = time;
                                        player.throw_count = 1;
                                        ctf_Handle_Throw(player, world, DROP_THROW);
-                                       return TRUE;
+                                       return true;
                                }
                                else
                                {
                                        Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_FLAG_THROW_PUNISH, rint((player.throw_prevtime + autocvar_g_ctf_throw_punish_delay) - time));
-                                       return FALSE;
+                                       return false;
                                }
                        }
                        else
@@ -1894,12 +1937,12 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerUseKey)
 
                                player.throw_prevtime = time;
                                ctf_Handle_Throw(player, world, DROP_THROW);
-                               return TRUE;
+                               return true;
                        }
                }
        }
 
-       return FALSE;
+       return false;
 }
 
 MUTATOR_HOOKFUNCTION(ctf_HelpMePing)
@@ -1911,11 +1954,11 @@ MUTATOR_HOOKFUNCTION(ctf_HelpMePing)
        }
        else // create a normal help me waypointsprite
        {
-               WaypointSprite_Spawn("helpme", waypointsprite_deployed_lifetime, waypointsprite_limitedrange, self, FLAG_WAYPOINT_OFFSET, world, self.team, self, wps_helpme, FALSE, RADARICON_HELPME, '1 0.5 0');
+               WaypointSprite_Spawn("helpme", waypointsprite_deployed_lifetime, waypointsprite_limitedrange, self, FLAG_WAYPOINT_OFFSET, world, self.team, self, wps_helpme, false, RADARICON_HELPME, '1 0.5 0');
                WaypointSprite_Ping(self.wps_helpme);
        }
 
-       return TRUE;
+       return true;
 }
 
 MUTATOR_HOOKFUNCTION(ctf_VehicleEnter)
@@ -1929,14 +1972,14 @@ MUTATOR_HOOKFUNCTION(ctf_VehicleEnter)
                else
                {
                        setattachment(vh_player.flagcarried, vh_vehicle, "");
-                       setorigin(vh_player.flagcarried, VEHICLE_FLAG_OFFSET);
+                       vh_player.flagcarried.move_origin = VEHICLE_FLAG_OFFSET;
                        vh_player.flagcarried.scale = VEHICLE_FLAG_SCALE;
-                       //vh_player.flagcarried.angles = '0 0 0';
+                       //vh_player.flagcarried.move_angles = '0 0 0';
                }
-               return TRUE;
+               return true;
        }
 
-       return FALSE;
+       return false;
 }
 
 MUTATOR_HOOKFUNCTION(ctf_VehicleExit)
@@ -1944,13 +1987,13 @@ MUTATOR_HOOKFUNCTION(ctf_VehicleExit)
        if(vh_player.flagcarried)
        {
                setattachment(vh_player.flagcarried, vh_player, "");
-               setorigin(vh_player.flagcarried, FLAG_CARRY_OFFSET);
+               vh_player.flagcarried.move_origin = VEHICLE_FLAG_OFFSET;
                vh_player.flagcarried.scale = FLAG_SCALE;
-               vh_player.flagcarried.angles = '0 0 0';
-               return TRUE;
+               vh_player.flagcarried.move_angles = '0 0 0';
+               return true;
        }
 
-       return FALSE;
+       return false;
 }
 
 MUTATOR_HOOKFUNCTION(ctf_AbortSpeedrun)
@@ -1959,10 +2002,10 @@ MUTATOR_HOOKFUNCTION(ctf_AbortSpeedrun)
        {
                Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(self.flagcarried, INFO_CTF_FLAGRETURN_ABORTRUN_));
                ctf_RespawnFlag(self.flagcarried);
-               return TRUE;
+               return true;
        }
 
-       return FALSE;
+       return false;
 }
 
 MUTATOR_HOOKFUNCTION(ctf_MatchEnd)
@@ -1977,10 +2020,10 @@ MUTATOR_HOOKFUNCTION(ctf_MatchEnd)
                        case FLAG_PASSING:
                        {
                                // lock the flag, game is over
-                               flag.movetype = MOVETYPE_NONE;
+                               flag.move_movetype = MOVETYPE_NONE;
                                flag.takedamage = DAMAGE_NO;
                                flag.solid = SOLID_NOT;
-                               flag.nextthink = FALSE; // stop thinking
+                               flag.nextthink = false; // stop thinking
 
                                //dprint("stopping the ", flag.netname, " from moving.\n");
                                break;
@@ -1996,13 +2039,13 @@ MUTATOR_HOOKFUNCTION(ctf_MatchEnd)
                }
        }
 
-       return FALSE;
+       return false;
 }
 
 MUTATOR_HOOKFUNCTION(ctf_BotRoles)
 {
        havocbot_ctf_reset_role(self);
-       return TRUE;
+       return true;
 }
 
 
@@ -2122,7 +2165,7 @@ void spawnfunc_team_CTF_bluespawn()  { spawnfunc_info_player_team2();  }
 // scoreboard setup
 void ctf_ScoreRules()
 {
-       ScoreRules_basics(2, SFL_SORT_PRIO_PRIMARY, 0, TRUE);
+       ScoreRules_basics(2, SFL_SORT_PRIO_PRIMARY, 0, true);
        ScoreInfo_SetLabel_TeamScore  (ST_CTF_CAPS,     "caps",      SFL_SORT_PRIO_PRIMARY);
        ScoreInfo_SetLabel_PlayerScore(SP_CTF_CAPS,     "caps",      SFL_SORT_PRIO_SECONDARY);
        ScoreInfo_SetLabel_PlayerScore(SP_CTF_CAPTIME,  "captime",   SFL_LOWER_IS_BETTER | SFL_TIME);