]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/mutators/mutator/gamemode_ctf.qc
server: pass compilation units test
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / mutators / mutator / gamemode_ctf.qc
index 699f1034caf0492a1646cd7acd375202736a460e..8cdad32558dcd01bcfaada28c1f167ab725f96dd 100644 (file)
@@ -1,6 +1,6 @@
-#ifndef GAMEMODE_CTF_H
-#define GAMEMODE_CTF_H
+#include "gamemode_ctf.qh"
 
+#ifdef IMPLEMENTATION
 #ifndef CSQC
 void ctf_Initialize();
 
@@ -35,184 +35,11 @@ REGISTER_MUTATOR(ctf, false)
 #endif
 
 #ifdef SVQC
-// used in cheats.qc
-void ctf_RespawnFlag(entity flag);
-
-// score rule declarations
-const int ST_CTF_CAPS = 1;
-const int SP_CTF_CAPS = 4;
-const int SP_CTF_CAPTIME = 5;
-const int SP_CTF_PICKUPS = 6;
-const int SP_CTF_DROPS = 7;
-const int SP_CTF_FCKILLS = 8;
-const int SP_CTF_RETURNS = 9;
-
-CLASS(Flag, Pickup)
-    ATTRIB(Flag, m_mins, vector, PL_MIN_CONST + '0 0 -13')
-    ATTRIB(Flag, m_maxs, vector, PL_MAX_CONST + '0 0 -13')
-ENDCLASS(Flag)
-Flag CTF_FLAG; STATIC_INIT(Flag) { CTF_FLAG = NEW(Flag); }
-void ctf_FlagTouch() { SELFPARAM(); ITEM_HANDLE(Pickup, CTF_FLAG, this, other); }
-
-// flag constants // for most of these, there is just one question to be asked: WHYYYYY?
-
-const float FLAG_SCALE = 0.6;
-
-const float FLAG_THINKRATE = 0.2;
-const float FLAG_TOUCHRATE = 0.5;
-const float WPFE_THINKRATE = 0.5;
-
-const vector FLAG_DROP_OFFSET = ('0 0 32');
-const vector FLAG_CARRY_OFFSET = ('-16 0 8');
-#define FLAG_SPAWN_OFFSET ('0 0 1' * (PL_MAX_CONST.z - 13))
-const vector FLAG_WAYPOINT_OFFSET = ('0 0 64');
-const vector FLAG_FLOAT_OFFSET = ('0 0 32');
-const vector FLAG_PASS_ARC_OFFSET = ('0 0 -10');
-
-const vector VEHICLE_FLAG_OFFSET = ('0 0 96');
-const float VEHICLE_FLAG_SCALE = 1.0;
-
-// waypoint colors
-#define WPCOLOR_ENEMYFC(t) ((t) ? colormapPaletteColor(t - 1, false) * 0.75 : '1 1 1')
-#define WPCOLOR_FLAGCARRIER(t) (WP_FlagCarrier.m_color)
-#define WPCOLOR_DROPPEDFLAG(t) ((t) ? ('0.25 0.25 0.25' + colormapPaletteColor(t - 1, false)) * 0.5 : '1 1 1')
-
-// sounds
-#define snd_flag_taken noise
-#define snd_flag_returned noise1
-#define snd_flag_capture noise2
-#define snd_flag_respawn noise3
-.string snd_flag_dropped;
-.string snd_flag_touch;
-.string snd_flag_pass;
-
-// effects
-.string toucheffect;
-.string passeffect;
-.string capeffect;
-
-// list of flags on the map
-entity ctf_worldflaglist;
-.entity ctf_worldflagnext;
-.entity ctf_staleflagnext;
-
-// waypoint sprites
-.entity bot_basewaypoint; // flag waypointsprite
-.entity wps_helpme;
-.entity wps_flagbase;
-.entity wps_flagcarrier;
-.entity wps_flagdropped;
-.entity wps_enemyflagcarrier;
-.float wps_helpme_time;
-bool wpforenemy_announced;
-float wpforenemy_nextthink;
-
-// statuses
-const int FLAG_BASE = 1;
-const int FLAG_DROPPED = 2;
-const int FLAG_CARRY = 3;
-const int FLAG_PASSING = 4;
-
-const int DROP_NORMAL = 1;
-const int DROP_THROW = 2;
-const int DROP_PASS = 3;
-const int DROP_RESET = 4;
-
-const int PICKUP_BASE = 1;
-const int PICKUP_DROPPED = 2;
-
-const int CAPTURE_NORMAL = 1;
-const int CAPTURE_DROPPED = 2;
-
-const int RETURN_TIMEOUT = 1;
-const int RETURN_DROPPED = 2;
-const int RETURN_DAMAGE = 3;
-const int RETURN_SPEEDRUN = 4;
-const int RETURN_NEEDKILL = 5;
-
-void ctf_Handle_Throw(entity player, entity receiver, float droptype);
-
-// flag properties
-#define ctf_spawnorigin dropped_origin
-bool ctf_stalemate; // indicates that a stalemate is active
-float ctf_captimerecord; // record time for capturing the flag
-.float ctf_pickuptime;
-.float ctf_droptime;
-.int ctf_status; // status of the flag (FLAG_BASE, FLAG_DROPPED, FLAG_CARRY declared globally)
-.entity ctf_dropper; // don't allow spam of dropping the flag
-.int max_flag_health;
-.float next_take_time;
-.bool ctf_flagdamaged;
-int ctf_teams;
-
-// passing/throwing properties
-.float pass_distance;
-.entity pass_sender;
-.entity pass_target;
-.float throw_antispam;
-.float throw_prevtime;
-.int throw_count;
-
-// CaptureShield: If the player is too bad to be allowed to capture, shield them from taking the flag.
-.bool ctf_captureshielded; // set to 1 if the player is too bad to be allowed to capture
-float ctf_captureshield_min_negscore; // punish at -20 points
-float ctf_captureshield_max_ratio; // punish at most 30% of each team
-float ctf_captureshield_force; // push force of the shield
-
-// 1 flag ctf
-bool ctf_oneflag; // indicates whether or not a neutral flag has been found
-
-// bot player logic
-const int HAVOCBOT_CTF_ROLE_NONE = 0;
-const int HAVOCBOT_CTF_ROLE_DEFENSE = 2;
-const int HAVOCBOT_CTF_ROLE_MIDDLE = 4;
-const int HAVOCBOT_CTF_ROLE_OFFENSE = 8;
-const int HAVOCBOT_CTF_ROLE_CARRIER = 16;
-const int HAVOCBOT_CTF_ROLE_RETRIEVER = 32;
-const int HAVOCBOT_CTF_ROLE_ESCORT = 64;
-
-.bool havocbot_cantfindflag;
-
-vector havocbot_ctf_middlepoint;
-float havocbot_ctf_middlepoint_radius;
-
-void havocbot_role_ctf_setrole(entity bot, int role);
-
-// team checking
-#define CTF_SAMETEAM(a,b) ((autocvar_g_ctf_reverse || (ctf_oneflag && autocvar_g_ctf_oneflag_reverse)) ? DIFF_TEAM(a,b) : SAME_TEAM(a,b))
-#define CTF_DIFFTEAM(a,b) ((autocvar_g_ctf_reverse || (ctf_oneflag && autocvar_g_ctf_oneflag_reverse)) ? SAME_TEAM(a,b) : DIFF_TEAM(a,b))
-
-// networked flag statuses
-.int ctf_flagstatus = _STAT(CTF_FLAGSTATUS);
-#endif
-
-const int CTF_RED_FLAG_TAKEN                   = 1;
-const int CTF_RED_FLAG_LOST                            = 2;
-const int CTF_RED_FLAG_CARRYING                        = 3;
-const int CTF_BLUE_FLAG_TAKEN                  = 4;
-const int CTF_BLUE_FLAG_LOST                   = 8;
-const int CTF_BLUE_FLAG_CARRYING               = 12;
-const int CTF_YELLOW_FLAG_TAKEN                        = 16;
-const int CTF_YELLOW_FLAG_LOST                 = 32;
-const int CTF_YELLOW_FLAG_CARRYING             = 48;
-const int CTF_PINK_FLAG_TAKEN                  = 64;
-const int CTF_PINK_FLAG_LOST                   = 128;
-const int CTF_PINK_FLAG_CARRYING               = 192;
-const int CTF_NEUTRAL_FLAG_TAKEN               = 256;
-const int CTF_NEUTRAL_FLAG_LOST                        = 512;
-const int CTF_NEUTRAL_FLAG_CARRYING            = 768;
-const int CTF_FLAG_NEUTRAL                             = 2048;
-const int CTF_SHIELDED                                 = 4096;
-#endif
-
-#ifdef IMPLEMENTATION
-
-#ifdef SVQC
-#include "../../../common/vehicles/all.qh"
-#include "../../teamplay.qh"
+#include <common/vehicles/all.qh>
+#include <server/teamplay.qh>
 #endif
 
