]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/mutators/gamemode_ctf.qc
Clean up a bunch of gamemode specific code
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / mutators / gamemode_ctf.qc
index 0c68bbfd0ff122aae3bc048ce595556d8dcf7dc6..016f9bd47a034ab31f651a40d9706afab771e8b5 100644 (file)
@@ -9,6 +9,75 @@
 
 #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)
 {
        msg_entity = e;
@@ -1889,7 +1958,7 @@ void havocbot_role_ctf_setrole(entity bot, int role)
 // Hook Functions
 // ==============
 
-MUTATOR_HOOKFUNCTION(ctf_PlayerPreThink)
+MUTATOR_HOOKFUNCTION(ctfPlayerPreThink)
 {SELFPARAM();
        entity flag;
        int t = 0, t2 = 0, t3 = 0;
@@ -1941,7 +2010,7 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerPreThink)
        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
        {
@@ -1969,7 +2038,7 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerDamage) // for changing damage and force values t
        return false;
 }
 
-MUTATOR_HOOKFUNCTION(ctf_PlayerDies)
+MUTATOR_HOOKFUNCTION(ctfPlayerDies)
 {
        if((frag_attacker != frag_target) && (IS_PLAYER(frag_attacker)) && (frag_target.flagcarried))
        {
@@ -1987,30 +2056,38 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerDies)
        return false;
 }
 
-MUTATOR_HOOKFUNCTION(ctf_GiveFragsForKill)
+MUTATOR_HOOKFUNCTION(ctfGiveFragsForKill)
 {
        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(ctfPortalTeleport)
 {SELFPARAM();
        if(self.flagcarried)
        if(!autocvar_g_ctf_portalteleport)
@@ -2019,7 +2096,7 @@ MUTATOR_HOOKFUNCTION(ctf_PortalTeleport)
        return false;
 }
 
-MUTATOR_HOOKFUNCTION(ctf_PlayerUseKey)
+MUTATOR_HOOKFUNCTION(ctfPlayerUseKey)
 {SELFPARAM();
        if(MUTATOR_RETURNVALUE || gameover) { return false; }
 
@@ -2112,7 +2189,7 @@ MUTATOR_HOOKFUNCTION(ctf_PlayerUseKey)
        return false;
 }
 
-MUTATOR_HOOKFUNCTION(ctf_HelpMePing)
+MUTATOR_HOOKFUNCTION(ctfHelpMePing)
 {SELFPARAM();
        if(self.wps_flagcarrier) // update the flagcarrier waypointsprite with "NEEDING HELP" notification
        {
@@ -2128,7 +2205,7 @@ MUTATOR_HOOKFUNCTION(ctf_HelpMePing)
        return true;
 }
 
-MUTATOR_HOOKFUNCTION(ctf_VehicleEnter)
+MUTATOR_HOOKFUNCTION(ctfVehicleEnter)
 {
        if(vh_player.flagcarried)
        {
@@ -2151,7 +2228,7 @@ MUTATOR_HOOKFUNCTION(ctf_VehicleEnter)
        return false;
 }
 
-MUTATOR_HOOKFUNCTION(ctf_VehicleExit)
+MUTATOR_HOOKFUNCTION(ctfVehicleExit)
 {
        if(vh_player.flagcarried)
        {
@@ -2166,7 +2243,7 @@ MUTATOR_HOOKFUNCTION(ctf_VehicleExit)
        return false;
 }
 
-MUTATOR_HOOKFUNCTION(ctf_AbortSpeedrun)
+MUTATOR_HOOKFUNCTION(ctfAbortSpeedrun)
 {SELFPARAM();
        if(self.flagcarried)
        {
@@ -2178,7 +2255,7 @@ MUTATOR_HOOKFUNCTION(ctf_AbortSpeedrun)
        return false;
 }
 
-MUTATOR_HOOKFUNCTION(ctf_MatchEnd)
+MUTATOR_HOOKFUNCTION(ctfMatchEnd)
 {
        entity flag; // temporary entity for the search method
 
@@ -2212,25 +2289,98 @@ MUTATOR_HOOKFUNCTION(ctf_MatchEnd)
        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(ctfGetTeamCount)
 {
        //ret_float = ctf_teams;
        ret_string = "ctf_team";
        return true;
 }
 
-MUTATOR_HOOKFUNCTION(ctf_SpectateCopy)
+MUTATOR_HOOKFUNCTION(ctfSpectateCopy)
 {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
@@ -2426,25 +2576,11 @@ void ctf_Initialize()
        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
        {