void anticheat_physics()
{
- float f, wishspeed;
- vector wishvel;
+ float f;
// div0_evade -> SPECTATORS
makevectors(self.v_angle);
MEAN_ACCUMULATE(anticheat_speedhack, max(0, f - self.anticheat_speedhack_offset), 1);
self.anticheat_speedhack_offset += (f - self.anticheat_speedhack_offset) * frametime * 0.1;
}
-
- // race/CTS: force kbd movement for fairness
- if(g_race || g_cts)
- {
- // if record times matter
- // ensure nothing EVIL is being done (i.e. div0_evade)
- // this hinders joystick users though
- // but it still gives SOME analog control
- wishvel_x = fabs(self.movement_x);
- wishvel_y = fabs(self.movement_y);
- if(wishvel_x != 0 && wishvel_y != 0 && wishvel_x != wishvel_y)
- {
- wishvel_z = 0;
- wishspeed = vlen(wishvel);
- if(wishvel_x >= 2 * wishvel_y)
- {
- // pure X motion
- if(self.movement_x > 0)
- self.movement_x = wishspeed;
- else
- self.movement_x = -wishspeed;
- self.movement_y = 0;
- }
- else if(wishvel_y >= 2 * wishvel_x)
- {
- // pure Y motion
- self.movement_x = 0;
- if(self.movement_y > 0)
- self.movement_y = wishspeed;
- else
- self.movement_y = -wishspeed;
- }
- else
- {
- // diagonal
- if(self.movement_x > 0)
- self.movement_x = M_SQRT1_2 * wishspeed;
- else
- self.movement_x = -M_SQRT1_2 * wishspeed;
- if(self.movement_y > 0)
- self.movement_y = M_SQRT1_2 * wishspeed;
- else
- self.movement_y = -M_SQRT1_2 * wishspeed;
- }
- }
- }
}
void anticheat_spectatecopy(entity spectatee)
self.havocbot_role = havocbot_role_dm;
}
-void havocbot_chooserole_race()
-{
- self.havocbot_role = havocbot_role_race;
-}
-
void havocbot_chooserole()
{
dprint("choosing a role...\n");
return;
else if (g_keyhunt)
havocbot_chooserole_kh();
- else if (g_race || g_cts)
- havocbot_chooserole_race();
else if (g_onslaught)
havocbot_chooserole_ons();
else // assume anything else is deathmatch
{
entity spot;
self.hud = HUD_NORMAL;
- race_PreSpawnObserver();
spot = SelectSpawnPoint (TRUE);
if(!spot)
WriteEntity(MSG_ONE, self);
}
- if((g_race && g_race_qualifying) || g_cts)
- {
- if(PlayerScore_Add(self, SP_RACE_FASTEST, 0))
- self.frags = FRAGS_LMS_LOSER;
- else
- self.frags = FRAGS_SPECTATOR;
- }
- else
- self.frags = FRAGS_SPECTATOR;
+ self.frags = FRAGS_SPECTATOR;
MUTATOR_CALLHOOK(MakePlayerObserver);
if(self.team < 0)
JoinBestTeam(self, FALSE, TRUE);
- race_PreSpawn();
-
spot = SelectSpawnPoint (FALSE);
if(!spot)
{
self.speedrunning = FALSE;
- race_PostSpawn(spot);
-
//stuffcmd(self, "chase_active 0");
//stuffcmd(self, "set viewsize $tmpviewsize \n");
anticheat_init();
- race_PreSpawnObserver();
-
// identify the right forced team
if(autocvar_g_campaign)
{
else
self.hitplotfh = -1;
- if(g_race || g_cts) {
- string rr;
- if(g_cts)
- rr = CTS_RECORD;
- else
- rr = RACE_RECORD;
-
- msg_entity = self;
- race_send_recordtime(MSG_ONE);
- race_send_speedaward(MSG_ONE);
-
- speedaward_alltimebest = stof(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed")));
- speedaward_alltimebest_holder = uid2name(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp")));
- race_send_speedaward_alltimebest(MSG_ONE);
-
- float i;
- for (i = 1; i <= RANKINGS_CNT; ++i) {
- race_SendRankings(i, 0, 0, MSG_ONE);
- }
- }
- else if(autocvar_sv_teamnagger && !(autocvar_bot_vs_human && (c3==-1 && c4==-1)) && !g_ca) // teamnagger is currently bad for ca
+ if(autocvar_sv_teamnagger && !(autocvar_bot_vs_human && (c3==-1 && c4==-1)) && !g_ca && !g_cts && !g_race) // teamnagger is currently bad for ca, race & cts
send_CSQC_teamnagger();
CheatInitClient();
if(self.spectatee_status != oldspectatee_status)
{
ClientData_Touch(self);
- if(g_race || g_cts)
- race_InitSpectator();
}
if(self.teamkill_soundtime)
playerdemo_write();
- if((g_cts || g_race) && self.cvar_cl_allow_uidtracking == 1 && self.cvar_cl_allow_uid2name == 1)
- {
- if (!self.stored_netname)
- self.stored_netname = strzone(uid2name(self.crypto_idfp));
- if(self.stored_netname != self.netname)
- {
- db_put(ServerProgsDB, strcat("/uid2name/", self.crypto_idfp), self.netname);
- strunzone(self.stored_netname);
- self.stored_netname = strzone(self.netname);
- }
- }
-
- /*
- if(g_race)
- dprintf("%f %.6f\n", time, race_GetFractionalLapCount(self));
- */
-
CSQCMODEL_AUTOUPDATE();
}
}
}
- if((g_cts || g_race) && !IS_OBSERVER(self)) {
- if(vlen(self.velocity - self.velocity_z * '0 0 1') > speedaward_speed) {
+ if((g_cts || g_race) && !IS_OBSERVER(self))
+ {
+ if(vlen(self.velocity - self.velocity_z * '0 0 1') > speedaward_speed)
+ {
speedaward_speed = vlen(self.velocity - self.velocity_z * '0 0 1');
speedaward_holder = self.netname;
speedaward_uid = self.crypto_idfp;
speedaward_lastupdate = time;
}
- if(speedaward_speed > speedaward_lastsent && time - speedaward_lastupdate > 1) {
- string rr;
- if(g_cts)
- rr = CTS_RECORD;
- else
- rr = RACE_RECORD;
+ if(speedaward_speed > speedaward_lastsent && time - speedaward_lastupdate > 1)
+ {
+ string rr = (g_cts) ? CTS_RECORD : RACE_RECORD;
race_send_speedaward(MSG_ALL);
speedaward_lastsent = speedaward_speed;
- if (speedaward_speed > speedaward_alltimebest && speedaward_uid != "") {
+ if (speedaward_speed > speedaward_alltimebest && speedaward_uid != "")
+ {
speedaward_alltimebest = speedaward_speed;
speedaward_alltimebest_holder = speedaward_holder;
speedaward_alltimebest_uid = speedaward_uid;
else
self.respawn_countdown = -1; // do not count down
- if(g_cts || autocvar_g_forced_respawn)
+ if(autocvar_g_forced_respawn)
self.respawn_flags = self.respawn_flags | RESPAWN_FORCE;
}
// print an obituary message
Obituary (attacker, inflictor, self, deathtype);
- race_PreDie();
// increment frag counter for used weapon type
float w;
return 0;
if (g_weaponarena)
return 0;
- if (g_cts)
- return 0;
if (g_nexball && w == WEP_GRENADE_LAUNCHER)
return 0;
if(w == 0)
float i, j, k, uidcnt = 0, thiscnt;
string s, temp_s, rr, myuid, thisuid;
- if(g_cts)
- rr = CTS_RECORD;
- else
- rr = RACE_RECORD;
+ rr = (g_cts) ? CTS_RECORD : RACE_RECORD;
for(k = 0; k < MapInfo_count; ++k)
{
if(time <= game_starttime && round_handler_IsActive())
round_handler_Reset(game_starttime);
- if(g_race || g_cts)
- race_ReadyRestart();
- else MUTATOR_CALLHOOK(reset_map_global);
+ MUTATOR_CALLHOOK(reset_map_global);
for(self = world; (self = nextent(self)); )
if(IS_NOT_A_CLIENT(self))
float g_warmup_limit;
float g_warmup_allguns;
float g_warmup_allow_timeout;
-float g_race_qualifying;
float warmup_stage;
float g_pickup_respawntime_weapon;
float g_pickup_respawntime_superweapon;
}
if (targ == attacker)
- {
- if(g_cts && !autocvar_g_cts_selfdamage)
- damage = 0;
- else
- damage = damage * autocvar_g_balance_selfdamagepercent; // Partial damage if the attacker hits himself
- }
+ damage = damage * autocvar_g_balance_selfdamagepercent; // Partial damage if the attacker hits himself
// count the damage
if(attacker)
sv_clones = cvar("sv_clones");
sv_foginterval = cvar("sv_foginterval");
g_cloaked = cvar("g_cloaked");
- if(g_cts)
- g_cloaked = 1; // always enable cloak in CTS
g_footsteps = cvar("g_footsteps");
g_grappling_hook = cvar("g_grappling_hook");
g_jetpack = cvar("g_jetpack");
return s;
}
-float race_readTime(string map, float pos)
-{
- string rr;
- if(g_cts)
- rr = CTS_RECORD;
- else
- rr = RACE_RECORD;
-
- return stof(db_get(ServerProgsDB, strcat(map, rr, "time", ftos(pos))));
-}
-
-string race_readUID(string map, float pos)
-{
- string rr;
- if(g_cts)
- rr = CTS_RECORD;
- else
- rr = RACE_RECORD;
-
- return db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos)));
-}
-
-float race_readPos(string map, float t) {
- float i;
- for (i = 1; i <= RANKINGS_CNT; ++i)
- if (race_readTime(map, i) == 0 || race_readTime(map, i) > t)
- return i;
-
- return 0; // pos is zero if unranked
-}
-
-void race_writeTime(string map, float t, string myuid)
-{
- string rr;
- if(g_cts)
- rr = CTS_RECORD;
- else
- rr = RACE_RECORD;
-
- float newpos;
- newpos = race_readPos(map, t);
-
- float i, prevpos = 0;
- for(i = 1; i <= RANKINGS_CNT; ++i)
- {
- if(race_readUID(map, i) == myuid)
- prevpos = i;
- }
- if (prevpos) { // player improved his existing record, only have to iterate on ranks between new and old recs
- for (i = prevpos; i > newpos; --i) {
- db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1)));
- db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1));
- }
- } else { // player has no ranked record yet
- for (i = RANKINGS_CNT; i > newpos; --i) {
- db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1)));
- db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1));
- }
- }
-
- // store new time itself
- db_put(ServerProgsDB, strcat(map, rr, "time", ftos(newpos)), ftos(t));
- db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(newpos)), myuid);
-}
-
-string race_readName(string map, float pos)
-{
- string rr;
- if(g_cts)
- rr = CTS_RECORD;
- else
- rr = RACE_RECORD;
-
- return uid2name(db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos))));
-}
-
float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
{
float m, i;
--- /dev/null
+void cts_ScoreRules()
+{
+ ScoreRules_basics(0, 0, 0, FALSE);
+ if(g_race_qualifying)
+ {
+ ScoreInfo_SetLabel_PlayerScore(SP_CTS_FASTEST, "fastest", SFL_SORT_PRIO_PRIMARY | SFL_LOWER_IS_BETTER | SFL_TIME);
+ }
+ else
+ {
+ ScoreInfo_SetLabel_PlayerScore(SP_CTS_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
+ ScoreInfo_SetLabel_PlayerScore(SP_CTS_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
+ ScoreInfo_SetLabel_PlayerScore(SP_CTS_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME);
+ }
+ ScoreRules_basics_end();
+}
+
+MUTATOR_HOOKFUNCTION(cts_PlayerPhysics)
+{
+ // force kbd movement for fairness
+ float wishspeed;
+ vector wishvel;
+
+ // if record times matter
+ // ensure nothing EVIL is being done (i.e. div0_evade)
+ // this hinders joystick users though
+ // but it still gives SOME analog control
+ wishvel_x = fabs(self.movement_x);
+ wishvel_y = fabs(self.movement_y);
+ if(wishvel_x != 0 && wishvel_y != 0 && wishvel_x != wishvel_y)
+ {
+ wishvel_z = 0;
+ wishspeed = vlen(wishvel);
+ if(wishvel_x >= 2 * wishvel_y)
+ {
+ // pure X motion
+ if(self.movement_x > 0)
+ self.movement_x = wishspeed;
+ else
+ self.movement_x = -wishspeed;
+ self.movement_y = 0;
+ }
+ else if(wishvel_y >= 2 * wishvel_x)
+ {
+ // pure Y motion
+ self.movement_x = 0;
+ if(self.movement_y > 0)
+ self.movement_y = wishspeed;
+ else
+ self.movement_y = -wishspeed;
+ }
+ else
+ {
+ // diagonal
+ if(self.movement_x > 0)
+ self.movement_x = M_SQRT1_2 * wishspeed;
+ else
+ self.movement_x = -M_SQRT1_2 * wishspeed;
+ if(self.movement_y > 0)
+ self.movement_y = M_SQRT1_2 * wishspeed;
+ else
+ self.movement_y = -M_SQRT1_2 * wishspeed;
+ }
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_ResetMap)
+{
+ float s;
+
+ Score_NicePrint(world);
+
+ race_ClearRecords();
+ PlayerScore_Sort(race_place, 0, 1, 0);
+
+ entity e;
+ FOR_EACH_CLIENT(e)
+ {
+ if(e.race_place)
+ {
+ s = PlayerScore_Add(e, SP_RACE_FASTEST, 0);
+ if(!s)
+ e.race_place = 0;
+ }
+ print(e.netname, " = ", ftos(e.race_place), "\n");
+ }
+
+ if(g_race_qualifying == 2)
+ {
+ g_race_qualifying = 0;
+ independent_players = 0;
+ cvar_set("fraglimit", ftos(race_fraglimit));
+ cvar_set("leadlimit", ftos(race_leadlimit));
+ cvar_set("timelimit", ftos(race_timelimit));
+ cts_ScoreRules();
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_PlayerPreThink)
+{
+ if(IS_SPEC(self) || IS_OBSERVER(self))
+ if(g_race_qualifying)
+ if(msg_entity.enemy.race_laptime)
+ race_SendNextCheckpoint(msg_entity.enemy, 1);
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_ClientConnect)
+{
+ race_PreparePlayer();
+ self.race_checkpoint = -1;
+
+ string rr = CTS_RECORD;
+
+ msg_entity = self;
+ race_send_recordtime(MSG_ONE);
+ race_send_speedaward(MSG_ONE);
+
+ speedaward_alltimebest = stof(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed")));
+ speedaward_alltimebest_holder = uid2name(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp")));
+ race_send_speedaward_alltimebest(MSG_ONE);
+
+ float i;
+ for (i = 1; i <= RANKINGS_CNT; ++i)
+ {
+ race_SendRankings(i, 0, 0, MSG_ONE);
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_MakePlayerObserver)
+{
+ if(PlayerScore_Add(self, SP_RACE_FASTEST, 0))
+ self.frags = FRAGS_LMS_LOSER;
+ else
+ self.frags = FRAGS_SPECTATOR;
+
+ race_PreparePlayer();
+ self.race_checkpoint = -1;
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_PlayerSpawn)
+{
+ if(spawn_spot.target == "")
+ // Emergency: this wasn't a real spawnpoint. Can this ever happen?
+ race_PreparePlayer();
+
+ // if we need to respawn, do it right
+ self.race_respawn_checkpoint = self.race_checkpoint;
+ self.race_respawn_spotref = spawn_spot;
+
+ self.race_place = 0;
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_PutClientInServer)
+{
+ if(IS_PLAYER(self))
+ if(!gameover)
+ {
+ if(self.killcount == -666 /* initial spawn */ || g_race_qualifying) // spawn
+ race_PreparePlayer();
+ else // respawn
+ race_RetractPlayer();
+
+ race_AbandonRaceCheck(self);
+ }
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_PlayerDies)
+{
+ self.respawn_flags |= RESPAWN_FORCE;
+ race_AbandonRaceCheck(self);
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_HavocBot_ChooseRule)
+{
+ self.havocbot_role = havocbot_role_race;
+ return TRUE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_PlayerPostThink)
+{
+ if(self.cvar_cl_allow_uidtracking == 1 && self.cvar_cl_allow_uid2name == 1)
+ {
+ if (!self.stored_netname)
+ self.stored_netname = strzone(uid2name(self.crypto_idfp));
+ if(self.stored_netname != self.netname)
+ {
+ db_put(ServerProgsDB, strcat("/uid2name/", self.crypto_idfp), self.netname);
+ strunzone(self.stored_netname);
+ self.stored_netname = strzone(self.netname);
+ }
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_ForbidThrowing)
+{
+ // no weapon dropping in CTS
+ return TRUE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_FilterItem)
+{
+ if(self.classname == "droppedweapon")
+ return TRUE;
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_PlayerDamage)
+{
+ if(frag_target == frag_attacker || frag_deathtype == DEATH_FALL)
+ if(!autocvar_g_cts_selfdamage)
+ frag_damage = 0;
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(cts_ForbidClearPlayerScore)
+{
+ return TRUE; // in CTS, you don't lose score by observing
+}
+
+void cts_Initialize()
+{
+ g_cloaked = 1; // always enable cloak in CTS
+
+ cts_ScoreRules();
+}
+
+MUTATOR_DEFINITION(gamemode_cts)
+{
+ MUTATOR_HOOK(PlayerPhysics, cts_PlayerPhysics, CBC_ORDER_ANY);
+ MUTATOR_HOOK(reset_map_global, cts_ResetMap, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerPreThink, cts_PlayerPreThink, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ClientConnect, cts_ClientConnect, CBC_ORDER_ANY);
+ MUTATOR_HOOK(MakePlayerObserver, cts_MakePlayerObserver, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerSpawn, cts_PlayerSpawn, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PutClientInServer, cts_PutClientInServer, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerDies, cts_PlayerDies, CBC_ORDER_ANY);
+ MUTATOR_HOOK(HavocBot_ChooseRule, cts_HavocBot_ChooseRule, CBC_ORDER_ANY);
+ MUTATOR_HOOK(GetPressedKeys, cts_PlayerPostThink, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ForbidThrowCurrentWeapon, cts_ForbidThrowing, CBC_ORDER_ANY);
+ MUTATOR_HOOK(FilterItem, cts_FilterItem, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerDamage_Calculate, cts_PlayerDamage, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ForbidPlayerScore_Clear, cts_ForbidClearPlayerScore, CBC_ORDER_ANY);
+
+ MUTATOR_ONADD
+ {
+ if(time > 1) // game loads at time 1
+ error("This is a game type and it cannot be added at runtime.");
+ cts_Initialize();
+ }
+
+ MUTATOR_ONROLLBACK_OR_REMOVE
+ {
+ // we actually cannot roll back cts_Initialize here
+ // BUT: we don't need to! If this gets called, adding always
+ // succeeds.
+ }
+
+ MUTATOR_ONREMOVE
+ {
+ print("This is a game type and it cannot be removed at runtime.");
+ return -1;
+ }
+
+ return 0;
+}
--- /dev/null
+float g_race_qualifying;
+
+// scores
+#define ST_CTS_LAPS 1
+#define SP_CTS_LAPS 4
+#define SP_CTS_TIME 5
+#define SP_CTS_FASTEST 6
--- /dev/null
+void race_ScoreRules()
+{
+ ScoreRules_basics(race_teams, 0, 0, FALSE);
+ if(race_teams)
+ {
+ ScoreInfo_SetLabel_TeamScore( ST_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
+ ScoreInfo_SetLabel_PlayerScore(SP_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
+ ScoreInfo_SetLabel_PlayerScore(SP_RACE_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
+ ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME);
+ }
+ else if(g_race_qualifying)
+ {
+ ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest", SFL_SORT_PRIO_PRIMARY | SFL_LOWER_IS_BETTER | SFL_TIME);
+ }
+ else
+ {
+ ScoreInfo_SetLabel_PlayerScore(SP_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
+ ScoreInfo_SetLabel_PlayerScore(SP_RACE_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
+ ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME);
+ }
+ ScoreRules_basics_end();
+}
+
+MUTATOR_HOOKFUNCTION(race_PlayerPhysics)
+{
+ // force kbd movement for fairness
+ float wishspeed;
+ vector wishvel;
+
+ // if record times matter
+ // ensure nothing EVIL is being done (i.e. div0_evade)
+ // this hinders joystick users though
+ // but it still gives SOME analog control
+ wishvel_x = fabs(self.movement_x);
+ wishvel_y = fabs(self.movement_y);
+ if(wishvel_x != 0 && wishvel_y != 0 && wishvel_x != wishvel_y)
+ {
+ wishvel_z = 0;
+ wishspeed = vlen(wishvel);
+ if(wishvel_x >= 2 * wishvel_y)
+ {
+ // pure X motion
+ if(self.movement_x > 0)
+ self.movement_x = wishspeed;
+ else
+ self.movement_x = -wishspeed;
+ self.movement_y = 0;
+ }
+ else if(wishvel_y >= 2 * wishvel_x)
+ {
+ // pure Y motion
+ self.movement_x = 0;
+ if(self.movement_y > 0)
+ self.movement_y = wishspeed;
+ else
+ self.movement_y = -wishspeed;
+ }
+ else
+ {
+ // diagonal
+ if(self.movement_x > 0)
+ self.movement_x = M_SQRT1_2 * wishspeed;
+ else
+ self.movement_x = -M_SQRT1_2 * wishspeed;
+ if(self.movement_y > 0)
+ self.movement_y = M_SQRT1_2 * wishspeed;
+ else
+ self.movement_y = -M_SQRT1_2 * wishspeed;
+ }
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(race_ResetMap)
+{
+ float s;
+
+ Score_NicePrint(world);
+
+ race_ClearRecords();
+ PlayerScore_Sort(race_place, 0, 1, 0);
+
+ entity e;
+ FOR_EACH_CLIENT(e)
+ {
+ if(e.race_place)
+ {
+ s = PlayerScore_Add(e, SP_RACE_FASTEST, 0);
+ if(!s)
+ e.race_place = 0;
+ }
+ print(e.netname, " = ", ftos(e.race_place), "\n");
+ }
+
+ if(g_race_qualifying == 2)
+ {
+ g_race_qualifying = 0;
+ independent_players = 0;
+ cvar_set("fraglimit", ftos(race_fraglimit));
+ cvar_set("leadlimit", ftos(race_leadlimit));
+ cvar_set("timelimit", ftos(race_timelimit));
+ race_ScoreRules();
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(race_PlayerPreThink)
+{
+ if(IS_SPEC(self) || IS_OBSERVER(self))
+ if(g_race_qualifying)
+ if(msg_entity.enemy.race_laptime)
+ race_SendNextCheckpoint(msg_entity.enemy, 1);
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(race_ClientConnect)
+{
+ race_PreparePlayer();
+ self.race_checkpoint = -1;
+
+ string rr = RACE_RECORD;
+
+ msg_entity = self;
+ race_send_recordtime(MSG_ONE);
+ race_send_speedaward(MSG_ONE);
+
+ speedaward_alltimebest = stof(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed")));
+ speedaward_alltimebest_holder = uid2name(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp")));
+ race_send_speedaward_alltimebest(MSG_ONE);
+
+ float i;
+ for (i = 1; i <= RANKINGS_CNT; ++i)
+ {
+ race_SendRankings(i, 0, 0, MSG_ONE);
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(race_MakePlayerObserver)
+{
+ if(g_race_qualifying)
+ if(PlayerScore_Add(self, SP_RACE_FASTEST, 0))
+ self.frags = FRAGS_LMS_LOSER;
+ else
+ self.frags = FRAGS_SPECTATOR;
+
+ race_PreparePlayer();
+ self.race_checkpoint = -1;
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(race_PlayerSpawn)
+{
+ if(spawn_spot.target == "")
+ // Emergency: this wasn't a real spawnpoint. Can this ever happen?
+ race_PreparePlayer();
+
+ // if we need to respawn, do it right
+ self.race_respawn_checkpoint = self.race_checkpoint;
+ self.race_respawn_spotref = spawn_spot;
+
+ self.race_place = 0;
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(race_PutClientInServer)
+{
+ if(IS_PLAYER(self))
+ if(!gameover)
+ {
+ if(self.killcount == -666 /* initial spawn */ || g_race_qualifying) // spawn
+ race_PreparePlayer();
+ else // respawn
+ race_RetractPlayer();
+
+ race_AbandonRaceCheck(self);
+ }
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(race_PlayerDies)
+{
+ self.respawn_flags |= RESPAWN_FORCE;
+ race_AbandonRaceCheck(self);
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(race_HavocBot_ChooseRule)
+{
+ self.havocbot_role = havocbot_role_race;
+ return TRUE;
+}
+
+MUTATOR_HOOKFUNCTION(race_PlayerPostThink)
+{
+ if(self.cvar_cl_allow_uidtracking == 1 && self.cvar_cl_allow_uid2name == 1)
+ {
+ if (!self.stored_netname)
+ self.stored_netname = strzone(uid2name(self.crypto_idfp));
+ if(self.stored_netname != self.netname)
+ {
+ db_put(ServerProgsDB, strcat("/uid2name/", self.crypto_idfp), self.netname);
+ strunzone(self.stored_netname);
+ self.stored_netname = strzone(self.netname);
+ }
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(race_ForbidClearPlayerScore)
+{
+ if(g_race_qualifying)
+ return TRUE; // in qualifying, you don't lose score by observing
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(race_GetTeamCount)
+{
+ ret_float = race_teams;
+ return FALSE;
+}
+
+void race_Initialize()
+{
+ race_ScoreRules();
+}
+
+MUTATOR_DEFINITION(gamemode_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_ChooseRule, race_HavocBot_ChooseRule, 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);
+
+ MUTATOR_ONADD
+ {
+ if(time > 1) // game loads at time 1
+ error("This is a game type and it cannot be added at runtime.");
+ race_Initialize();
+ }
+
+ MUTATOR_ONROLLBACK_OR_REMOVE
+ {
+ // we actually cannot roll back race_Initialize here
+ // BUT: we don't need to! If this gets called, adding always
+ // succeeds.
+ }
+
+ MUTATOR_ONREMOVE
+ {
+ print("This is a game type and it cannot be removed at runtime.");
+ return -1;
+ }
+
+ return 0;
+}
--- /dev/null
+float g_race_qualifying;
+float race_teams;
+
+// scores
+#define ST_RACE_LAPS 1
+#define SP_RACE_LAPS 4
+#define SP_RACE_TIME 5
+#define SP_RACE_FASTEST 6
MUTATOR_DECLARATION(gamemode_domination);
MUTATOR_DECLARATION(gamemode_lms);
MUTATOR_DECLARATION(gamemode_invasion);
+MUTATOR_DECLARATION(gamemode_cts);
+MUTATOR_DECLARATION(gamemode_race);
MUTATOR_DECLARATION(mutator_dodging);
MUTATOR_DECLARATION(mutator_invincibleprojectiles);
mutators/gamemode_nexball.qh
mutators/gamemode_lms.qh
mutators/gamemode_invasion.qh
+mutators/gamemode_cts.qh
+mutators/gamemode_race.qh
mutators/mutator_dodging.qh
mutators/mutator_nades.qh
mutators/gamemode_onslaught.qc
mutators/gamemode_lms.qc
mutators/gamemode_invasion.qc
+mutators/gamemode_cts.qc
+mutators/gamemode_race.qc
mutators/mutator_invincibleproj.qc
mutators/mutator_new_toys.qc
mutators/mutator_nix.qc
+float race_readTime(string map, float pos)
+{
+ string rr = (g_cts) ? CTS_RECORD : RACE_RECORD;
+
+ return stof(db_get(ServerProgsDB, strcat(map, rr, "time", ftos(pos))));
+}
+
+string race_readUID(string map, float pos)
+{
+ string rr = (g_cts) ? CTS_RECORD : RACE_RECORD;
+
+ return db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos)));
+}
+
+float race_readPos(string map, float t)
+{
+ float i;
+ for (i = 1; i <= RANKINGS_CNT; ++i)
+ if (race_readTime(map, i) == 0 || race_readTime(map, i) > t)
+ return i;
+
+ return 0; // pos is zero if unranked
+}
+
+void race_writeTime(string map, float t, string myuid)
+{
+ string rr = (g_cts) ? CTS_RECORD : RACE_RECORD;
+
+ float newpos;
+ newpos = race_readPos(map, t);
+
+ float i, prevpos = 0;
+ for(i = 1; i <= RANKINGS_CNT; ++i)
+ {
+ if(race_readUID(map, i) == myuid)
+ prevpos = i;
+ }
+ if (prevpos)
+ {
+ // player improved his existing record, only have to iterate on ranks between new and old recs
+ for (i = prevpos; i > newpos; --i)
+ {
+ db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1)));
+ db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1));
+ }
+ }
+ else
+ {
+ // player has no ranked record yet
+ for (i = RANKINGS_CNT; i > newpos; --i)
+ {
+ db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1)));
+ db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1));
+ }
+ }
+
+ // store new time itself
+ db_put(ServerProgsDB, strcat(map, rr, "time", ftos(newpos)), ftos(t));
+ db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(newpos)), myuid);
+}
+
+string race_readName(string map, float pos)
+{
+ string rr = (g_cts) ? CTS_RECORD : RACE_RECORD;
+
+ return uid2name(db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos))));
+}
+
+
#define MAX_CHECKPOINTS 255
void spawnfunc_target_checkpoint();
});
}
-void race_InitSpectator()
-{
- if(g_race_qualifying)
- if(msg_entity.enemy.race_laptime)
- race_SendNextCheckpoint(msg_entity.enemy, 1);
-}
-
void race_send_recordtime(float msg)
{
// send the server best time
});
}
-void race_setTime(string map, float t, string myuid, string mynetname, entity e) { // netname only used TEMPORARILY for printing
+void race_setTime(string map, float t, string myuid, string mynetname, entity e)
+{
+ // netname only used TEMPORARILY for printing
float newpos, player_prevpos;
newpos = race_readPos(map, t);
race_SendStatus(0, e); // "fail"
Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_RACE_FAIL_RANKED, mynetname, player_prevpos, t, oldrec);
return;
- } else if (!newpos) { // no ranking, time worse than the worst ranked
+ }
+ else if (!newpos)
+ {
+ // no ranking, time worse than the worst ranked
oldrec = race_readTime(GetMapname(), RANKINGS_CNT);
race_SendStatus(0, e); // "fail"
Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_RACE_FAIL_UNRANKED, mynetname, RANKINGS_CNT, t, oldrec);
// store new ranking
race_writeTime(GetMapname(), t, myuid);
- if (newpos == 1) {
+ if (newpos == 1)
+ {
write_recordmarker(e, time - TIME_DECODE(t), TIME_DECODE(t));
race_send_recordtime(MSG_ALL);
}
}
}
-void race_deleteTime(string map, float pos) {
+void race_deleteTime(string map, float pos)
+{
string rr;
if(g_cts)
rr = CTS_RECORD;
rr = RACE_RECORD;
float i;
- for (i = pos; i <= RANKINGS_CNT; ++i) {
- if (i == RANKINGS_CNT) {
+ for (i = pos; i <= RANKINGS_CNT; ++i)
+ {
+ if (i == RANKINGS_CNT)
+ {
db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), string_null);
db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), string_null);
}
- else {
+ else
+ {
db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(GetMapname(), i+1)));
db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(GetMapname(), i+1));
}
if(recordholder == e.netname)
recordholder = "";
- if(t != 0) {
+ if(t != 0)
+ {
if(cp == race_timed_checkpoint)
{
race_setTime(GetMapname(), t, e.crypto_idfp, e.netname, e);
other.porto_forbidden = 2; // decreased by 1 each StartFrame
- if(defrag_ents) {
+ if(defrag_ents)
+ {
if(self.race_checkpoint == -2)
{
self.race_checkpoint = other.race_checkpoint;
float largest_cp_id = 0;
float cp_amount = 0;
- for(cp = world; (cp = find(cp, classname, "target_checkpoint"));) {
+ for(cp = world; (cp = find(cp, classname, "target_checkpoint"));)
+ {
cp_amount += 1;
if(cp.race_checkpoint > largest_cp_id) // update the finish id if someone hit a new checkpoint
{
race_highest_checkpoint = largest_cp_id + 1;
race_timed_checkpoint = largest_cp_id + 1;
- for(cp = world; (cp = find(cp, classname, "target_checkpoint"));) {
+ for(cp = world; (cp = find(cp, classname, "target_checkpoint"));)
+ {
if(cp.race_checkpoint == -2) // set defragcpexists to -1 so that the cp id file will be rewritten when someone finishes
defragcpexists = -1;
}
}
}
- if(cp_amount == 0) {
+ if(cp_amount == 0)
+ {
for(cp = world; (cp = find(cp, classname, "target_stopTimer"));)
cp.race_checkpoint = 1;
race_highest_checkpoint = 1;
while((l = fgets(fh)))
{
len = tokenize_console(l);
- if(len != 2) {
+ if(len != 2)
+ {
defragcpexists = -1; // something's wrong in the defrag cp file, set defragcpexists to -1 so that it will be rewritten when someone finishes
continue;
}
g_race_qualifying = qual;
- if(race_timed_checkpoint) {
- if(defrag_ents) {
+ if(race_timed_checkpoint)
+ {
+ if(defrag_ents)
+ {
for(cp = world; (cp = find(cp, classname, "target_startTimer"));)
WaypointSprite_UpdateSprites(cp.sprite, "race-start", "", "");
for(cp = world; (cp = find(cp, classname, "target_stopTimer"));)
WaypointSprite_UpdateSprites(cp.sprite, "race-finish", "", "");
- for(cp = world; (cp = find(cp, classname, "target_checkpoint"));) {
+ for(cp = world; (cp = find(cp, classname, "target_checkpoint"));)
+ {
if(cp.race_checkpoint == -2) // something's wrong with the defrag cp file or it has not been written yet, set defragcpexists to -1 so that it will be rewritten when someone finishes
defragcpexists = -1;
}
- if(defragcpexists != -1){
+ if(defragcpexists != -1)
+ {
float largest_cp_id = 0;
for(cp = world; (cp = find(cp, classname, "target_checkpoint"));)
if(cp.race_checkpoint > largest_cp_id)
cp.race_checkpoint = largest_cp_id + 1; // finish line
race_highest_checkpoint = largest_cp_id + 1;
race_timed_checkpoint = largest_cp_id + 1;
- } else {
+ }
+ else
+ {
for(cp = world; (cp = find(cp, classname, "target_stopTimer"));)
cp.race_checkpoint = 255; // finish line
race_highest_checkpoint = 255;
race_timed_checkpoint = 255;
}
}
- else {
+ else
+ {
for(cp = world; (cp = find(cp, classname, "trigger_race_checkpoint")); )
if(cp.sprite)
{
}
}
- if(defrag_ents) {
+ if(defrag_ents)
+ {
entity trigger, targ;
for(trigger = world; (trigger = find(trigger, classname, "trigger_multiple")); )
for(targ = world; (targ = find(targ, targetname, trigger.target)); )
- if (targ.classname == "target_checkpoint" || targ.classname == "target_startTimer" || targ.classname == "target_stopTimer") {
+ if (targ.classname == "target_checkpoint" || targ.classname == "target_startTimer" || targ.classname == "target_stopTimer")
+ {
trigger.wait = 0;
trigger.delay = 0;
targ.wait = 0;
void spawnfunc_trigger_race_checkpoint()
{
vector o;
- if(!g_race && !g_cts)
- {
- remove(self);
- return;
- }
+ if(!g_race && !g_cts) { remove(self); return; }
EXACTTRIGGER_INIT;
void spawnfunc_target_checkpoint() // defrag entity
{
vector o;
- if(!g_race && !g_cts)
- {
- remove(self);
- return;
- }
+ if(!g_race && !g_cts) { remove(self); return; }
defrag_ents = 1;
EXACTTRIGGER_INIT;
self.race_checkpoint = self.race_respawn_checkpoint;
}
-void race_PreDie()
-{
- if(!g_race && !g_cts)
- return;
-
- race_AbandonRaceCheck(self);
-}
-
-void race_PreSpawn()
-{
- if(!g_race && !g_cts)
- return;
- if(self.killcount == -666 /* initial spawn */ || g_race_qualifying) // spawn
- race_PreparePlayer();
- else // respawn
- race_RetractPlayer();
-
- race_AbandonRaceCheck(self);
-}
-
-void race_PostSpawn(entity spot)
-{
- if(!g_race && !g_cts)
- return;
-
- if(spot.target == "")
- // Emergency: this wasn't a real spawnpoint. Can this ever happen?
- race_PreparePlayer();
-
- // if we need to respawn, do it right
- self.race_respawn_checkpoint = self.race_checkpoint;
- self.race_respawn_spotref = spot;
-
- self.race_place = 0;
-}
-
-void race_PreSpawnObserver()
-{
- if(!g_race && !g_cts)
- return;
- race_PreparePlayer();
- self.race_checkpoint = -1;
-}
-
void spawnfunc_info_player_race (void)
{
- if(!g_race && !g_cts)
- {
- remove(self);
- return;
- }
+ if(!g_race && !g_cts) { remove(self); return; }
++race_spawns;
spawnfunc_info_player_deathmatch();
self = e;
}
-void race_ReadyRestart()
-{
- float s;
-
- Score_NicePrint(world);
-
- race_ClearRecords();
- PlayerScore_Sort(race_place, 0, 1, 0);
-
- entity e;
- FOR_EACH_CLIENT(e)
- {
- if(e.race_place)
- {
- s = PlayerScore_Add(e, SP_RACE_FASTEST, 0);
- if(!s)
- e.race_place = 0;
- }
- print(e.netname, " = ", ftos(e.race_place), "\n");
- }
-
- if(g_race_qualifying == 2)
- {
- g_race_qualifying = 0;
- independent_players = 0;
- cvar_set("fraglimit", ftos(race_fraglimit));
- cvar_set("leadlimit", ftos(race_leadlimit));
- cvar_set("timelimit", ftos(race_timelimit));
- ScoreRules_race();
- }
-}
-
void race_ImposePenaltyTime(entity pl, float penalty, string reason)
{
if(g_race_qualifying)
-void race_InitSpectator();
-void race_PreSpawnObserver();
-void race_PreSpawn();
-void race_PostSpawn(entity spot);
-void race_PreDie();
-void race_ReadyRestart();
-float race_teams;
float race_spawns;
-float race_PreviousCheckpoint(float f);
-float race_NextCheckpoint(float f);
-void race_AbandonRaceCheck(entity p);
float race_highest_place_spawn; // number of places; a place higher gets spawned at 0
float race_lowest_place_spawn; // where to spawn in qualifying
float race_fraglimit;
.float race_started;
.float race_completed;
float race_completing;
-void race_ImposePenaltyTime(entity pl, float penalty, string reason);
-void race_StartCompleting();
.float race_movetime; // for reading
.float race_movetime_frac; // fractional accumulator for higher accuracy (helper for writing)
.float race_respawn_checkpoint;
.entity race_respawn_spotref; // try THIS spawn in case you respawn
+// definitions for functions used outside race.qc
+float race_PreviousCheckpoint(float f);
+float race_NextCheckpoint(float f);
+void race_AbandonRaceCheck(entity p);
+void race_ImposePenaltyTime(entity pl, float penalty, string reason);
+void race_StartCompleting();
float race_GetFractionalLapCount(entity e);
+float race_readTime(string map, float pos);
+string race_readUID(string map, float pos);
+string race_readName(string map, float pos);
if(MUTATOR_CALLHOOK(ForbidPlayerScore_Clear)) return 0;
- if(g_cts) return 0; // in CTS, you don't lose score by observing
- if(g_race && g_race_qualifying) return 0; // in qualifying, you don't lose score by observing
-
sk = player.scorekeeper;
for(i = 0; i < MAX_SCORE; ++i)
{
ScoreRules_basics_end();
}
-// Race stuff
-#define ST_RACE_LAPS 1
-#define SP_RACE_LAPS 4
-#define SP_RACE_TIME 5
-#define SP_RACE_FASTEST 6
-void ScoreRules_race()
-{
- ScoreRules_basics(race_teams, 0, 0, FALSE);
- if(race_teams)
- {
- ScoreInfo_SetLabel_TeamScore( ST_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
- ScoreInfo_SetLabel_PlayerScore(SP_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
- ScoreInfo_SetLabel_PlayerScore(SP_RACE_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
- ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME);
- }
- else if(g_race_qualifying)
- {
- ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest", SFL_SORT_PRIO_PRIMARY | SFL_LOWER_IS_BETTER | SFL_TIME);
- }
- else
- {
- ScoreInfo_SetLabel_PlayerScore(SP_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
- ScoreInfo_SetLabel_PlayerScore(SP_RACE_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
- ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME);
- }
- ScoreRules_basics_end();
-}
-
// Nexball stuff
#define ST_NEXBALL_GOALS 1
#define SP_NEXBALL_GOALS 4
{
// check for falling damage
float velocity_len = vlen(self.velocity);
- if(!self.hook.state && !(g_cts && !autocvar_g_cts_selfdamage))
+ if(!self.hook.state)
{
dm = vlen(self.oldvelocity) - velocity_len; // dm is now the velocity DECREASE. Velocity INCREASE should never cause a sound or any damage.
if (self.deadflag)
if(g_race)
{
-
if(autocvar_g_race_teams)
{
ActivateTeamplay();
qualifying_override = autocvar_g_race_qualifying_timelimit_override;
fraglimit_override = autocvar_g_race_laps_limit;
leadlimit_override = 0; // currently not supported by race
+
+ MUTATOR_ADD(gamemode_race);
}
if(g_cts)
g_race_qualifying = 1;
fraglimit_override = 0;
leadlimit_override = 0;
+ MUTATOR_ADD(gamemode_cts);
}
if(g_nexball)
}
if(g_race || g_cts)
- {
- if(g_race_qualifying)
- independent_players = 1;
-
- ScoreRules_race();
- }
+ if(g_race_qualifying)
+ independent_players = 1;
InitializeEntity(world, default_delayedinit, INITPRIO_GAMETYPE_FALLBACK);
}
else
{
// cover anything else by treating it like tdm with no teams spawned
- if(g_race)
- dm = race_teams;
- else
- dm = 2;
+ dm = 2;
ret_float = dm;
MUTATOR_CALLHOOK(GetTeamCount);