-#include "../../../lib/warpzone/common.qh"
+#include <lib/warpzone/common.qh>
 
 bool autocvar_g_ctf_allow_vehicle_carry;
 bool autocvar_g_ctf_allow_vehicle_touch;
@@ -310,9 +137,9 @@ void ctf_CaptureRecord(entity flag, entity player)
 
        // notify about shit
        if(ctf_oneflag) { Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_CTF_CAPTURE_NEUTRAL, player.netname); }
-       else if(!ctf_captimerecord) { Send_Notification(NOTIF_ALL, world, MSG_CHOICE, APP_TEAM_ENT_4(flag, CHOICE_CTF_CAPTURE_TIME_), player.netname, (cap_time * 100)); }
-       else if(cap_time < cap_record) { Send_Notification(NOTIF_ALL, world, MSG_CHOICE, APP_TEAM_ENT_4(flag, CHOICE_CTF_CAPTURE_BROKEN_), player.netname, refername, (cap_time * 100), (cap_record * 100)); }
-       else { Send_Notification(NOTIF_ALL, world, MSG_CHOICE, APP_TEAM_ENT_4(flag, CHOICE_CTF_CAPTURE_UNBROKEN_), player.netname, refername, (cap_time * 100), (cap_record * 100)); }
+       else if(!ctf_captimerecord) { Send_Notification(NOTIF_ALL, world, MSG_CHOICE, APP_TEAM_ENT(flag, CHOICE_CTF_CAPTURE_TIME), player.netname, (cap_time * 100)); }
+       else if(cap_time < cap_record) { Send_Notification(NOTIF_ALL, world, MSG_CHOICE, APP_TEAM_ENT(flag, CHOICE_CTF_CAPTURE_BROKEN), player.netname, refername, (cap_time * 100), (cap_record * 100)); }
+       else { Send_Notification(NOTIF_ALL, world, MSG_CHOICE, APP_TEAM_ENT(flag, CHOICE_CTF_CAPTURE_UNBROKEN), player.netname, refername, (cap_time * 100), (cap_record * 100)); }
 
        // write that shit in the database
        if(!ctf_oneflag) // but not in 1-flag mode
