summaryrefslogtreecommitdiff
path: root/sourcemod/scripting/gokz-racing/racer.sp
diff options
context:
space:
mode:
authornavewindre <nw@moneybot.cc>2023-12-04 18:06:10 +0100
committernavewindre <nw@moneybot.cc>2023-12-04 18:06:10 +0100
commitaef0d1c1268ab7d4bc18996c9c6b4da16a40aadc (patch)
tree43e766b51704f4ab8b383583bdc1871eeeb9c698 /sourcemod/scripting/gokz-racing/racer.sp
parent38f1140c11724da05a23a10385061200b907cf6e (diff)
bbbbbbbbwaaaaaaaaaaa
Diffstat (limited to 'sourcemod/scripting/gokz-racing/racer.sp')
-rw-r--r--sourcemod/scripting/gokz-racing/racer.sp439
1 files changed, 439 insertions, 0 deletions
diff --git a/sourcemod/scripting/gokz-racing/racer.sp b/sourcemod/scripting/gokz-racing/racer.sp
new file mode 100644
index 0000000..eb4ff3f
--- /dev/null
+++ b/sourcemod/scripting/gokz-racing/racer.sp
@@ -0,0 +1,439 @@
+/*
+ Functions that affect the state of clients participating in a race.
+ See the RacerStatus enum for possible states.
+*/
+
+
+
+static int racerStatus[MAXPLAYERS + 1];
+static int racerRaceID[MAXPLAYERS + 1];
+static float lastTimerStartTime[MAXPLAYERS + 1];
+static float lastCheckpointTime[MAXPLAYERS + 1];
+
+
+
+// =====[ EVENTS ]=====
+
+Action OnTimerStart_Racer(int client, int course)
+{
+ if (InCountdown(client)
+ || InStartedRace(client) && (!InRaceMode(client) || !IsRaceCourse(client, course)))
+ {
+ return Plugin_Stop;
+ }
+
+ return Plugin_Continue;
+}
+
+Action OnTimerStart_Post_Racer(int client)
+{
+ lastTimerStartTime[client] = GetGameTime();
+ return Plugin_Continue;
+}
+
+Action OnMakeCheckpoint_Racer(int client)
+{
+ if (GOKZ_GetTimerRunning(client) && InStartedRace(client))
+ {
+ int checkpointRule = GetRaceInfo(GetRaceID(client), RaceInfo_CheckpointRule);
+ if (checkpointRule == 0)
+ {
+ GOKZ_PrintToChat(client, true, "%t", "Checkpoints Not Allowed During Race");
+ GOKZ_PlayErrorSound(client);
+ return Plugin_Handled;
+ }
+ else if (checkpointRule != -1 && GOKZ_GetCheckpointCount(client) >= checkpointRule)
+ {
+ GOKZ_PrintToChat(client, true, "%t", "No Checkpoints Left");
+ GOKZ_PlayErrorSound(client);
+ return Plugin_Handled;
+ }
+
+ float cooldownRule = float(GetRaceInfo(GetRaceID(client), RaceInfo_CooldownRule));
+ float timeSinceLastCheckpoint = FloatMin(
+ GetGameTime() - lastTimerStartTime[client],
+ GetGameTime() - lastCheckpointTime[client]);
+ if (timeSinceLastCheckpoint < cooldownRule)
+ {
+ GOKZ_PrintToChat(client, true, "%t", "Checkpoint On Cooldown", (cooldownRule - timeSinceLastCheckpoint));
+ GOKZ_PlayErrorSound(client);
+ return Plugin_Handled;
+ }
+ }
+
+ return Plugin_Continue;
+}
+
+void OnMakeCheckpoint_Post_Racer(int client)
+{
+ lastCheckpointTime[client] = GetGameTime();
+}
+
+Action OnUndoTeleport_Racer(int client)
+{
+ if (GOKZ_GetTimerRunning(client)
+ && InStartedRace(client)
+ && GetRaceInfo(GetRaceID(client), RaceInfo_CheckpointRule) != -1)
+ {
+ GOKZ_PrintToChat(client, true, "%t", "Undo TP Not Allowed During Race");
+ GOKZ_PlayErrorSound(client);
+ return Plugin_Handled;
+ }
+
+ return Plugin_Continue;
+}
+
+
+
+// =====[ GENERAL ]=====
+
+int GetStatus(int client)
+{
+ return racerStatus[client];
+}
+
+int GetRaceID(int client)
+{
+ return racerRaceID[client];
+}
+
+bool InRace(int client)
+{
+ return GetStatus(client) != RacerStatus_Available;
+}
+
+bool InStartedRace(int client)
+{
+ return GetStatus(client) == RacerStatus_Racing;
+}
+
+bool InCountdown(int client)
+{
+ return GetRaceInfo(GetRaceID(client), RaceInfo_Status) == RaceStatus_Countdown;
+}
+
+bool InRaceMode(int client)
+{
+ return GOKZ_GetCoreOption(client, Option_Mode) == GetRaceInfo(GetRaceID(client), RaceInfo_Mode);
+}
+
+bool IsRaceCourse(int client, int course)
+{
+ return course == GetRaceInfo(GetRaceID(client), RaceInfo_Course);
+}
+
+bool IsFinished(int client)
+{
+ int status = GetStatus(client);
+ return status == RacerStatus_Finished || status == RacerStatus_Surrendered;
+}
+
+bool IsAccepted(int client)
+{
+ return GetStatus(client) == RacerStatus_Accepted;
+}
+
+bool IsRaceHost(int client)
+{
+ return GetRaceHost(GetRaceID(client)) == client;
+}
+
+static void ResetRacer(int client)
+{
+ racerStatus[client] = RacerStatus_Available;
+ racerRaceID[client] = -1;
+ lastTimerStartTime[client] = 0.0;
+ lastCheckpointTime[client] = 0.0;
+}
+
+static void ResetRacersInRace(int raceID)
+{
+ for (int client = 1; client <= MaxClients; client++)
+ {
+ if (racerRaceID[client] == raceID)
+ {
+ ResetRacer(client);
+ }
+ }
+}
+
+
+
+// =====[ RACING ]=====
+
+void StartRacer(int client)
+{
+ if (racerStatus[client] == RacerStatus_Pending)
+ {
+ DeclineRequest(client, true);
+ return;
+ }
+
+ if (racerStatus[client] != RacerStatus_Accepted)
+ {
+ return;
+ }
+
+ racerStatus[client] = RacerStatus_Racing;
+
+ // Prepare the racer
+ GOKZ_StopTimer(client);
+ GOKZ_SetCoreOption(client, Option_Mode, GetRaceInfo(racerRaceID[client], RaceInfo_Mode));
+
+ int course = GetRaceInfo(racerRaceID[client], RaceInfo_Course);
+ if (GOKZ_SetStartPositionToMapStart(client, course))
+ {
+ GOKZ_TeleportToStart(client);
+ }
+ else
+ {
+ GOKZ_PrintToChat(client, true, "%t", "No Start Found", course);
+ }
+}
+
+bool FinishRacer(int client, int course)
+{
+ if (racerStatus[client] != RacerStatus_Racing ||
+ course != GetRaceInfo(racerRaceID[client], RaceInfo_Course))
+ {
+ return false;
+ }
+
+ racerStatus[client] = RacerStatus_Finished;
+
+ int raceID = racerRaceID[client];
+ int place = IncrementFinishedRacerCount(raceID);
+
+ Call_OnFinish(client, raceID, place);
+
+ CheckRaceFinished(raceID);
+
+ return true;
+}
+
+bool SurrenderRacer(int client)
+{
+ if (racerStatus[client] == RacerStatus_Available
+ || racerStatus[client] == RacerStatus_Surrendered)
+ {
+ return false;
+ }
+
+ racerStatus[client] = RacerStatus_Surrendered;
+
+ int raceID = racerRaceID[client];
+
+ Call_OnSurrender(client, raceID);
+
+ CheckRaceFinished(raceID);
+
+ return true;
+}
+
+// Auto-finish last remaining racer, and reset everyone if no one is left
+static void CheckRaceFinished(int raceID)
+{
+ ArrayList remainingRacers = GetUnfinishedRacers(raceID);
+ if (remainingRacers.Length == 1)
+ {
+ int lastRacer = remainingRacers.Get(0);
+ FinishRacer(lastRacer, GetRaceInfo(racerRaceID[lastRacer], RaceInfo_Course));
+ }
+ else if (remainingRacers.Length == 0)
+ {
+ ResetRacersInRace(raceID);
+ }
+ delete remainingRacers;
+}
+
+bool AbortRacer(int client)
+{
+ if (racerStatus[client] == RacerStatus_Available)
+ {
+ return false;
+ }
+
+ ResetRacer(client);
+
+ return true;
+}
+
+
+
+// =====[ HOSTING ]=====
+
+int HostRace(int client, int type, int course, int mode, int checkpointRule, int cooldownRule)
+{
+ if (InRace(client))
+ {
+ return -1;
+ }
+
+ int raceID = RegisterRace(client, type, course, mode, checkpointRule, cooldownRule);
+ racerRaceID[client] = raceID;
+ racerStatus[client] = RacerStatus_Accepted;
+
+ return raceID;
+}
+
+bool StartHostedRace(int client)
+{
+ if (!InRace(client) || !IsRaceHost(client))
+ {
+ GOKZ_PrintToChat(client, true, "%t", "You Are Not Hosting A Race");
+ GOKZ_PlayErrorSound(client);
+ return false;
+ }
+
+ int raceID = racerRaceID[client];
+
+ if (GetRaceInfo(raceID, RaceInfo_Status) != RaceStatus_Pending)
+ {
+ GOKZ_PrintToChat(client, true, "%t", "Race Already Started");
+ GOKZ_PlayErrorSound(client);
+ return false;
+ }
+
+ if (GetAcceptedRacersCount(raceID) <= 1)
+ {
+ GOKZ_PrintToChat(client, true, "%t", "No One Accepted");
+ GOKZ_PlayErrorSound(client);
+ return false;
+ }
+
+ return StartRace(raceID);
+}
+
+bool AbortHostedRace(int client)
+{
+ if (!InRace(client) || !IsRaceHost(client))
+ {
+ GOKZ_PrintToChat(client, true, "%t", "You Are Not Hosting A Race");
+ GOKZ_PlayErrorSound(client);
+ return false;
+ }
+
+ int raceID = racerRaceID[client];
+
+ return AbortRace(raceID);
+}
+
+
+
+// =====[ REQUESTS ]=====
+
+bool SendRequest(int host, int target)
+{
+ if (IsFakeClient(target) || target == host || InRace(target)
+ || !IsRaceHost(host) || GetRaceInfo(racerRaceID[host], RaceInfo_Status) != RaceStatus_Pending)
+ {
+ return false;
+ }
+
+ int raceID = racerRaceID[host];
+
+ racerRaceID[target] = raceID;
+ racerStatus[target] = RacerStatus_Pending;
+
+ // Host callback
+ DataPack data = new DataPack();
+ data.WriteCell(GetClientUserId(host));
+ data.WriteCell(GetClientUserId(target));
+ data.WriteCell(raceID);
+ CreateTimer(RC_REQUEST_TIMEOUT_TIME, Timer_RequestTimeout, data);
+
+ Call_OnRequestReceived(target, raceID);
+
+ return true;
+}
+
+public Action Timer_RequestTimeout(Handle timer, DataPack data)
+{
+ data.Reset();
+ int host = GetClientOfUserId(data.ReadCell());
+ int target = GetClientOfUserId(data.ReadCell());
+ int raceID = data.ReadCell();
+ delete data;
+
+ if (!IsValidClient(host) || racerRaceID[host] != raceID
+ || !IsValidClient(target) || racerRaceID[target] != raceID)
+ {
+ return Plugin_Continue;
+ }
+
+ // If haven't accepted by now, auto decline the race
+ if (racerStatus[target] == RacerStatus_Pending)
+ {
+ DeclineRequest(target, true);
+ }
+ return Plugin_Continue;
+}
+
+int SendRequestAll(int host)
+{
+ int sentCount = 0;
+ for (int target = 1; target <= MaxClients; target++)
+ {
+ if (IsClientInGame(target) && SendRequest(host, target))
+ {
+ sentCount++;
+ }
+ }
+ return sentCount;
+}
+
+bool AcceptRequest(int client)
+{
+ if (GetStatus(client) != RacerStatus_Pending)
+ {
+ return false;
+ }
+
+ racerStatus[client] = RacerStatus_Accepted;
+
+ Call_OnRequestAccepted(client, racerRaceID[client]);
+
+ return true;
+}
+
+bool DeclineRequest(int client, bool timeout = false)
+{
+ if (GetStatus(client) != RacerStatus_Pending)
+ {
+ return false;
+ }
+
+ int raceID = racerRaceID[client];
+ ResetRacer(client);
+
+ Call_OnRequestDeclined(client, raceID, timeout);
+
+ return true;
+}
+
+
+
+// =====[ EVENTS ]=====
+
+void OnClientPutInServer_Racer(int client)
+{
+ ResetRacer(client);
+}
+
+void OnClientDisconnect_Racer(int client)
+{
+ // Abort if player was the host of the race, else surrender
+ if (InRace(client))
+ {
+ if (IsRaceHost(client) && GetRaceInfo(racerRaceID[client], RaceInfo_Status) == RaceStatus_Pending)
+ {
+ AbortRace(racerRaceID[client]);
+ }
+ else
+ {
+ SurrenderRacer(client);
+ }
+ }
+
+ ResetRacer(client);
+} \ No newline at end of file