#include "gamemode_ctf.qh"
-#include "../_all.qh"
#include "gamemode.qh"
#ifdef SVQC
#include "../../common/vehicles/all.qh"
+#include "../teamplay.qh"
#endif
-#include "../../warpzonelib/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_allow_monster_touch;
+bool autocvar_g_ctf_throw;
+float autocvar_g_ctf_throw_angle_max;
+float autocvar_g_ctf_throw_angle_min;
+int autocvar_g_ctf_throw_punish_count;
+float autocvar_g_ctf_throw_punish_delay;
+float autocvar_g_ctf_throw_punish_time;
+float autocvar_g_ctf_throw_strengthmultiplier;
+float autocvar_g_ctf_throw_velocity_forward;
+float autocvar_g_ctf_throw_velocity_up;
+float autocvar_g_ctf_drop_velocity_up;
+float autocvar_g_ctf_drop_velocity_side;
+bool autocvar_g_ctf_oneflag_reverse;
+bool autocvar_g_ctf_portalteleport;
+bool autocvar_g_ctf_pass;
+float autocvar_g_ctf_pass_arc;
+float autocvar_g_ctf_pass_arc_max;
+float autocvar_g_ctf_pass_directional_max;
+float autocvar_g_ctf_pass_directional_min;
+float autocvar_g_ctf_pass_radius;
+float autocvar_g_ctf_pass_wait;
+bool autocvar_g_ctf_pass_request;
+float autocvar_g_ctf_pass_turnrate;
+float autocvar_g_ctf_pass_timelimit;
+float autocvar_g_ctf_pass_velocity;
+bool autocvar_g_ctf_dynamiclights;
+float autocvar_g_ctf_flag_collect_delay;
+float autocvar_g_ctf_flag_damageforcescale;
+bool autocvar_g_ctf_flag_dropped_waypoint;
+bool autocvar_g_ctf_flag_dropped_floatinwater;
+bool autocvar_g_ctf_flag_glowtrails;
+int autocvar_g_ctf_flag_health;
+bool autocvar_g_ctf_flag_return;
+float autocvar_g_ctf_flag_return_carried_radius;
+float autocvar_g_ctf_flag_return_time;
+bool autocvar_g_ctf_flag_return_when_unreachable;
+float autocvar_g_ctf_flag_return_damage;
+float autocvar_g_ctf_flag_return_damage_delay;
+float autocvar_g_ctf_flag_return_dropped;
+float autocvar_g_ctf_flagcarrier_auto_helpme_damage;
+float autocvar_g_ctf_flagcarrier_auto_helpme_time;
+float autocvar_g_ctf_flagcarrier_selfdamagefactor;
+float autocvar_g_ctf_flagcarrier_selfforcefactor;
+float autocvar_g_ctf_flagcarrier_damagefactor;
+float autocvar_g_ctf_flagcarrier_forcefactor;
+//float autocvar_g_ctf_flagcarrier_waypointforenemy_spotting;
+bool autocvar_g_ctf_fullbrightflags;
+bool autocvar_g_ctf_ignore_frags;
+int autocvar_g_ctf_score_capture;
+int autocvar_g_ctf_score_capture_assist;
+int autocvar_g_ctf_score_kill;
+int autocvar_g_ctf_score_penalty_drop;
+int autocvar_g_ctf_score_penalty_returned;
+int autocvar_g_ctf_score_pickup_base;
+int autocvar_g_ctf_score_pickup_dropped_early;
+int autocvar_g_ctf_score_pickup_dropped_late;
+int autocvar_g_ctf_score_return;
+float autocvar_g_ctf_shield_force;
+float autocvar_g_ctf_shield_max_ratio;
+int autocvar_g_ctf_shield_min_negscore;
+bool autocvar_g_ctf_stalemate;
+int autocvar_g_ctf_stalemate_endcondition;
+float autocvar_g_ctf_stalemate_time;
+bool autocvar_g_ctf_reverse;
+float autocvar_g_ctf_dropped_capture_delay;
+float autocvar_g_ctf_dropped_capture_radius;
void ctf_FakeTimeLimit(entity e, float t)
{
void ctf_FlagcarrierWaypoints(entity player)
{
WaypointSprite_Spawn(WP_FlagCarrier, 0, 0, player, FLAG_WAYPOINT_OFFSET, world, player.team, player, wps_flagcarrier, true, RADARICON_FLAG);
- 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_UpdateMaxHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(start_health, start_armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id) * 2);
+ WaypointSprite_UpdateHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(player.health, player.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id));
WaypointSprite_UpdateTeamRadar(player.wps_flagcarrier, RADARICON_FLAGCARRIER, WPCOLOR_FLAGCARRIER(player.team));
}
vector mymid = (self.absmin + self.absmax) * 0.5;
vector othermid = (other.absmin + other.absmax) * 0.5;
- Damage(other, self, self, 0, DEATH_HURTTRIGGER, mymid, normalize(othermid - mymid) * ctf_captureshield_force);
+ Damage(other, self, self, 0, DEATH_HURTTRIGGER.m_id, mymid, normalize(othermid - mymid) * ctf_captureshield_force);
if(IS_REAL_CLIENT(other)) { Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_CTF_CAPTURESHIELD_SHIELDED); }
}
// 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);
- sound(flag, CH_TRIGGER, flag.snd_flag_dropped, VOL_BASE, ATTEN_NONE);
+ _sound(flag, CH_TRIGGER, flag.snd_flag_dropped, VOL_BASE, ATTEN_NONE);
ctf_EventLog("dropped", player.team, player);
// scoring
flag.ctf_status = FLAG_CARRY;
// messages and sounds
- sound(player, CH_TRIGGER, flag.snd_flag_pass, VOL_BASE, ATTEN_NORM);
+ _sound(player, CH_TRIGGER, flag.snd_flag_pass, VOL_BASE, ATTEN_NORM);
ctf_EventLog("receive", flag.team, player);
FOR_EACH_REALPLAYER(tmp_player)
flag.ctf_status = FLAG_PASSING;
// other
- sound(player, CH_TRIGGER, flag.snd_flag_touch, VOL_BASE, ATTEN_NORM);
+ _sound(player, CH_TRIGGER, flag.snd_flag_touch, VOL_BASE, ATTEN_NORM);
WarpZone_TrailParticles(world, _particleeffectnum(flag.passeffect), player.origin, targ_origin);
ctf_EventLog("pass", flag.team, player);
break;
// 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));
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);
+ _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);
switch(capturetype)
{
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);
}
- sound(player, CH_TRIGGER, flag.snd_flag_returned, VOL_BASE, ATTEN_NONE);
+ _sound(player, CH_TRIGGER, flag.snd_flag_returned, VOL_BASE, ATTEN_NONE);
ctf_EventLog("return", flag.team, player);
// scoring
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);
- sound(player, CH_TRIGGER, flag.snd_flag_taken, VOL_BASE, ATTEN_NONE);
+ _sound(player, CH_TRIGGER, flag.snd_flag_taken, VOL_BASE, ATTEN_NONE);
// scoring
PlayerScore_Add(player, SP_CTF_PICKUPS, 1);
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; }
}
- sound(flag, CH_TRIGGER, flag.snd_flag_respawn, VOL_BASE, ATTEN_NONE);
+ _sound(flag, CH_TRIGGER, flag.snd_flag_respawn, VOL_BASE, ATTEN_NONE);
ctf_EventLog("returned", flag.team, world);
ctf_RespawnFlag(flag);
}
if(time > self.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);
+ _sound(self, CH_TRIGGER, self.snd_flag_touch, VOL_BASE, ATTEN_NORM);
self.wait = time + FLAG_TOUCHRATE;
}
return;
void ctf_FlagSetup(int teamnumber, entity flag) // called when spawning a flag entity on the map as a spawnfunc
{SELFPARAM();
// declarations
- string teamname = Static_Team_ColorName_Lower(teamnumber);
setself(flag); // for later usage with droptofloor()
// main setup
flag.nextthink = time + FLAG_THINKRATE;
flag.ctf_status = FLAG_BASE;
+ string teamname = Static_Team_ColorName_Lower(teamnumber);
// appearence
if(!flag.scale) { flag.scale = FLAG_SCALE; }
if(flag.skin == 0) { flag.skin = cvar(sprintf("g_ctf_flag_%s_skin", teamname)); }
set_flag_string(flag, capeffect, "%s_cap", teamname);
// sounds
- set_flag_string(flag, snd_flag_taken, "ctf/%s_taken.wav", teamname);
- set_flag_string(flag, snd_flag_returned, "ctf/%s_returned.wav", teamname);
- set_flag_string(flag, snd_flag_capture, "ctf/%s_capture.wav", teamname);
- set_flag_string(flag, snd_flag_dropped, "ctf/%s_dropped.wav", teamname);
- if(flag.snd_flag_respawn == "") { flag.snd_flag_respawn = "ctf/flag_respawn.wav"; } // if there is ever a team-based sound for this, update the code to match.
- if(flag.snd_flag_touch == "") { flag.snd_flag_touch = "ctf/touch.wav"; } // again has no team-based sound
- if(flag.snd_flag_pass == "") { flag.snd_flag_pass = "ctf/pass.wav"; } // same story here
-
- // precache
- precache_sound(flag.snd_flag_taken);
- precache_sound(flag.snd_flag_returned);
- precache_sound(flag.snd_flag_capture);
+ 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.
precache_sound(flag.snd_flag_respawn);
- precache_sound(flag.snd_flag_dropped);
+ if (flag.snd_flag_touch == "") flag.snd_flag_touch = 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
precache_sound(flag.snd_flag_pass);
+
+ // precache
precache_model(flag.model);
// appearence
{
// Can't navigate to my own base, suicide!
// TODO: drop it and wander around
- Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0');
+ Damage(self, self, self, 100000, DEATH_KILL.m_id, self.origin, '0 0 0');
return;
}
}
// Hook Functions
// ==============
-MUTATOR_HOOKFUNCTION(ctf_PlayerPreThink)
+MUTATOR_HOOKFUNCTION(ctf, PlayerPreThink)
{SELFPARAM();
entity flag;
int t = 0, t2 = 0, t3 = 0;
// update the health of the flag carrier waypointsprite
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));
+ WaypointSprite_UpdateHealth(self.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(self.health, self.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id));
return false;
}
-MUTATOR_HOOKFUNCTION(ctf_PlayerDamage) // for changing damage and force values that are applied to players in g_damage.qc
+MUTATOR_HOOKFUNCTION(ctf, PlayerDamage_Calculate) // for changing damage and force values that are applied to players in g_damage.qc
{
if(frag_attacker.flagcarried) // if the attacker is a flagcarrier
{
}
else if(frag_target.flagcarried && (frag_target.deadflag == DEAD_NO) && 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)))
+ 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)
{
frag_target.wps_helpme_time = time;
return false;
}
-MUTATOR_HOOKFUNCTION(ctf_PlayerDies)
+MUTATOR_HOOKFUNCTION(ctf, PlayerDies)
{
if((frag_attacker != frag_target) && (IS_PLAYER(frag_attacker)) && (frag_target.flagcarried))
{
return false;
}
-MUTATOR_HOOKFUNCTION(ctf_GiveFragsForKill)
+MUTATOR_HOOKFUNCTION(ctf, GiveFragsForKill)
{
frag_score = 0;
return (autocvar_g_ctf_ignore_frags); // no frags counted in ctf if this is true
}
-MUTATOR_HOOKFUNCTION(ctf_RemovePlayer)
-{SELFPARAM();
- entity flag; // temporary entity for the search method
-
- if(self.flagcarried)
- { ctf_Handle_Throw(self, world, DROP_NORMAL); }
+void ctf_RemovePlayer(entity player)
+{
+ if(player.flagcarried)
+ { ctf_Handle_Throw(player, world, DROP_NORMAL); }
- for(flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext)
+ for(entity flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext)
{
- if(flag.pass_sender == self) { flag.pass_sender = world; }
- if(flag.pass_target == self) { flag.pass_target = world; }
- if(flag.ctf_dropper == self) { flag.ctf_dropper = world; }
+ if(flag.pass_sender == player) { flag.pass_sender = world; }
+ if(flag.pass_target == player) { flag.pass_target = world; }
+ if(flag.ctf_dropper == player) { flag.ctf_dropper = world; }
}
+}
+MUTATOR_HOOKFUNCTION(ctf, MakePlayerObserver)
+{SELFPARAM();
+ ctf_RemovePlayer(self);
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(ctf, ClientDisconnect)
+{SELFPARAM();
+ ctf_RemovePlayer(self);
return false;
}
-MUTATOR_HOOKFUNCTION(ctf_PortalTeleport)
+MUTATOR_HOOKFUNCTION(ctf, PortalTeleport)
{SELFPARAM();
if(self.flagcarried)
if(!autocvar_g_ctf_portalteleport)
return false;
}
-MUTATOR_HOOKFUNCTION(ctf_PlayerUseKey)
+MUTATOR_HOOKFUNCTION(ctf, PlayerUseKey)
{SELFPARAM();
if(MUTATOR_RETURNVALUE || gameover) { return false; }
return false;
}
-MUTATOR_HOOKFUNCTION(ctf_HelpMePing)
+MUTATOR_HOOKFUNCTION(ctf, HelpMePing)
{SELFPARAM();
if(self.wps_flagcarrier) // update the flagcarrier waypointsprite with "NEEDING HELP" notification
{
return true;
}
-MUTATOR_HOOKFUNCTION(ctf_VehicleEnter)
+MUTATOR_HOOKFUNCTION(ctf, VehicleEnter)
{
if(vh_player.flagcarried)
{
return false;
}
-MUTATOR_HOOKFUNCTION(ctf_VehicleExit)
+MUTATOR_HOOKFUNCTION(ctf, VehicleExit)
{
if(vh_player.flagcarried)
{
return false;
}
-MUTATOR_HOOKFUNCTION(ctf_AbortSpeedrun)
+MUTATOR_HOOKFUNCTION(ctf, AbortSpeedrun)
{SELFPARAM();
if(self.flagcarried)
{
return false;
}
-MUTATOR_HOOKFUNCTION(ctf_MatchEnd)
+MUTATOR_HOOKFUNCTION(ctf, MatchEnd)
{
entity flag; // temporary entity for the search method
return false;
}
-MUTATOR_HOOKFUNCTION(ctf_BotRoles)
+MUTATOR_HOOKFUNCTION(ctf, HavocBot_ChooseRole)
{SELFPARAM();
havocbot_ctf_reset_role(self);
return true;
}
-MUTATOR_HOOKFUNCTION(ctf_GetTeamCount)
+MUTATOR_HOOKFUNCTION(ctf, GetTeamCount)
{
//ret_float = ctf_teams;
ret_string = "ctf_team";
return true;
}
-MUTATOR_HOOKFUNCTION(ctf_SpectateCopy)
+MUTATOR_HOOKFUNCTION(ctf, SpectateCopy)
{SELFPARAM();
self.ctf_flagstatus = other.ctf_flagstatus;
return false;
}
+MUTATOR_HOOKFUNCTION(ctf, GetRecords)
+{
+ for(int i = record_page * 200; i < MapInfo_count && i < record_page * 200 + 200; ++i)
+ {
+ if (MapInfo_Get_ByID(i))
+ {
+ float r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
+
+ if(!r)
+ continue;
+
+ // TODO: uid2name
+ string h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
+ ret_string = strcat(ret_string, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n");
+ }
+ }
+
+ return false;
+}
+
+bool superspec_Spectate(entity _player); // TODO
+void superspec_msg(string _center_title, string _con_title, entity _to, string _msg, float _spamlevel); // TODO
+MUTATOR_HOOKFUNCTION(ctf, SV_ParseClientCommand)
+{
+ if(IS_PLAYER(self) || MUTATOR_RETURNVALUE || !cvar("g_superspectate")) { return false; }
+
+ if(cmd_name == "followfc")
+ {
+ if(!g_ctf)
+ return true;
+
+ entity _player;
+ int _team = 0;
+ bool found = false;
+
+ if(cmd_argc == 2)
+ {
+ switch(argv(1))
+ {
+ case "red": _team = NUM_TEAM_1; break;
+ case "blue": _team = NUM_TEAM_2; break;
+ case "yellow": if(ctf_teams >= 3) _team = NUM_TEAM_3; break;
+ case "pink": if(ctf_teams >= 4) _team = NUM_TEAM_4; break;
+ }
+ }
+
+ FOR_EACH_PLAYER(_player)
+ {
+ if(_player.flagcarried && (_player.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(!found)
+ superspec_msg("", "", self, "No active flag carrier\n", 1);
+ return true;
+ }
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(ctf, DropSpecialItems)
+{
+ if(frag_target.flagcarried)
+ ctf_Handle_Throw(frag_target, world, DROP_THROW);
+
+ return false;
+}
+
// ==========
// Spawnfuncs
"noise3" sound played when flag is lost in the field and respawns itself...
"noise4" sound played when flag is dropped by a player...
"noise5" sound played when flag touches the ground... */
-void spawnfunc_item_flag_team1()
-{SELFPARAM();
+spawnfunc(item_flag_team1)
+{
if(!g_ctf) { remove(self); return; }
ctf_FlagSetup(NUM_TEAM_1, self);
"noise3" sound played when flag is lost in the field and respawns itself...
"noise4" sound played when flag is dropped by a player...
"noise5" sound played when flag touches the ground... */
-void spawnfunc_item_flag_team2()
-{SELFPARAM();
+spawnfunc(item_flag_team2)
+{
if(!g_ctf) { remove(self); return; }
ctf_FlagSetup(NUM_TEAM_2, self);
"noise3" sound played when flag is lost in the field and respawns itself...
"noise4" sound played when flag is dropped by a player...
"noise5" sound played when flag touches the ground... */
-void spawnfunc_item_flag_team3()
-{SELFPARAM();
+spawnfunc(item_flag_team3)
+{
if(!g_ctf) { remove(self); return; }
ctf_FlagSetup(NUM_TEAM_3, self);
"noise3" sound played when flag is lost in the field and respawns itself...
"noise4" sound played when flag is dropped by a player...
"noise5" sound played when flag touches the ground... */
-void spawnfunc_item_flag_team4()
-{SELFPARAM();
+spawnfunc(item_flag_team4)
+{
if(!g_ctf) { remove(self); return; }
ctf_FlagSetup(NUM_TEAM_4, self);
"noise3" sound played when flag is lost in the field and respawns itself...
"noise4" sound played when flag is dropped by a player...
"noise5" sound played when flag touches the ground... */
-void spawnfunc_item_flag_neutral()
-{SELFPARAM();
+spawnfunc(item_flag_neutral)
+{
if(!g_ctf) { remove(self); return; }
if(!cvar("g_ctf_oneflag")) { remove(self); return; }
Keys:
"netname" Name of the team (for example Red, Blue, Green, Yellow, Life, Death, Offense, Defense, etc)...
"cnt" Scoreboard color of the team (for example 4 is red and 13 is blue)... */
-void spawnfunc_ctf_team()
-{SELFPARAM();
+spawnfunc(ctf_team)
+{
if(!g_ctf) { remove(self); return; }
self.classname = "ctf_team";
}
// compatibility for quake maps
-void spawnfunc_team_CTF_redflag() { spawnfunc_item_flag_team1(); }
-void spawnfunc_team_CTF_blueflag() { spawnfunc_item_flag_team2(); }
-void spawnfunc_team_CTF_redplayer() { spawnfunc_info_player_team1(); }
-void spawnfunc_team_CTF_blueplayer() { spawnfunc_info_player_team2(); }
-void spawnfunc_team_CTF_redspawn() { spawnfunc_info_player_team1(); }
-void spawnfunc_team_CTF_bluespawn() { spawnfunc_info_player_team2(); }
+spawnfunc(team_CTF_redflag) { spawnfunc_item_flag_team1(this); }
+spawnfunc(team_CTF_blueflag) { spawnfunc_item_flag_team2(this); }
+spawnfunc(info_player_team1);
+spawnfunc(team_CTF_redplayer) { spawnfunc_info_player_team1(this); }
+spawnfunc(team_CTF_redspawn) { spawnfunc_info_player_team1(this); }
+spawnfunc(info_player_team2);
+spawnfunc(team_CTF_blueplayer) { spawnfunc_info_player_team2(this); }
+spawnfunc(team_CTF_bluespawn) { spawnfunc_info_player_team2(this); }
-void team_CTF_neutralflag() { spawnfunc_item_flag_neutral(); }
-void team_neutralobelisk() { spawnfunc_item_flag_neutral(); }
+void team_CTF_neutralflag() { SELFPARAM(); spawnfunc_item_flag_neutral(self); }
+void team_neutralobelisk() { SELFPARAM(); spawnfunc_item_flag_neutral(self); }
// ==============
// code from here on is just to support maps that don't have flag and team entities
void ctf_SpawnTeam (string teamname, int teamcolor)
-{SELFPARAM();
- setself(spawn());
- self.classname = "ctf_team";
- self.netname = teamname;
- self.cnt = teamcolor;
-
- spawnfunc_ctf_team();
-
- setself(this);
+{
+ entity this = new(ctf_team);
+ this.netname = teamname;
+ this.cnt = teamcolor;
+ this.spawnfunc_checked = true;
+ WITH(entity, self, this, spawnfunc_ctf_team(this));
}
void ctf_DelayedInit() // Do this check with a delay so we can wait for teams to be set up.
InitializeEntity(world, ctf_DelayedInit, INITPRIO_GAMETYPE);
}
-
-MUTATOR_DEFINITION(gamemode_ctf)
+REGISTER_MUTATOR(ctf, g_ctf)
{
- MUTATOR_HOOK(MakePlayerObserver, ctf_RemovePlayer, CBC_ORDER_ANY);
- MUTATOR_HOOK(ClientDisconnect, ctf_RemovePlayer, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerDies, ctf_PlayerDies, CBC_ORDER_ANY);
- MUTATOR_HOOK(MatchEnd, ctf_MatchEnd, CBC_ORDER_ANY);
- MUTATOR_HOOK(PortalTeleport, ctf_PortalTeleport, CBC_ORDER_ANY);
- MUTATOR_HOOK(GiveFragsForKill, ctf_GiveFragsForKill, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerPreThink, ctf_PlayerPreThink, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerDamage_Calculate, ctf_PlayerDamage, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerUseKey, ctf_PlayerUseKey, CBC_ORDER_ANY);
- MUTATOR_HOOK(HelpMePing, ctf_HelpMePing, CBC_ORDER_ANY);
- MUTATOR_HOOK(VehicleEnter, ctf_VehicleEnter, CBC_ORDER_ANY);
- MUTATOR_HOOK(VehicleExit, ctf_VehicleExit, CBC_ORDER_ANY);
- MUTATOR_HOOK(AbortSpeedrun, ctf_AbortSpeedrun, CBC_ORDER_ANY);
- MUTATOR_HOOK(HavocBot_ChooseRole, ctf_BotRoles, CBC_ORDER_ANY);
- MUTATOR_HOOK(GetTeamCount, ctf_GetTeamCount, CBC_ORDER_ANY);
- MUTATOR_HOOK(SpectateCopy, ctf_SpectateCopy, CBC_ORDER_ANY);
+ ActivateTeamplay();
+ SetLimits(autocvar_capturelimit_override, -1, autocvar_captureleadlimit_override, -1);
+ have_team_spawns = -1; // request team spawns
MUTATOR_ONADD
{