@@ -401,7 +228,6 @@ bool ctf_CheckPassDirection(vector head_center, vector passer_center, vector pas
 bool ctf_CaptureShield_CheckStatus(entity p)
 {
        int s, s2, s3, s4, se, se2, se3, se4, sr, ser;
-       entity e;
        int players_worseeq, players_total;
 
        if(ctf_captureshield_max_ratio <= 0)
@@ -418,21 +244,20 @@ bool ctf_CaptureShield_CheckStatus(entity p)
                return false;
 
        players_total = players_worseeq = 0;
-       FOR_EACH_PLAYER(e)
-       {
-               if(DIFF_TEAM(e, p))
+       FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
+               if(DIFF_TEAM(it, p))
                        continue;
-               se = PlayerScore_Add(e, SP_CTF_CAPS, 0);
-               se2 = PlayerScore_Add(e, SP_CTF_PICKUPS, 0);
-               se3 = PlayerScore_Add(e, SP_CTF_RETURNS, 0);
-               se4 = PlayerScore_Add(e, SP_CTF_FCKILLS, 0);
+               se = PlayerScore_Add(it, SP_CTF_CAPS, 0);
+               se2 = PlayerScore_Add(it, SP_CTF_PICKUPS, 0);
+               se3 = PlayerScore_Add(it, SP_CTF_RETURNS, 0);
+               se4 = PlayerScore_Add(it, SP_CTF_FCKILLS, 0);
 
                ser = ((se - se2) + (se3 + se4));
 
                if(ser <= sr)
                        ++players_worseeq;
                ++players_total;
-       }
+       ));
 
        // player is in the worse half, if >= half the players are better than him, or consequently, if < half of the players are worse
        // use this rule here
@@ -512,7 +337,7 @@ void ctf_Handle_Drop(entity flag, entity player, int droptype)
        flag.ctf_status = FLAG_DROPPED;
 
        // messages and sounds
-       Send_Notification(NOTIF_ALL, world, MSG_INFO, ((flag.team) ? APP_TEAM_ENT_4(flag, INFO_CTF_LOST_) : INFO_CTF_LOST_NEUTRAL), player.netname);
+       Send_Notification(NOTIF_ALL, world, MSG_INFO, ((flag.team) ? APP_TEAM_ENT(flag, INFO_CTF_LOST) : INFO_CTF_LOST_NEUTRAL), player.netname);
        _sound(flag, CH_TRIGGER, flag.snd_flag_dropped, VOL_BASE, ATTEN_NONE);
        ctf_EventLog("dropped", player.team, player);
 
@@ -544,7 +369,6 @@ void ctf_Handle_Drop(entity flag, entity player, int droptype)
 
 void ctf_Handle_Retrieve(entity flag, entity player)
 {
-       entity tmp_player; // temporary entity which the FOR_EACH_PLAYER loop uses to scan players
        entity sender = flag.pass_sender;
 
        // transfer flag to player
@@ -573,15 +397,14 @@ void ctf_Handle_Retrieve(entity flag, entity player)
        _sound(player, CH_TRIGGER, flag.snd_flag_pass, VOL_BASE, ATTEN_NORM);
        ctf_EventLog("receive", flag.team, player);
 
-       FOR_EACH_REALPLAYER(tmp_player)
-       {
-               if(tmp_player == sender)
-                       Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, ((flag.team) ? APP_TEAM_ENT_4(flag, CENTER_CTF_PASS_SENT_) : CENTER_CTF_PASS_SENT_NEUTRAL), player.netname);
-               else if(tmp_player == player)
-                       Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, ((flag.team) ? APP_TEAM_ENT_4(flag, CENTER_CTF_PASS_RECEIVED_) : CENTER_CTF_PASS_RECEIVED_NEUTRAL), sender.netname);
-               else if(SAME_TEAM(tmp_player, sender))
-                       Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, ((flag.team) ? APP_TEAM_ENT_4(flag, CENTER_CTF_PASS_OTHER_) : CENTER_CTF_PASS_OTHER_NEUTRAL), sender.netname, player.netname);
-       }
+       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), LAMBDA(
+               if(it == sender)
+                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, ((flag.team) ? APP_TEAM_ENT(flag, CENTER_CTF_PASS_SENT) : CENTER_CTF_PASS_SENT_NEUTRAL), player.netname);
+               else if(it == player)
+                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, ((flag.team) ? APP_TEAM_ENT(flag, CENTER_CTF_PASS_RECEIVED) : CENTER_CTF_PASS_RECEIVED_NEUTRAL), sender.netname);
+               else if(SAME_TEAM(it, sender))
+                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, ((flag.team) ? APP_TEAM_ENT(flag, CENTER_CTF_PASS_OTHER) : CENTER_CTF_PASS_OTHER_NEUTRAL), sender.netname, player.netname);
+       ));
 
        // create new waypoint
        ctf_FlagcarrierWaypoints(player);
