+#include "gamemode_race.qh"
+
+#include "gamemode.qh"
+
+#include "../race.qh"
+
+#define autocvar_g_race_laps_limit cvar("g_race_laps_limit")
+float autocvar_g_race_qualifying_timelimit;
+float autocvar_g_race_qualifying_timelimit_override;
+int autocvar_g_race_teams;
+
// legacy bot roles
.float race_checkpoint;
void havocbot_role_race()
-{
+{SELFPARAM();
if(self.deadflag != DEAD_NO)
return;
GameLogEcho(strcat(":race:", mode, ":", ((actor != world) ? (strcat(":", ftos(actor.playerid))) : "")));
}
-MUTATOR_HOOKFUNCTION(race_PlayerPhysics)
-{
+MUTATOR_HOOKFUNCTION(rc, PlayerPhysics)
+{SELFPARAM();
// force kbd movement for fairness
float wishspeed;
vector wishvel;
return false;
}
-MUTATOR_HOOKFUNCTION(race_ResetMap)
+MUTATOR_HOOKFUNCTION(rc, reset_map_global)
{
float s;
return false;
}
-MUTATOR_HOOKFUNCTION(race_PlayerPreThink)
-{
+MUTATOR_HOOKFUNCTION(rc, PlayerPreThink)
+{SELFPARAM();
if(IS_SPEC(self) || IS_OBSERVER(self))
if(g_race_qualifying)
if(msg_entity.enemy.race_laptime)
return false;
}
-MUTATOR_HOOKFUNCTION(race_ClientConnect)
-{
+MUTATOR_HOOKFUNCTION(rc, ClientConnect)
+{SELFPARAM();
race_PreparePlayer();
self.race_checkpoint = -1;
return false;
}
-MUTATOR_HOOKFUNCTION(race_MakePlayerObserver)
-{
+MUTATOR_HOOKFUNCTION(rc, MakePlayerObserver)
+{SELFPARAM();
if(g_race_qualifying)
if(PlayerScore_Add(self, SP_RACE_FASTEST, 0))
self.frags = FRAGS_LMS_LOSER;
return false;
}
-MUTATOR_HOOKFUNCTION(race_PlayerSpawn)
-{
+MUTATOR_HOOKFUNCTION(rc, PlayerSpawn)
+{SELFPARAM();
if(spawn_spot.target == "")
// Emergency: this wasn't a real spawnpoint. Can this ever happen?
race_PreparePlayer();
return false;
}
-MUTATOR_HOOKFUNCTION(race_PutClientInServer)
-{
+MUTATOR_HOOKFUNCTION(rc, PutClientInServer)
+{SELFPARAM();
if(IS_PLAYER(self))
if(!gameover)
{
return false;
}
-MUTATOR_HOOKFUNCTION(race_PlayerDies)
-{
+MUTATOR_HOOKFUNCTION(rc, PlayerDies)
+{SELFPARAM();
self.respawn_flags |= RESPAWN_FORCE;
race_AbandonRaceCheck(self);
return false;
}
-MUTATOR_HOOKFUNCTION(race_BotRoles)
-{
+MUTATOR_HOOKFUNCTION(rc, HavocBot_ChooseRole)
+{SELFPARAM();
self.havocbot_role = havocbot_role_race;
return true;
}
-MUTATOR_HOOKFUNCTION(race_PlayerPostThink)
-{
+MUTATOR_HOOKFUNCTION(rc, GetPressedKeys)
+{SELFPARAM();
if(self.cvar_cl_allow_uidtracking == 1 && self.cvar_cl_allow_uid2name == 1)
{
if (!self.stored_netname)
return false;
}
-MUTATOR_HOOKFUNCTION(race_ForbidClearPlayerScore)
+MUTATOR_HOOKFUNCTION(rc, ForbidPlayerScore_Clear)
{
if(g_race_qualifying)
return true; // in qualifying, you don't lose score by observing
return false;
}
-MUTATOR_HOOKFUNCTION(race_GetTeamCount)
+MUTATOR_HOOKFUNCTION(rc, GetTeamCount, CBC_ORDER_EXCLUSIVE)
{
ret_float = race_teams;
return false;
}
+MUTATOR_HOOKFUNCTION(rc, Scores_CountFragsRemaining)
+{
+ // announce remaining frags if not in qualifying mode
+ if(!g_race_qualifying)
+ return true;
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(rc, GetRecords)
+{
+ for(int i = record_page * 200; i < MapInfo_count && i < record_page * 200 + 200; ++i)
+ {
+ if(MapInfo_Get_ByID(i))
+ {
+ float r = race_readTime(MapInfo_Map_bspname, 1);
+
+ if(!r)
+ continue;
+
+ string h = race_readName(MapInfo_Map_bspname, 1);
+ ret_string = strcat(ret_string, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
+ }
+ }
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(rc, FixClientCvars)
+{
+ stuffcmd(fix_client, "cl_cmd settemp cl_movecliptokeyboard 2\n");
+ return false;
+}
+
void race_Initialize()
{
race_ScoreRules();
warmup_stage = 0;
}
-MUTATOR_DEFINITION(gamemode_race)
+void rc_SetLimits()
+{
+ int fraglimit_override, leadlimit_override;
+ float timelimit_override, qualifying_override;
+
+ if(autocvar_g_race_teams)
+ {
+ ActivateTeamplay();
+ race_teams = bound(2, autocvar_g_race_teams, 4);
+ have_team_spawns = -1; // request team spawns
+ }
+ else
+ race_teams = 0;
+
+ qualifying_override = autocvar_g_race_qualifying_timelimit_override;
+ fraglimit_override = autocvar_g_race_laps_limit;
+ leadlimit_override = 0; // currently not supported by race
+ timelimit_override = -1; // use default if we don't set it below
+
+ // we need to find out the correct value for g_race_qualifying
+ float want_qualifying = ((qualifying_override >= 0) ? qualifying_override : autocvar_g_race_qualifying_timelimit) > 0;
+
+ if(autocvar_g_campaign)
+ {
+ g_race_qualifying = 1;
+ independent_players = 1;
+ }
+ else if(!autocvar_g_campaign && want_qualifying)
+ {
+ g_race_qualifying = 2;
+ independent_players = 1;
+ race_fraglimit = (race_fraglimit >= 0) ? fraglimit_override : autocvar_fraglimit;
+ race_leadlimit = (race_leadlimit >= 0) ? leadlimit_override : autocvar_leadlimit;
+ race_timelimit = (race_timelimit >= 0) ? timelimit_override : autocvar_timelimit;
+ fraglimit_override = 0;
+ leadlimit_override = 0;
+ timelimit_override = autocvar_g_race_qualifying_timelimit;
+ }
+ else
+ g_race_qualifying = 0;
+
+ SetLimits(fraglimit_override, leadlimit_override, timelimit_override, qualifying_override);
+}
+
+REGISTER_MUTATOR(rc, g_race)
{
- MUTATOR_HOOK(PlayerPhysics, race_PlayerPhysics, CBC_ORDER_ANY);
- MUTATOR_HOOK(reset_map_global, race_ResetMap, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerPreThink, race_PlayerPreThink, CBC_ORDER_ANY);
- MUTATOR_HOOK(ClientConnect, race_ClientConnect, CBC_ORDER_ANY);
- MUTATOR_HOOK(MakePlayerObserver, race_MakePlayerObserver, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerSpawn, race_PlayerSpawn, CBC_ORDER_ANY);
- MUTATOR_HOOK(PutClientInServer, race_PutClientInServer, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerDies, race_PlayerDies, CBC_ORDER_ANY);
- MUTATOR_HOOK(HavocBot_ChooseRole, race_BotRoles, CBC_ORDER_ANY);
- MUTATOR_HOOK(GetPressedKeys, race_PlayerPostThink, CBC_ORDER_ANY);
- MUTATOR_HOOK(ForbidPlayerScore_Clear, race_ForbidClearPlayerScore, CBC_ORDER_ANY);
- MUTATOR_HOOK(GetTeamCount, race_GetTeamCount, CBC_ORDER_ANY);
+ rc_SetLimits();
MUTATOR_ONADD
{
MUTATOR_ONREMOVE
{
- print("This is a game type and it cannot be removed at runtime.");
+ LOG_INFO("This is a game type and it cannot be removed at runtime.");
return -1;
}