}
}
+bool ctf_Immediate_Return_Allowed(entity flag, entity toucher)
+{
+ int num_perteam = 0;
+ FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(toucher, it), { ++num_perteam; });
+
+ // automatically return if there's only 1 player on the team
+ return ((autocvar_g_ctf_flag_return || num_perteam <= 1 || (autocvar_g_ctf_flag_return_carrying && toucher.flagcarried))
+ && flag.team);
+}
+
bool ctf_Return_Customize(entity this, entity client)
{
// only to the carrier
else if(CTF_DIFFTEAM(player, flag))
Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_NUM(flag.team, 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_ONE, player, MSG_CENTER, ((SAME_TEAM(player, flag)) ? CENTER_CTF_PICKUP_RETURN : CENTER_CTF_PICKUP_RETURN_ENEMY), Team_ColorCode(flag.team));
Send_Notification(NOTIF_TEAM_EXCEPT, player, MSG_CHOICE, APP_NUM(flag.team, CHOICE_CTF_PICKUP_TEAM), Team_ColorCode(player.team), player.netname);
if(ITEM_DAMAGE_NEEDKILL(deathtype))
{
if(autocvar_g_ctf_flag_return_damage_delay)
- {
- this.ctf_flagdamaged = true;
- }
+ this.ctf_flagdamaged_byworld = true;
else
{
this.health = 0;
LOG_TRACE("wtf the flag got squashed?");
tracebox(this.origin, CTF_FLAG.m_mins, CTF_FLAG.m_maxs, this.origin, MOVE_NOMONSTERS, this);
if(!trace_startsolid || this.noalign) // can we resize it without getting stuck?
- setsize(this, CTF_FLAG.m_mins, CTF_FLAG.m_maxs); }
-
- switch(this.ctf_status) // reset flag angles in case warpzones adjust it
- {
- case FLAG_DROPPED:
- {
- this.angles = '0 0 0';
- break;
- }
-
- default: break;
+ setsize(this, CTF_FLAG.m_mins, CTF_FLAG.m_maxs);
}
// main think method
case FLAG_DROPPED:
{
+ this.angles = '0 0 0'; // reset flag angles in case warpzones adjust it
+
if(autocvar_g_ctf_flag_dropped_floatinwater)
{
vector midpoint = ((this.absmin + this.absmax) * 0.5);
return;
}
}
- if(this.ctf_flagdamaged)
+ if(this.ctf_flagdamaged_byworld)
{
this.health -= ((this.max_flag_health / autocvar_g_ctf_flag_return_damage_delay) * FLAG_THINKRATE);
ctf_CheckFlagReturn(this, RETURN_NEEDKILL);
METHOD(Flag, giveTo, bool(Flag this, entity flag, entity toucher))
{
return = false;
- if(gameover) { return; }
+ if(game_stopped) return;
if(trace_dphitcontents & (DPCONTENTS_PLAYERCLIP | DPCONTENTS_MONSTERCLIP)) { return; }
bool is_not_monster = (!IS_MONSTER(toucher));
flag.health = 0;
ctf_CheckFlagReturn(flag, RETURN_NEEDKILL);
}
- if(!flag.ctf_flagdamaged) { return; }
+ if(!flag.ctf_flagdamaged_byworld) { return; }
}
- int num_perteam = 0;
- FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(toucher, it), LAMBDA(++num_perteam));
-
// special touch behaviors
if(STAT(FROZEN, toucher)) { return; }
else if(IS_VEHICLE(toucher))
case FLAG_DROPPED:
{
- 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
+ if(CTF_SAMETEAM(toucher, flag) && ctf_Immediate_Return_Allowed(flag, toucher))
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
if((IS_PLAYER(toucher)) && !IS_DEAD(toucher) && (toucher != flag.pass_sender))
{
if(DIFF_TEAM(toucher, flag.pass_sender))
- ctf_Handle_Return(flag, toucher);
- else
+ {
+ if(ctf_Immediate_Return_Allowed(flag, toucher))
+ ctf_Handle_Return(flag, toucher);
+ else if(is_not_monster && (!toucher.flagcarried))
+ ctf_Handle_Pickup(flag, toucher, PICKUP_DROPPED);
+ }
+ else if(!toucher.flagcarried)
ctf_Handle_Retrieve(flag, toucher);
}
break;
flag.ctf_dropper = NULL;
flag.ctf_pickuptime = 0;
flag.ctf_droptime = 0;
- flag.ctf_flagdamaged = 0;
+ flag.ctf_flagdamaged_byworld = false;
ctf_CheckStalemate();
}
entity f;
vector s = '0 0 0';
vector fo = '0 0 0';
- float n = 0;
+ int n = 0;
f = ctf_worldflaglist;
while (f)
fo = f.origin;
s = s + fo;
f = f.ctf_worldflagnext;
+ n++;
}
if(!n)
return;
- havocbot_ctf_middlepoint = s * (1.0 / n);
- havocbot_ctf_middlepoint_radius = vlen(fo - havocbot_ctf_middlepoint);
+ havocbot_ctf_middlepoint = s / n;
+ havocbot_ctf_middlepoint_radius = vlen(fo - havocbot_ctf_middlepoint);
}
mf = havocbot_ctf_find_flag(this);
if(mf.ctf_status==FLAG_BASE)
{
+ if(this.goalcurrent == mf)
+ {
+ navigation_clearroute(this);
+ this.bot_strategytime = 0;
+ }
havocbot_ctf_reset_role(this);
return;
}
WaypointSprite_UpdateHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(player.health, player.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id));
}
-MUTATOR_HOOKFUNCTION(ctf, PlayerDamage_Calculate) // for changing damage and force values that are applied to players in g_damage.qc
+MUTATOR_HOOKFUNCTION(ctf, Damage_Calculate) // for changing damage and force values that are applied to players in g_damage.qc
{
entity frag_attacker = M_ARGV(1, entity);
entity frag_target = M_ARGV(2, entity);
MUTATOR_HOOKFUNCTION(ctf, PlayerUseKey)
{
- if(MUTATOR_RETURNVALUE || gameover) { return; }
+ if(MUTATOR_RETURNVALUE || game_stopped) return;
entity player = M_ARGV(0, entity);
player.throw_antispam = time + autocvar_g_ctf_pass_wait;
return true;
}
- else if(player.flagcarried)
+ else if(player.flagcarried && !head.flagcarried)
{
if(closest_target)
{
spawnfunc(team_CTF_neutralflag) { spawnfunc_item_flag_neutral(this); }
spawnfunc(team_neutralobelisk) { spawnfunc_item_flag_neutral(this); }
+// compatibility for wop maps
+spawnfunc(team_redplayer) { spawnfunc_info_player_team1(this); }
+spawnfunc(team_blueplayer) { spawnfunc_info_player_team2(this); }
+spawnfunc(team_ctl_redlolly) { spawnfunc_item_flag_team1(this); }
+spawnfunc(team_CTL_redlolly) { spawnfunc_item_flag_team1(this); }
+spawnfunc(team_ctl_bluelolly) { spawnfunc_item_flag_team2(this); }
+spawnfunc(team_CTL_bluelolly) { spawnfunc_item_flag_team2(this); }
+
// ==============
// Initialization