@@ -688,6 +511,8 @@ void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
 // Event Handlers
 // ==============
 
+void nades_GiveBonus(entity player, float score);
+
 void ctf_Handle_Capture(entity flag, entity toucher, int capturetype)
 {
        entity enemy_flag = ((capturetype == CAPTURE_NORMAL) ? toucher.flagcarried : toucher);
@@ -712,7 +537,7 @@ void ctf_Handle_Capture(entity flag, entity toucher, int capturetype)
        player.throw_count = 0;
 
        // messages and sounds
-       Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((enemy_flag.team) ? APP_TEAM_ENT_4(enemy_flag, CENTER_CTF_CAPTURE_) : CENTER_CTF_CAPTURE_NEUTRAL));
+       Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((enemy_flag.team) ? APP_TEAM_ENT(enemy_flag, CENTER_CTF_CAPTURE) : CENTER_CTF_CAPTURE_NEUTRAL));
        ctf_CaptureRecord(enemy_flag, player);
        _sound(player, CH_TRIGGER, ((ctf_oneflag) ? player_team_flag.snd_flag_capture : ((DIFF_TEAM(player, flag)) ? enemy_flag.snd_flag_capture : flag.snd_flag_capture)), VOL_BASE, ATTEN_NONE);
 
@@ -756,12 +581,12 @@ void ctf_Handle_Return(entity flag, entity player)
        // messages and sounds
        if(IS_MONSTER(player))
        {
-               Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(flag, INFO_CTF_RETURN_MONSTER_), player.monster_name);
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT(flag, INFO_CTF_RETURN_MONSTER), player.monster_name);
        }
        else if(flag.team)
        {
-               Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_ENT_4(flag, CENTER_CTF_RETURN_));
-               Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(flag, INFO_CTF_RETURN_), player.netname);
+               Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_ENT(flag, CENTER_CTF_RETURN));
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT(flag, INFO_CTF_RETURN), player.netname);
        }
        _sound(player, CH_TRIGGER, flag.snd_flag_returned, VOL_BASE, ATTEN_NONE);
        ctf_EventLog("return", flag.team, player);
@@ -796,7 +621,6 @@ void ctf_Handle_Pickup(entity flag, entity player, int pickuptype)
 {
        // declarations
        float pickup_dropped_score; // used to calculate dropped pickup score
-       entity tmp_entity; // temporary entity
 
        // attach the flag to the player
        flag.owner = player;
@@ -828,28 +652,25 @@ void ctf_Handle_Pickup(entity flag, entity player, int pickuptype)
        }
 
        // messages and sounds
-       Send_Notification(NOTIF_ALL, world, MSG_INFO, ((flag.team) ? APP_TEAM_ENT_4(flag, INFO_CTF_PICKUP_) : INFO_CTF_PICKUP_NEUTRAL), player.netname);
+       Send_Notification(NOTIF_ALL, world, MSG_INFO, ((flag.team) ? APP_TEAM_ENT(flag, INFO_CTF_PICKUP) : INFO_CTF_PICKUP_NEUTRAL), player.netname);
        if(ctf_stalemate) { Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_STALEMATE_CARRIER); }
        if(!flag.team) { Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PICKUP_NEUTRAL); }
-       else if(CTF_DIFFTEAM(player, flag)) { Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_ENT_4(flag, CENTER_CTF_PICKUP_)); }
+       else if(CTF_DIFFTEAM(player, flag)) { Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_ENT(flag, CENTER_CTF_PICKUP)); }
        else { Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((SAME_TEAM(player, flag)) ? CENTER_CTF_PICKUP_TEAM : CENTER_CTF_PICKUP_TEAM_ENEMY), Team_ColorCode(flag.team)); }
 
-       Send_Notification(NOTIF_TEAM_EXCEPT, player, MSG_CHOICE, ((flag.team) ? APP_TEAM_ENT_4(flag, CHOICE_CTF_PICKUP_TEAM_) : CHOICE_CTF_PICKUP_TEAM_NEUTRAL), Team_ColorCode(player.team), player.netname);
+       Send_Notification(NOTIF_TEAM_EXCEPT, player, MSG_CHOICE, ((flag.team) ? APP_TEAM_ENT(flag, CHOICE_CTF_PICKUP_TEAM) : CHOICE_CTF_PICKUP_TEAM_NEUTRAL), Team_ColorCode(player.team), player.netname);
 
        if(!flag.team)
