+#include "gamemode_cts.qh"
+#include <server/race.qh>
+
#ifndef GAMEMODE_CTS_H
#define GAMEMODE_CTS_H
+void cts_Initialize();
+
+REGISTER_MUTATOR(cts, false)
+{
+ MUTATOR_ONADD
+ {
+ if (time > 1) // game loads at time 1
+ error("This is a game type and it cannot be added at runtime.");
+
+ g_race_qualifying = true;
+ independent_players = 1;
+ SetLimits(0, 0, autocvar_timelimit_override, -1);
+
+ 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
+ {
+ LOG_INFO("This is a game type and it cannot be removed at runtime.");
+ return -1;
+ }
+
+ return 0;
+}
+
// scores
const float ST_CTS_LAPS = 1;
const float SP_CTS_LAPS = 4;
#ifdef IMPLEMENTATION
-#include "../../race.qh"
+#include <server/race.qh>
float autocvar_g_cts_finish_kill_delay;
bool autocvar_g_cts_selfdamage;
// legacy bot roles
.float race_checkpoint;
-void havocbot_role_cts()
-{SELFPARAM();
- if(self.deadflag != DEAD_NO)
+void havocbot_role_cts(entity this)
+{
+ if(IS_DEAD(this))
return;
- entity e;
- if (self.bot_strategytime < time)
+ if (this.bot_strategytime < time)
{
- self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
- navigation_goalrating_start();
+ this.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+ navigation_goalrating_start(this);
- for(e = world; (e = find(e, classname, "trigger_race_checkpoint")) != world; )
+ FOREACH_ENTITY_CLASS("trigger_race_checkpoint", true,
{
- if(e.cnt == self.race_checkpoint)
- {
- navigation_routerating(e, 1000000, 5000);
- }
- else if(self.race_checkpoint == -1)
- {
- navigation_routerating(e, 1000000, 5000);
- }
- }
+ if(it.cnt == this.race_checkpoint)
+ navigation_routerating(this, it, 1000000, 5000);
+ else if(this.race_checkpoint == -1)
+ navigation_routerating(this, it, 1000000, 5000);
+ });
- navigation_goalrating_end();
+ navigation_goalrating_end(this);
}
}
GameLogEcho(strcat(":cts:", mode, ":", ((actor != world) ? (strcat(":", ftos(actor.playerid))) : "")));
}
+void KillIndicator_Think();
void CTS_ClientKill(entity e) // silent version of ClientKill, used when player finishes a CTS run. Useful to prevent cheating by running back to the start line and starting out with more speed
{
e.killindicator = spawn();
race_ClearRecords();
PlayerScore_Sort(race_place, 0, 1, 0);
- entity e;
- FOR_EACH_CLIENT(e)
- {
- if(e.race_place)
+ FOREACH_CLIENT(true, LAMBDA(
+ if(it.race_place)
{
- s = PlayerScore_Add(e, SP_RACE_FASTEST, 0);
+ s = PlayerScore_Add(it, SP_RACE_FASTEST, 0);
if(!s)
- e.race_place = 0;
+ it.race_place = 0;
}
- cts_EventLog(ftos(e.race_place), e);
- }
+ cts_EventLog(ftos(it.race_place), it);
+ ));
if(g_race_qualifying == 2)
{
return false;
}
-MUTATOR_HOOKFUNCTION(cts, PlayerPreThink)
-{SELFPARAM();
- 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)
{SELFPARAM();
race_PreparePlayer();
if(IS_PLAYER(self))
if(!gameover)
{
- if(self.killcount == -666 /* initial spawn */ || g_race_qualifying) // spawn
+ if(self.killcount == FRAGS_SPECTATOR /* initial spawn */ || g_race_qualifying) // spawn
race_PreparePlayer();
else // respawn
race_RetractPlayer();
}
MUTATOR_HOOKFUNCTION(cts, PlayerDies)
-{SELFPARAM();
- self.respawn_flags |= RESPAWN_FORCE;
- race_AbandonRaceCheck(self);
+{
+ frag_target.respawn_flags |= RESPAWN_FORCE;
+ race_AbandonRaceCheck(frag_target);
return false;
}
return true; // in CTS, you don't lose score by observing
}
-MUTATOR_HOOKFUNCTION(cts, SetModname)
-{
- g_cloaked = 1; // always enable cloak in CTS
-
- return false;
-}
-
MUTATOR_HOOKFUNCTION(cts, GetRecords)
{
for(int i = record_page * 200; i < MapInfo_count && i < record_page * 200 + 200; ++i)
return false;
}
+void ClientKill_Now();
MUTATOR_HOOKFUNCTION(cts, ClientKill)
{
+ SELFPARAM();
ret_float = 0;
if(self.killindicator && self.killindicator.health == 1) // self.killindicator.health == 1 means that the kill indicator was spawned by CTS_ClientKill
MUTATOR_HOOKFUNCTION(cts, Race_FinalCheckpoint)
{
if(autocvar_g_cts_finish_kill_delay)
- CTS_ClientKill(self);
+ CTS_ClientKill(race_player);
return false;
}
MUTATOR_HOOKFUNCTION(cts, WantWeapon)
{
- ret_float = (want_weaponinfo.weapon == WEP_SHOTGUN.m_id);
+ ret_float = (want_weaponinfo == WEP_SHOTGUN);
want_mutatorblocked = true;
return true;
}
cts_ScoreRules();
}
-REGISTER_MUTATOR(cts, g_cts)
-{
- g_race_qualifying = 1;
- independent_players = 1;
- SetLimits(0, 0, 0, -1);
-
- 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
- {
- LOG_INFO("This is a game type and it cannot be removed at runtime.");
- return -1;
- }
-
- return 0;
-}
#endif