#include "gamemode_ctf.qh"
#ifndef CSQC
+#include <common/effects/all.qh>
void ctf_Initialize();
REGISTER_MUTATOR(ctf, false)
error("This is a game type and it cannot be added at runtime.");
ctf_Initialize();
- ActivateTeamplay();
- SetLimits(autocvar_capturelimit_override, autocvar_captureleadlimit_override, autocvar_timelimit_override, -1);
- have_team_spawns = -1; // request team spawns
+ GameRules_teams(true);
+ GameRules_limit_score(autocvar_capturelimit_override);
+ GameRules_limit_lead(autocvar_captureleadlimit_override);
}
MUTATOR_ONROLLBACK_OR_REMOVE
if(ctf_oneflag)
Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_CTF_CAPTURE_NEUTRAL, player.netname);
else if(!ctf_captimerecord)
- Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_CAPTURE_TIME), player.netname, (cap_time * 100));
+ Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_CAPTURE_TIME), player.netname, TIME_ENCODE(cap_time));
else if(cap_time < cap_record)
- Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_CAPTURE_BROKEN), player.netname, refername, (cap_time * 100), (cap_record * 100));
+ Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_CAPTURE_BROKEN), player.netname, refername, TIME_ENCODE(cap_time), TIME_ENCODE(cap_record));
else
- Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_CAPTURE_UNBROKEN), player.netname, refername, (cap_time * 100), (cap_record * 100));
+ Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_CAPTURE_UNBROKEN), player.netname, refername, TIME_ENCODE(cap_time), TIME_ENCODE(cap_record));
// write that shit in the database
if(!ctf_oneflag) // but not in 1-flag mode
ctf_captimerecord = cap_time;
db_put(ServerProgsDB, strcat(GetMapname(), "/captimerecord/time"), ftos(cap_time));
db_put(ServerProgsDB, strcat(GetMapname(), "/captimerecord/netname"), player.netname);
- write_recordmarker(player, (time - cap_time), cap_time);
+ write_recordmarker(player, flag.ctf_pickuptime, cap_time);
}
if(autocvar_g_ctf_leaderboard && !ctf_oneflag)
return false;
players_total = players_worseeq = 0;
- FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
+ FOREACH_CLIENT(IS_PLAYER(it), {
if(DIFF_TEAM(it, p))
continue;
se = PlayerScore_Add(it, SP_CTF_CAPS, 0);
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
_sound(player, CH_TRIGGER, flag.snd_flag_pass, VOL_BASE, ATTEN_NORM);
ctf_EventLog("receive", flag.team, player);
- FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), LAMBDA(
+ FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), {
if(it == sender)
Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_NUM(flag.team, CENTER_CTF_PASS_SENT), player.netname);
else if(it == player)
Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_NUM(flag.team, CENTER_CTF_PASS_RECEIVED), sender.netname);
else if(SAME_TEAM(it, sender))
Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_NUM(flag.team, CENTER_CTF_PASS_OTHER), sender.netname, player.netname);
- ));
+ });
// create new waypoint
ctf_FlagcarrierWaypoints(player);
Send_Notification(NOTIF_TEAM_EXCEPT, player, MSG_CHOICE, APP_NUM(flag.team, CHOICE_CTF_PICKUP_TEAM), Team_ColorCode(player.team), player.netname);
if(!flag.team)
- 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)));
+ FOREACH_CLIENT(IS_PLAYER(it) && it != player && DIFF_TEAM(it, player), { Send_Notification(NOTIF_ONE, it, MSG_CHOICE, CHOICE_CTF_PICKUP_ENEMY_NEUTRAL, Team_ColorCode(player.team), player.netname); });
if(flag.team)
- FOREACH_CLIENT(IS_PLAYER(it) && it != player, LAMBDA(
+ FOREACH_CLIENT(IS_PLAYER(it) && it != player, {
if(CTF_SAMETEAM(flag, it))
if(SAME_TEAM(player, it))
Send_Notification(NOTIF_ONE, it, MSG_CHOICE, APP_TEAM_NUM(flag.team, 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);
case RETURN_DAMAGE:
Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_DAMAGED)); break;
case RETURN_SPEEDRUN:
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_SPEEDRUN), ctf_captimerecord); break;
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_SPEEDRUN), TIME_ENCODE(ctf_captimerecord)); break;
case RETURN_NEEDKILL:
Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_NEEDKILL)); break;
default:
if (!wpforenemy_announced)
{
- 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))));
+ FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), { Send_Notification(NOTIF_ONE, it, MSG_CENTER, ((it.flagcarried) ? CENTER_CTF_STALEMATE_CARRIER : CENTER_CTF_STALEMATE_OTHER)); });
wpforenemy_announced = true;
}
// captureshield
if(this == ctf_worldflaglist) // only for the first flag
- FOREACH_CLIENT(true, LAMBDA(ctf_CaptureShield_Update(it, 1))); // release shield only
+ FOREACH_CLIENT(true, { ctf_CaptureShield_Update(it, 1); }); // release shield only
// sanity checks
if(this.mins != this.m_mins || this.maxs != this.m_maxs) { // reset the flag boundaries in case it got squished
this.health = 0;
ctf_CheckFlagReturn(this, RETURN_SPEEDRUN);
- this.owner.impulse = CHIMPULSE_SPEEDRUN.impulse; // move the player back to the waypoint they set
+ CS(this.owner).impulse = CHIMPULSE_SPEEDRUN.impulse; // move the player back to the waypoint they set
ImpulseCommands(this.owner);
}
if(autocvar_g_ctf_stalemate)
}
if(!n)
return;
- havocbot_ctf_middlepoint = s / n;
- havocbot_ctf_middlepoint_radius = vlen(fo - havocbot_ctf_middlepoint);
+
+ havocbot_middlepoint = s / n;
+ havocbot_middlepoint_radius = vlen(fo - havocbot_middlepoint);
+
+ havocbot_symmetryaxis_equation = '0 0 0';
+ if(n == 2)
+ {
+ // for symmetrical editing of waypoints
+ entity f1 = ctf_worldflaglist;
+ entity f2 = f1.ctf_worldflagnext;
+ float m = -(f1.origin.y - f2.origin.y) / (f1.origin.x - f2.origin.x);
+ float q = havocbot_middlepoint.y - m * havocbot_middlepoint.x;
+ havocbot_symmetryaxis_equation.x = m;
+ havocbot_symmetryaxis_equation.y = q;
+ }
+ // store number of flags in this otherwise unused vector component
+ havocbot_symmetryaxis_equation.z = n;
}
int c = 0;
- FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
+ FOREACH_CLIENT(IS_PLAYER(it), {
if(DIFF_TEAM(it, bot) || IS_DEAD(it) || it == bot)
continue;
if(vdist(it.origin - org, <, tc_radius))
++c;
- ));
+ });
return c;
}
// if there is only me on the team switch to offense
c = 0;
- FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(it, this), LAMBDA(++c));
+ FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(it, this), { ++c; });
if(c==1)
{
// Evaluate best position to take
// Count mates on middle position
- cmiddle = havocbot_ctf_teamcount(this, havocbot_ctf_middlepoint, havocbot_ctf_middlepoint_radius * 0.5);
+ cmiddle = havocbot_ctf_teamcount(this, havocbot_middlepoint, havocbot_middlepoint_radius * 0.5);
// Count mates on defense position
- cdefense = havocbot_ctf_teamcount(this, mf.dropped_origin, havocbot_ctf_middlepoint_radius * 0.5);
+ cdefense = havocbot_ctf_teamcount(this, mf.dropped_origin, havocbot_middlepoint_radius * 0.5);
// Count mates on offense position
- coffense = havocbot_ctf_teamcount(this, ef.dropped_origin, havocbot_ctf_middlepoint_radius);
+ coffense = havocbot_ctf_teamcount(this, ef.dropped_origin, havocbot_middlepoint_radius);
if(cdefense<=coffense)
havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_DEFENSE);
{
vector org;
- org = havocbot_ctf_middlepoint;
+ org = havocbot_middlepoint;
org.z = this.origin.z;
this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
navigation_goalrating_start(this);
havocbot_goalrating_ctf_ourstolenflag(this, 50000);
havocbot_goalrating_ctf_droppedflags(this, 30000, this.origin, 10000);
- havocbot_goalrating_enemyplayers(this, 10000, org, havocbot_ctf_middlepoint_radius * 0.5);
- havocbot_goalrating_items(this, 5000, org, havocbot_ctf_middlepoint_radius * 0.5);
+ havocbot_goalrating_enemyplayers(this, 10000, org, havocbot_middlepoint_radius * 0.5);
+ havocbot_goalrating_items(this, 5000, org, havocbot_middlepoint_radius * 0.5);
havocbot_goalrating_items(this, 2500, this.origin, 10000);
havocbot_goalrating_ctf_enemybase(this, 2500);
navigation_goalrating_end(this);
}
if (this.bot_strategytime < time)
{
- float mp_radius;
- vector org;
-
- org = mf.dropped_origin;
- mp_radius = havocbot_ctf_middlepoint_radius;
+ vector org = mf.dropped_origin;
this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
navigation_goalrating_start(this);
// if enemies are closer to our base, go there
entity closestplayer = NULL;
float distance, bestdistance = 10000;
- FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it), LAMBDA(
+ FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it), {
distance = vlen(org - it.origin);
if(distance<bestdistance)
{
closestplayer = it;
bestdistance = distance;
}
- ));
+ });
if(closestplayer)
if(DIFF_TEAM(closestplayer, this))
havocbot_goalrating_ctf_ourbase(this, 30000);
havocbot_goalrating_ctf_ourstolenflag(this, 20000);
- havocbot_goalrating_ctf_droppedflags(this, 20000, org, mp_radius);
- havocbot_goalrating_enemyplayers(this, 15000, org, mp_radius);
- havocbot_goalrating_items(this, 10000, org, mp_radius);
+ havocbot_goalrating_ctf_droppedflags(this, 20000, org, havocbot_middlepoint_radius);
+ havocbot_goalrating_enemyplayers(this, 15000, org, havocbot_middlepoint_radius);
+ havocbot_goalrating_items(this, 10000, org, havocbot_middlepoint_radius);
havocbot_goalrating_items(this, 5000, this.origin, 10000);
navigation_goalrating_end(this);
}
entity player = M_ARGV(0, entity);
- if(player.cvar_cl_allow_uidtracking == 1 && player.cvar_cl_allow_uid2name == 1)
+ if(CS(player).cvar_cl_allow_uidtracking == 1 && CS(player).cvar_cl_allow_uid2name == 1)
{
if (!player.stored_netname)
player.stored_netname = strzone(uid2name(player.crypto_idfp));
}
}
- FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
+ FOREACH_CLIENT(IS_PLAYER(it), {
if(it.flagcarried && (it.team == _team || _team == 0))
{
found = true;
continue; // already spectating this fc, try another
return superspec_Spectate(player, it);
}
- ));
+ });
if(!found)
superspec_msg("", "", player, "No active flag carrier\n", 1);
void ctf_ScoreRules(int teams)
{
CheckAllowedTeams(NULL);
- ScoreRules_basics(teams, 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);
- ScoreInfo_SetLabel_PlayerScore(SP_CTF_PICKUPS, "pickups", 0);
- ScoreInfo_SetLabel_PlayerScore(SP_CTF_FCKILLS, "fckills", 0);
- ScoreInfo_SetLabel_PlayerScore(SP_CTF_RETURNS, "returns", 0);
- ScoreInfo_SetLabel_PlayerScore(SP_CTF_DROPS, "drops", SFL_LOWER_IS_BETTER);
- ScoreRules_basics_end();
+ GameRules_scoring(teams, SFL_SORT_PRIO_PRIMARY, 0, {
+ field_team(ST_CTF_CAPS, "caps", SFL_SORT_PRIO_PRIMARY);
+ field(SP_CTF_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
+ field(SP_CTF_CAPTIME, "captime", SFL_LOWER_IS_BETTER | SFL_TIME);
+ field(SP_CTF_PICKUPS, "pickups", 0);
+ field(SP_CTF_FCKILLS, "fckills", 0);
+ field(SP_CTF_RETURNS, "returns", 0);
+ field(SP_CTF_DROPS, "drops", SFL_LOWER_IS_BETTER);
+ });
}
// code from here on is just to support maps that don't have flag and team entities