-       FOR_EACH_PLAYER(tmp_entity)
-       if(tmp_entity != player)
-       if(DIFF_TEAM(player, tmp_entity))
-               Send_Notification(NOTIF_ONE, tmp_entity, MSG_CHOICE, CHOICE_CTF_PICKUP_ENEMY_NEUTRAL, Team_ColorCode(player.team), player.netname);
+               FOREACH_CLIENT(IS_PLAYER(it) && it != player && DIFF_TEAM(it, player), LAMBDA(Send_Notification(NOTIF_ONE, it, MSG_CHOICE, CHOICE_CTF_PICKUP_ENEMY_NEUTRAL, Team_ColorCode(player.team), player.netname)));
 
        if(flag.team)
-       FOR_EACH_PLAYER(tmp_entity)
-       if(tmp_entity != player)
-       if(CTF_SAMETEAM(flag, tmp_entity))
-       if(SAME_TEAM(player, tmp_entity))
-               Send_Notification(NOTIF_ONE, tmp_entity, MSG_CHOICE, APP_TEAM_ENT_4(flag, CHOICE_CTF_PICKUP_TEAM_), Team_ColorCode(player.team), player.netname);
-       else
-               Send_Notification(NOTIF_ONE, tmp_entity, MSG_CHOICE, ((SAME_TEAM(flag, player)) ? CHOICE_CTF_PICKUP_ENEMY_TEAM : CHOICE_CTF_PICKUP_ENEMY), Team_ColorCode(player.team), player.netname);
+               FOREACH_CLIENT(IS_PLAYER(it) && it != player, LAMBDA(
+                       if(CTF_SAMETEAM(flag, it))
+                       if(SAME_TEAM(player, it))
+                               Send_Notification(NOTIF_ONE, it, MSG_CHOICE, APP_TEAM_ENT(flag, CHOICE_CTF_PICKUP_TEAM), Team_ColorCode(player.team), player.netname);
+                       else
+                               Send_Notification(NOTIF_ONE, it, MSG_CHOICE, ((SAME_TEAM(flag, player)) ? CHOICE_CTF_PICKUP_ENEMY_TEAM : CHOICE_CTF_PICKUP_ENEMY), Team_ColorCode(player.team), player.netname);
+               ));
 
        _sound(player, CH_TRIGGER, flag.snd_flag_taken, VOL_BASE, ATTEN_NONE);
 
@@ -910,14 +731,14 @@ void ctf_CheckFlagReturn(entity flag, int returntype)
                {
                        switch(returntype)
                        {
-                               case RETURN_DROPPED: Send_Notification(NOTIF_ALL, world, MSG_INFO, ((flag.team) ? APP_TEAM_ENT_4(flag, INFO_CTF_FLAGRETURN_DROPPED_) : INFO_CTF_FLAGRETURN_DROPPED_NEUTRAL)); break;
-                               case RETURN_DAMAGE: Send_Notification(NOTIF_ALL, world, MSG_INFO, ((flag.team) ? APP_TEAM_ENT_4(flag, INFO_CTF_FLAGRETURN_DAMAGED_) : INFO_CTF_FLAGRETURN_DAMAGED_NEUTRAL)); break;
-                               case RETURN_SPEEDRUN: Send_Notification(NOTIF_ALL, world, MSG_INFO, ((flag.team) ? APP_TEAM_ENT_4(flag, INFO_CTF_FLAGRETURN_SPEEDRUN_) : INFO_CTF_FLAGRETURN_SPEEDRUN_NEUTRAL), ctf_captimerecord); break;
-                               case RETURN_NEEDKILL: Send_Notification(NOTIF_ALL, world, MSG_INFO, ((flag.team) ? APP_TEAM_ENT_4(flag, INFO_CTF_FLAGRETURN_NEEDKILL_) : INFO_CTF_FLAGRETURN_NEEDKILL_NEUTRAL)); break;
+                               case RETURN_DROPPED: Send_Notification(NOTIF_ALL, world, MSG_INFO, ((flag.team) ? APP_TEAM_ENT(flag, INFO_CTF_FLAGRETURN_DROPPED) : INFO_CTF_FLAGRETURN_DROPPED_NEUTRAL)); break;
+                               case RETURN_DAMAGE: Send_Notification(NOTIF_ALL, world, MSG_INFO, ((flag.team) ? APP_TEAM_ENT(flag, INFO_CTF_FLAGRETURN_DAMAGED) : INFO_CTF_FLAGRETURN_DAMAGED_NEUTRAL)); break;
+                               case RETURN_SPEEDRUN: Send_Notification(NOTIF_ALL, world, MSG_INFO, ((flag.team) ? APP_TEAM_ENT(flag, INFO_CTF_FLAGRETURN_SPEEDRUN) : INFO_CTF_FLAGRETURN_SPEEDRUN_NEUTRAL), ctf_captimerecord); break;
+                               case RETURN_NEEDKILL: Send_Notification(NOTIF_ALL, world, MSG_INFO, ((flag.team) ? APP_TEAM_ENT(flag, INFO_CTF_FLAGRETURN_NEEDKILL) : INFO_CTF_FLAGRETURN_NEEDKILL_NEUTRAL)); break;
 
                                default:
                                case RETURN_TIMEOUT:
-                                       { Send_Notification(NOTIF_ALL, world, MSG_INFO, ((flag.team) ? APP_TEAM_ENT_4(flag, INFO_CTF_FLAGRETURN_TIMEOUT_) : INFO_CTF_FLAGRETURN_TIMEOUT_NEUTRAL)); break; }
+                                       { Send_Notification(NOTIF_ALL, world, MSG_INFO, ((flag.team) ? APP_TEAM_ENT(flag, INFO_CTF_FLAGRETURN_TIMEOUT) : INFO_CTF_FLAGRETURN_TIMEOUT_NEUTRAL)); break; }
                        }
                        _sound(flag, CH_TRIGGER, flag.snd_flag_respawn, VOL_BASE, ATTEN_NONE);
                        ctf_EventLog("returned", flag.team, world);
@@ -999,34 +820,33 @@ void ctf_CheckStalemate()
 
                if (!wpforenemy_announced)
                {
-                       FOR_EACH_REALPLAYER(tmp_entity)
-                               Send_Notification(NOTIF_ONE, tmp_entity, MSG_CENTER, ((tmp_entity.flagcarried) ? CENTER_CTF_STALEMATE_CARRIER : CENTER_CTF_STALEMATE_OTHER));
+                       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), LAMBDA(Send_Notification(NOTIF_ONE, it, MSG_CENTER, ((it.flagcarried) ? CENTER_CTF_STALEMATE_CARRIER : CENTER_CTF_STALEMATE_OTHER))));
 
                        wpforenemy_announced = true;
                }
        }
 }
 
