REGISTER_MUTATOR(ctf, false)
{
- ActivateTeamplay();
- SetLimits(autocvar_capturelimit_override, -1, autocvar_captureleadlimit_override, -1);
- have_team_spawns = -1; // request team spawns
-
MUTATOR_ONADD
{
if (time > 1) // game loads at time 1
error("This is a game type and it cannot be added at runtime.");
ctf_Initialize();
+
+ ActivateTeamplay();
+ SetLimits(autocvar_capturelimit_override, autocvar_captureleadlimit_override, -1, -1);
+ have_team_spawns = -1; // request team spawns
}
MUTATOR_ONROLLBACK_OR_REMOVE
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?
-#define FLAG_MIN (PL_MIN_CONST + '0 0 -13')
-#define FLAG_MAX (PL_MAX_CONST + '0 0 -13')
const float FLAG_SCALE = 0.6;
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
#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;
+.int ctf_flagstatus = _STAT(CTF_FLAGSTATUS);
#endif
const int CTF_RED_FLAG_TAKEN = 1;
#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;
bool autocvar_g_ctf_flag_glowtrails;
int autocvar_g_ctf_flag_health;
bool autocvar_g_ctf_flag_return;
+bool autocvar_g_ctf_flag_return_carrying;
float autocvar_g_ctf_flag_return_carried_radius;
float autocvar_g_ctf_flag_return_time;
bool autocvar_g_ctf_flag_return_when_unreachable;
// 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
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)
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
void ctf_CaptureShield_Spawn(entity flag)
{SELFPARAM();
- entity shield = spawn();
+ entity shield = new(ctf_captureshield);
shield.enemy = self;
shield.team = self.team;
shield.touch = ctf_CaptureShield_Touch;
shield.customizeentityforclient = ctf_CaptureShield_Customize;
- shield.classname = "ctf_captureshield";
shield.effects = EF_ADDITIVE;
shield.movetype = MOVETYPE_NOCLIP;
shield.solid = SOLID_TRIGGER;
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);
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
_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);
ctf_CaptureShield_Update(player, 0); // shield player from picking up flag
}
+void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
+{
+ return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
+}
// ==============
// Event Handlers
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);
// 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);
{
// 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;
}
// 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);
{
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);
return true;
}
-void ctf_CheckStalemate(void)
+void ctf_CheckStalemate()
{
// declarations
int stale_flags = 0, stale_red_flags = 0, stale_blue_flags = 0, stale_yellow_flags = 0, stale_pink_flags = 0, stale_neutral_flags = 0;
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;
}
}
// 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 != FLAG_MIN || self.maxs != FLAG_MAX) { // reset the flag boundaries in case it got squished
+ if(self.mins != CTF_FLAG.m_mins || self.maxs != CTF_FLAG.m_maxs) { // reset the flag boundaries in case it got squished
LOG_TRACE("wtf the flag got squashed?\n");
- tracebox(self.origin, FLAG_MIN, FLAG_MAX, self.origin, MOVE_NOMONSTERS, self);
+ tracebox(self.origin, CTF_FLAG.m_mins, CTF_FLAG.m_maxs, self.origin, MOVE_NOMONSTERS, self);
if(!trace_startsolid || self.noalign) // can we resize it without getting stuck?
- setsize(self, FLAG_MIN, FLAG_MAX); }
+ setsize(self, CTF_FLAG.m_mins, CTF_FLAG.m_maxs); }
switch(self.ctf_status) // reset flag angles in case warpzones adjust it
{
ctf_CheckFlagReturn(self, RETURN_SPEEDRUN);
setself(self.owner);
- self.impulse = CHIMPULSE_SPEEDRUN; // move the player back to the waypoint they set
- ImpulseCommands();
+ self.impulse = CHIMPULSE_SPEEDRUN.impulse; // move the player back to the waypoint they set
+ ImpulseCommands(self);
setself(this);
}
if(autocvar_g_ctf_stalemate)
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))
}
}
-void ctf_FlagTouch()
-{SELFPARAM();
+METHOD(Flag, giveTo, bool(Flag this, entity flag, entity toucher))
+{
+ return = false;
if(gameover) { return; }
if(trace_dphitcontents & (DPCONTENTS_PLAYERCLIP | DPCONTENTS_MONSTERCLIP)) { return; }
- entity toucher = other, tmp_entity;
- bool is_not_monster = (!IS_MONSTER(toucher)), num_perteam = 0;
+ bool is_not_monster = (!IS_MONSTER(toucher));
// automatically kill the flag and return it if it touched lava/slime/nodrop surfaces
if(ITEM_TOUCH_NEEDKILL())
{
if(!autocvar_g_ctf_flag_return_damage_delay)
{
- self.health = 0;
- ctf_CheckFlagReturn(self, RETURN_NEEDKILL);
+ flag.health = 0;
+ ctf_CheckFlagReturn(flag, RETURN_NEEDKILL);
}
- if(!self.ctf_flagdamaged) { return; }
+ if(!flag.ctf_flagdamaged) { return; }
}
- FOR_EACH_PLAYER(tmp_entity) if(SAME_TEAM(toucher, tmp_entity)) { ++num_perteam; }
+ int num_perteam = 0;
+ 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)
}
else if (!IS_PLAYER(toucher)) // The flag just touched an object, most likely the world
{
- if(time > self.wait) // if we haven't in a while, play a sound/effect
+ if(time > flag.wait) // if we haven't in a while, play a sound/effect
{
- Send_Effect_(self.toucheffect, self.origin, '0 0 0', 1);
- _sound(self, CH_TRIGGER, self.snd_flag_touch, VOL_BASE, ATTEN_NORM);
- self.wait = time + FLAG_TOUCHRATE;
+ Send_Effect_(flag.toucheffect, flag.origin, '0 0 0', 1);
+ _sound(flag, CH_TRIGGER, flag.snd_flag_touch, VOL_BASE, ATTEN_NORM);
+ flag.wait = time + FLAG_TOUCHRATE;
}
return;
}
- else if(toucher.deadflag != DEAD_NO) { return; }
+ else if(IS_DEAD(toucher)) { return; }
- switch(self.ctf_status)
+ switch(flag.ctf_status)
{
case FLAG_BASE:
{
if(ctf_oneflag)
{
- if(CTF_SAMETEAM(toucher, self) && (toucher.flagcarried) && !toucher.flagcarried.team && is_not_monster)
- ctf_Handle_Capture(self, toucher, CAPTURE_NORMAL); // toucher just captured the neutral flag to enemy base
- else if(!self.team && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && is_not_monster)
- ctf_Handle_Pickup(self, toucher, PICKUP_BASE); // toucher just stole the neutral flag
+ if(CTF_SAMETEAM(toucher, flag) && (toucher.flagcarried) && !toucher.flagcarried.team && is_not_monster)
+ ctf_Handle_Capture(flag, toucher, CAPTURE_NORMAL); // toucher just captured the neutral flag to enemy base
+ else if(!flag.team && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && is_not_monster)
+ ctf_Handle_Pickup(flag, toucher, PICKUP_BASE); // toucher just stole the neutral flag
}
- else if(CTF_SAMETEAM(toucher, self) && (toucher.flagcarried) && DIFF_TEAM(toucher.flagcarried, self) && is_not_monster)
- ctf_Handle_Capture(self, toucher, CAPTURE_NORMAL); // toucher just captured the enemies flag to his base
- else if(CTF_DIFFTEAM(toucher, self) && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && is_not_monster)
- ctf_Handle_Pickup(self, toucher, PICKUP_BASE); // toucher just stole the enemies flag
+ else if(CTF_SAMETEAM(toucher, flag) && (toucher.flagcarried) && DIFF_TEAM(toucher.flagcarried, flag) && is_not_monster)
+ ctf_Handle_Capture(flag, toucher, CAPTURE_NORMAL); // toucher just captured the enemies flag to his base
+ else if(CTF_DIFFTEAM(toucher, flag) && (toucher.flagcarried) && CTF_SAMETEAM(toucher.flagcarried, toucher) && (!toucher.ctf_captureshielded) && autocvar_g_ctf_flag_return_carrying && (time > toucher.next_take_time) && is_not_monster)
+ {
+ ctf_Handle_Return(toucher.flagcarried, toucher); // return their current flag
+ ctf_Handle_Pickup(flag, toucher, PICKUP_BASE); // now pickup the flag
+ }
+ else if(CTF_DIFFTEAM(toucher, flag) && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && is_not_monster)
+ ctf_Handle_Pickup(flag, toucher, PICKUP_BASE); // toucher just stole the enemies flag
break;
}
case FLAG_DROPPED:
{
- if(CTF_SAMETEAM(toucher, self) && (autocvar_g_ctf_flag_return || num_perteam <= 1) && self.team) // automatically return if there's only 1 player on the team
- ctf_Handle_Return(self, toucher); // toucher just returned his own flag
- else if(is_not_monster && (!toucher.flagcarried) && ((toucher != self.ctf_dropper) || (time > self.ctf_droptime + autocvar_g_ctf_flag_collect_delay)))
- ctf_Handle_Pickup(self, toucher, PICKUP_DROPPED); // toucher just picked up a dropped enemy flag
+ if(CTF_SAMETEAM(toucher, flag) && (autocvar_g_ctf_flag_return || num_perteam <= 1 || (autocvar_g_ctf_flag_return_carrying && toucher.flagcarried)) && flag.team) // automatically return if there's only 1 player on the team
+ ctf_Handle_Return(flag, toucher); // toucher just returned his own flag
+ else if(is_not_monster && (!toucher.flagcarried) && ((toucher != flag.ctf_dropper) || (time > flag.ctf_droptime + autocvar_g_ctf_flag_collect_delay)))
+ ctf_Handle_Pickup(flag, toucher, PICKUP_DROPPED); // toucher just picked up a dropped enemy flag
break;
}
case FLAG_PASSING:
{
- if((IS_PLAYER(toucher)) && (toucher.deadflag == DEAD_NO) && (toucher != self.pass_sender))
+ if((IS_PLAYER(toucher)) && !IS_DEAD(toucher) && (toucher != flag.pass_sender))
{
- if(DIFF_TEAM(toucher, self.pass_sender))
- ctf_Handle_Return(self, toucher);
+ if(DIFF_TEAM(toucher, flag.pass_sender))
+ ctf_Handle_Return(flag, toucher);
else
- ctf_Handle_Retrieve(self, toucher);
+ ctf_Handle_Retrieve(flag, toucher);
}
break;
}
ctf_CheckStalemate();
}
-void ctf_Reset()
-{SELFPARAM();
- if(self.owner)
- if(IS_PLAYER(self.owner))
- ctf_Handle_Throw(self.owner, world, DROP_RESET);
+void ctf_Reset(entity this)
+{
+ if(this.owner && IS_PLAYER(this.owner))
+ ctf_Handle_Throw(this.owner, world, DROP_RESET);
- ctf_RespawnFlag(self);
+ ctf_RespawnFlag(this);
}
-void ctf_DelayedFlagSetup(void) // called after a flag is placed on a map by ctf_FlagSetup()
+void ctf_DelayedFlagSetup() // called after a flag is placed on a map by ctf_FlagSetup()
{SELFPARAM();
// bot waypoints
waypoint_spawnforitem_force(self, self.origin);
ctf_CaptureShield_Spawn(self);
}
-void set_flag_string(entity flag, .string field, string value, string teamname)
-{
- if(flag.(field) == "")
- flag.(field) = strzone(sprintf(value,teamname));
-}
-
void ctf_FlagSetup(int teamnumber, entity flag) // called when spawning a flag entity on the map as a spawnfunc
{SELFPARAM();
// declarations
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';
if(!flag.scale) { flag.scale = FLAG_SCALE; }
if(flag.skin == 0) { flag.skin = cvar(sprintf("g_ctf_flag_%s_skin", teamname)); }
if(flag.model == "") { flag.model = cvar_string(sprintf("g_ctf_flag_%s_model", teamname)); }
- set_flag_string(flag, toucheffect, "%sflag_touch", teamname);
- set_flag_string(flag, passeffect, "%s_pass", teamname);
- set_flag_string(flag, capeffect, "%s_cap", teamname);
+ if (flag.toucheffect == "") { flag.toucheffect = EFFECT_FLAG_TOUCH(teamnumber).eent_eff_name; }
+ if (flag.passeffect == "") { flag.passeffect = EFFECT_PASS(teamnumber).eent_eff_name; }
+ if (flag.capeffect == "") { flag.capeffect = EFFECT_CAP(teamnumber).eent_eff_name; }
// sounds
- flag.snd_flag_taken = SND(CTF_TAKEN(teamnumber));
- flag.snd_flag_returned = SND(CTF_RETURNED(teamnumber));
- flag.snd_flag_capture = SND(CTF_CAPTURE(teamnumber));
- flag.snd_flag_dropped = SND(CTF_DROPPED(teamnumber));
- if (flag.snd_flag_respawn == "") flag.snd_flag_respawn = SND(CTF_RESPAWN); // if there is ever a team-based sound for this, update the code to match.
+ flag.snd_flag_taken = strzone(SND(CTF_TAKEN(teamnumber)));
+ flag.snd_flag_returned = strzone(SND(CTF_RETURNED(teamnumber)));
+ flag.snd_flag_capture = strzone(SND(CTF_CAPTURE(teamnumber)));
+ flag.snd_flag_dropped = strzone(SND(CTF_DROPPED(teamnumber)));
+ if (flag.snd_flag_respawn == "") flag.snd_flag_respawn = strzone(SND(CTF_RESPAWN)); // if there is ever a team-based sound for this, update the code to match.
precache_sound(flag.snd_flag_respawn);
- if (flag.snd_flag_touch == "") flag.snd_flag_touch = SND(CTF_TOUCH); // again has no team-based sound
+ if (flag.snd_flag_touch == "") flag.snd_flag_touch = strzone(SND(CTF_TOUCH)); // again has no team-based sound
precache_sound(flag.snd_flag_touch);
- if (flag.snd_flag_pass == "") flag.snd_flag_pass = SND(CTF_PASS); // same story here
+ if (flag.snd_flag_pass == "") flag.snd_flag_pass = strzone(SND(CTF_PASS)); // same story here
precache_sound(flag.snd_flag_pass);
// precache
// appearence
_setmodel(flag, flag.model); // precision set below
- setsize(flag, FLAG_MIN, FLAG_MAX);
+ setsize(flag, CTF_FLAG.m_mins, CTF_FLAG.m_maxs);
setorigin(flag, (flag.origin + FLAG_SPAWN_OFFSET));
if(autocvar_g_ctf_flag_glowtrails)
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;
}
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)
// 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)
{
void havocbot_role_ctf_carrier()
{SELFPARAM();
- if(self.deadflag != DEAD_NO)
+ if(IS_DEAD(self))
{
havocbot_ctf_reset_role(self);
return;
{SELFPARAM();
entity mf, ef;
- if(self.deadflag != DEAD_NO)
+ if(IS_DEAD(self))
{
havocbot_ctf_reset_role(self);
return;
entity mf, ef;
vector pos;
- if(self.deadflag != DEAD_NO)
+ if(IS_DEAD(self))
{
havocbot_ctf_reset_role(self);
return;
{SELFPARAM();
entity mf;
- if(self.deadflag != DEAD_NO)
+ if(IS_DEAD(self))
{
havocbot_ctf_reset_role(self);
return;
{SELFPARAM();
entity mf;
- if(self.deadflag != DEAD_NO)
+ if(IS_DEAD(self))
{
havocbot_ctf_reset_role(self);
return;
{SELFPARAM();
entity mf;
- if(self.deadflag != DEAD_NO)
+ if(IS_DEAD(self))
{
havocbot_ctf_reset_role(self);
return;
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))
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)
{
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);
}
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)
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)
{
{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;
}
if(!g_ctf)
return true;
- entity _player;
int _team = 0;
bool found = false;
}
}
- 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);
// 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;
// if no teams are found, spawn defaults
if(find(world, classname, "ctf_team") == world)
{
- LOG_INFO("No ""ctf_team"" entities found on this map, creating them anyway.\n");
+ LOG_TRACE("No \"ctf_team\" entities found on this map, creating them anyway.\n");
ctf_SpawnTeam("Red", NUM_TEAM_1 - 1);
ctf_SpawnTeam("Blue", NUM_TEAM_2 - 1);
if(ctf_teams >= 3)
ctf_captureshield_max_ratio = autocvar_g_ctf_shield_max_ratio;
ctf_captureshield_force = autocvar_g_ctf_shield_force;
- addstat(STAT_CTF_FLAGSTATUS, AS_INT, ctf_flagstatus);
-
InitializeEntity(world, ctf_DelayedInit, INITPRIO_GAMETYPE);
}