-void ctf_FlagDamage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
-{SELFPARAM();
+void ctf_FlagDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{
        if(ITEM_DAMAGE_NEEDKILL(deathtype))
        {
                if(autocvar_g_ctf_flag_return_damage_delay)
                {
-                       self.ctf_flagdamaged = true;
+                       this.ctf_flagdamaged = true;
                }
                else
                {
-                       self.health = 0;
-                       ctf_CheckFlagReturn(self, RETURN_NEEDKILL);
+                       this.health = 0;
+                       ctf_CheckFlagReturn(this, RETURN_NEEDKILL);
                }
                return;
        }
        if(autocvar_g_ctf_flag_return_damage)
        {
                // reduce health and check if it should be returned
-               self.health = self.health - damage;
-               ctf_CheckFlagReturn(self, RETURN_DAMAGE);
+               this.health = this.health - damage;
+               ctf_CheckFlagReturn(this, RETURN_DAMAGE);
                return;
        }
 }
@@ -1040,8 +860,7 @@ void ctf_FlagThink()
 
        // captureshield
        if(self == ctf_worldflaglist) // only for the first flag
-               FOR_EACH_CLIENT(tmp_entity)
-                       ctf_CaptureShield_Update(tmp_entity, 1); // release shield only
+               FOREACH_CLIENT(true, LAMBDA(ctf_CaptureShield_Update(it, 1))); // release shield only
 
        // sanity checks
        if(self.mins != CTF_FLAG.m_mins || self.maxs != CTF_FLAG.m_maxs) { // reset the flag boundaries in case it got squished
@@ -1154,7 +973,7 @@ void ctf_FlagThink()
                        WarpZone_TraceLine(self.origin, targ_origin, MOVE_NOMONSTERS, self);
 
                        if((self.pass_target == world)
-                               || (self.pass_target.deadflag != DEAD_NO)
+                               || (IS_DEAD(self.pass_target))
                                || (self.pass_target.flagcarried)
                                || (vlen(self.origin - targ_origin) > autocvar_g_ctf_pass_radius)
                                || ((trace_fraction < 1) && (trace_ent != self.pass_target))
@@ -1199,10 +1018,10 @@ METHOD(Flag, giveTo, bool(Flag this, entity flag, entity toucher))
        }
 
        int num_perteam = 0;
-       entity tmp_entity; FOR_EACH_PLAYER(tmp_entity) if(SAME_TEAM(toucher, tmp_entity)) { ++num_perteam; }
+       FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(toucher, it), LAMBDA(++num_perteam));
 
        // special touch behaviors
-       if(toucher.frozen) { return; }
+       if(STAT(FROZEN, toucher)) { return; }
        else if(IS_VEHICLE(toucher))
        {
                if(autocvar_g_ctf_allow_vehicle_touch && toucher.owner)
@@ -1225,7 +1044,7 @@ METHOD(Flag, giveTo, bool(Flag this, entity flag, entity toucher))
                }
                return;
        }
-       else if(toucher.deadflag != DEAD_NO) { return; }
+       else if(IS_DEAD(toucher)) { return; }
 
        switch(flag.ctf_status)
        {
@@ -1267,7 +1086,7 @@ METHOD(Flag, giveTo, bool(Flag this, entity flag, entity toucher))
 
                case FLAG_PASSING:
                {
-                       if((IS_PLAYER(toucher)) && (toucher.deadflag == DEAD_NO) && (toucher != flag.pass_sender))
+                       if((IS_PLAYER(toucher)) && !IS_DEAD(toucher) && (toucher != flag.pass_sender))
                        {
                                if(DIFF_TEAM(toucher, flag.pass_sender))
                                        ctf_Handle_Return(flag, toucher);
@@ -1365,6 +1184,8 @@ void ctf_DelayedFlagSetup() // called after a flag is placed on a map by ctf_Fla
        ctf_CaptureShield_Spawn(self);
 }
 
+.bool pushable;
+
 void ctf_FlagSetup(int teamnumber, entity flag) // called when spawning a flag entity on the map as a spawnfunc
 {SELFPARAM();
        // declarations
@@ -1389,7 +1210,7 @@ void ctf_FlagSetup(int teamnumber, entity flag) // called when spawning a flag e
        flag.event_damage = ctf_FlagDamage;
        flag.pushable = true;
        flag.teleportable = TELEPORT_NORMAL;
-       flag.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
+       flag.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP;
        flag.damagedbytriggers = autocvar_g_ctf_flag_return_when_unreachable;
        flag.damagedbycontents = autocvar_g_ctf_flag_return_when_unreachable;
        flag.velocity = '0 0 0';
@@ -1548,16 +1369,14 @@ int havocbot_ctf_teamcount(entity bot, vector org, float tc_radius)
                return 0;
 
        int c = 0;
-       entity head;
 
-       FOR_EACH_PLAYER(head)
-       {
-               if(DIFF_TEAM(head, bot) || head.deadflag != DEAD_NO || head == bot)
+       FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
+               if(DIFF_TEAM(it, bot) || IS_DEAD(it) || it == bot)
                        continue;
 
-               if(vlen(head.origin - org) < tc_radius)
+               if(vlen(it.origin - org) < tc_radius)
                        ++c;
-       }
+       ));
 
        return c;
 }
@@ -1697,10 +1516,10 @@ void havocbot_goalrating_ctf_carrieritems(float ratingscale, vector org, float s
 void havocbot_ctf_reset_role(entity bot)
 {
        float cdefense, cmiddle, coffense;
-       entity mf, ef, head;
+       entity mf, ef;
        float c;
 
-       if(bot.deadflag != DEAD_NO)
+       if(IS_DEAD(bot))
                return;
 
        if(vlen(havocbot_ctf_middlepoint)==0)
@@ -1732,9 +1551,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(SAME_TEAM(head, bot))
-               ++c;
+       FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(it, bot), LAMBDA(++c));
 
        if(c==1)
        {
@@ -1762,7 +1579,7 @@ void havocbot_ctf_reset_role(entity bot)
 
 void havocbot_role_ctf_carrier()
 {SELFPARAM();
-       if(self.deadflag != DEAD_NO)
+       if(IS_DEAD(self))
        {
                havocbot_ctf_reset_role(self);
                return;
@@ -1805,7 +1622,7 @@ void havocbot_role_ctf_escort()
 {SELFPARAM();
        entity mf, ef;
 
-       if(self.deadflag != DEAD_NO)
+       if(IS_DEAD(self))
        {
                havocbot_ctf_reset_role(self);
                return;
@@ -1866,7 +1683,7 @@ void havocbot_role_ctf_offense()
        entity mf, ef;
        vector pos;
 
-       if(self.deadflag != DEAD_NO)
+       if(IS_DEAD(self))
        {
                havocbot_ctf_reset_role(self);
                return;
@@ -1947,7 +1764,7 @@ void havocbot_role_ctf_retriever()
 {SELFPARAM();
        entity mf;
 
-       if(self.deadflag != DEAD_NO)
+       if(IS_DEAD(self))
        {
                havocbot_ctf_reset_role(self);
                return;
@@ -1995,7 +1812,7 @@ void havocbot_role_ctf_middle()
 {SELFPARAM();
        entity mf;
 
-       if(self.deadflag != DEAD_NO)
+       if(IS_DEAD(self))
        {
                havocbot_ctf_reset_role(self);
                return;
@@ -2046,7 +1863,7 @@ void havocbot_role_ctf_defense()
 {SELFPARAM();
        entity mf;
 
-       if(self.deadflag != DEAD_NO)
+       if(IS_DEAD(self))
        {
                havocbot_ctf_reset_role(self);
                return;
@@ -2086,20 +1903,16 @@ void havocbot_role_ctf_defense()
                navigation_goalrating_start();
 
                // if enemies are closer to our base, go there
-               entity head, closestplayer = world;
+               entity closestplayer = world;
                float distance, bestdistance = 10000;
-               FOR_EACH_PLAYER(head)
-               {
-                       if(head.deadflag!=DEAD_NO)
-                               continue;
-
-                       distance = vlen(org - head.origin);
+               FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it), LAMBDA(
+                       distance = vlen(org - it.origin);
                        if(distance<bestdistance)
                        {
-                               closestplayer = head;
+                               closestplayer = it;
                                bestdistance = distance;
                        }
-               }
+               ));
 
                if(closestplayer)
                if(DIFF_TEAM(closestplayer, self))
@@ -2233,7 +2046,7 @@ MUTATOR_HOOKFUNCTION(ctf, PlayerDamage_Calculate) // for changing damage and for
                        frag_force *= autocvar_g_ctf_flagcarrier_forcefactor;
                }
        }
-       else if(frag_target.flagcarried && (frag_target.deadflag == DEAD_NO) && CTF_DIFFTEAM(frag_target, frag_attacker)) // if the target is a flagcarrier
+       else if(frag_target.flagcarried && !IS_DEAD(frag_target) && CTF_DIFFTEAM(frag_target, frag_attacker)) // if the target is a flagcarrier
        {
                if(autocvar_g_ctf_flagcarrier_auto_helpme_damage > ('1 0 0' * healtharmor_maxdamage(frag_target.health, frag_target.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id)))
                if(time > frag_target.wps_helpme_time + autocvar_g_ctf_flagcarrier_auto_helpme_time)
@@ -2250,7 +2063,7 @@ MUTATOR_HOOKFUNCTION(ctf, PlayerDies)
 {
        if((frag_attacker != frag_target) && (IS_PLAYER(frag_attacker)) && (frag_target.flagcarried))
        {
-               PlayerTeamScore_AddScore(frag_attacker, autocvar_g_ctf_score_kill);
+               PlayerTeamScore_AddScore(frag_attacker, ((SAME_TEAM(frag_attacker, frag_target)) ? -autocvar_g_ctf_score_kill : autocvar_g_ctf_score_kill));
                PlayerScore_Add(frag_attacker, SP_CTF_FCKILLS, 1);
        }
 
@@ -2310,7 +2123,7 @@ MUTATOR_HOOKFUNCTION(ctf, PlayerUseKey)
 
        entity player = self;
 
-       if((time > player.throw_antispam) && (player.deadflag == DEAD_NO) && !player.speedrunning && (!player.vehicle || autocvar_g_ctf_allow_vehicle_touch))
+       if((time > player.throw_antispam) && !IS_DEAD(player) && !player.speedrunning && (!player.vehicle || autocvar_g_ctf_allow_vehicle_touch))
        {
                // pass the flag to a team mate
                if(autocvar_g_ctf_pass)
@@ -2320,7 +2133,7 @@ MUTATOR_HOOKFUNCTION(ctf, PlayerUseKey)
 
                        while(head) // find the closest acceptable target to pass to
                        {
-                               if(IS_PLAYER(head) && head.deadflag == DEAD_NO)
+                               if(IS_PLAYER(head) && !IS_DEAD(head))
                                if(head != player && SAME_TEAM(head, player))
                                if(!head.speedrunning && !head.vehicle)
                                {
@@ -2455,7 +2268,7 @@ MUTATOR_HOOKFUNCTION(ctf, AbortSpeedrun)
 {SELFPARAM();
        if(self.flagcarried)
        {
-               Send_Notification(NOTIF_ALL, world, MSG_INFO, ((self.flagcarried.team) ? APP_TEAM_ENT_4(self.flagcarried, INFO_CTF_FLAGRETURN_ABORTRUN_) : INFO_CTF_FLAGRETURN_ABORTRUN_NEUTRAL));
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, ((self.flagcarried.team) ? APP_TEAM_ENT(self.flagcarried, INFO_CTF_FLAGRETURN_ABORTRUN) : INFO_CTF_FLAGRETURN_ABORTRUN_NEUTRAL));
                ctf_RespawnFlag(self.flagcarried);
                return true;
        }
@@ -2547,7 +2360,6 @@ MUTATOR_HOOKFUNCTION(ctf, SV_ParseClientCommand)
                if(!g_ctf)
                        return true;
 
-               entity _player;
                int _team = 0;
                bool found = false;
 
@@ -2562,16 +2374,15 @@ MUTATOR_HOOKFUNCTION(ctf, SV_ParseClientCommand)
                        }
                }
 
-               FOR_EACH_PLAYER(_player)
-               {
-                       if(_player.flagcarried && (_player.team == _team || _team == 0))
+               FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
+                       if(it.flagcarried && (it.team == _team || _team == 0))
                        {
                                found = true;
-                               if(_team == 0 && IS_SPEC(self) && self.enemy == _player)
-                                       continue; // already spectating a fc, try to find the other fc
-                               return superspec_Spectate(_player);
+                               if(_team == 0 && IS_SPEC(self) && self.enemy == it)
+                                       continue; // already spectating this fc, try another
+                               return superspec_Spectate(it);
                        }
-               }
+               ));
 
                if(!found)
                        superspec_msg("", "", self, "No active flag carrier\n", 1);
@@ -2735,7 +2546,7 @@ void ctf_ScoreRules(int teams)
 // code from here on is just to support maps that don't have flag and team entities
 void ctf_SpawnTeam (string teamname, int teamcolor)
 {
-       entity this = new(ctf_team);
+       entity this = new_pure(ctf_team);
        this.netname = teamname;
        this.cnt = teamcolor;
        this.spawnfunc_checked = true;