summaryrefslogtreecommitdiff
path: root/sourcemod/scripting/gokz-core/timer
diff options
context:
space:
mode:
Diffstat (limited to 'sourcemod/scripting/gokz-core/timer')
-rw-r--r--sourcemod/scripting/gokz-core/timer/pause.sp257
-rw-r--r--sourcemod/scripting/gokz-core/timer/timer.sp368
-rw-r--r--sourcemod/scripting/gokz-core/timer/virtual_buttons.sp322
3 files changed, 0 insertions, 947 deletions
diff --git a/sourcemod/scripting/gokz-core/timer/pause.sp b/sourcemod/scripting/gokz-core/timer/pause.sp
deleted file mode 100644
index 92ab1fb..0000000
--- a/sourcemod/scripting/gokz-core/timer/pause.sp
+++ /dev/null
@@ -1,257 +0,0 @@
-static bool paused[MAXPLAYERS + 1];
-static bool pausedOnLadder[MAXPLAYERS + 1];
-static float lastPauseTime[MAXPLAYERS + 1];
-static bool hasPausedInThisRun[MAXPLAYERS + 1];
-static float lastResumeTime[MAXPLAYERS + 1];
-static bool hasResumedInThisRun[MAXPLAYERS + 1];
-static float lastDuckValue[MAXPLAYERS + 1];
-static float lastStaminaValue[MAXPLAYERS + 1];
-
-
-
-// =====[ PUBLIC ]=====
-
-bool GetPaused(int client)
-{
- return paused[client];
-}
-
-void SetPausedOnLadder(int client, bool onLadder)
-{
- pausedOnLadder[client] = onLadder;
-}
-
-void Pause(int client)
-{
- if (!CanPause(client, true))
- {
- return;
- }
-
- // Call Pre Forward
- Action result;
- Call_GOKZ_OnPause(client, result);
- if (result != Plugin_Continue)
- {
- GOKZ_PrintToChat(client, true, "%t", "Can't Pause (Generic)");
- GOKZ_PlayErrorSound(client);
- return;
- }
-
- // Pause
- paused[client] = true;
- pausedOnLadder[client] = Movement_GetMovetype(client) == MOVETYPE_LADDER;
- lastDuckValue[client] = Movement_GetDuckSpeed(client);
- lastStaminaValue[client] = GetEntPropFloat(client, Prop_Send, "m_flStamina");
- Movement_SetVelocity(client, view_as<float>( { 0.0, 0.0, 0.0 } ));
- Movement_SetMovetype(client, MOVETYPE_NONE);
- if (GetTimerRunning(client))
- {
- hasPausedInThisRun[client] = true;
- lastPauseTime[client] = GetEngineTime();
- }
-
- // Call Post Forward
- Call_GOKZ_OnPause_Post(client);
-}
-
-bool CanPause(int client, bool showError = false)
-{
- if (paused[client])
- {
- return false;
- }
-
- if (GetTimerRunning(client))
- {
- if (hasResumedInThisRun[client]
- && GetEngineTime() - lastResumeTime[client] < GOKZ_PAUSE_COOLDOWN)
- {
- if (showError)
- {
- GOKZ_PrintToChat(client, true, "%t", "Can't Pause (Just Resumed)");
- GOKZ_PlayErrorSound(client);
- }
- return false;
- }
- else if (!Movement_GetOnGround(client)
- && !(Movement_GetSpeed(client) == 0 && Movement_GetVerticalVelocity(client) == 0))
- {
- if (showError)
- {
- GOKZ_PrintToChat(client, true, "%t", "Can't Pause (Midair)");
- GOKZ_PlayErrorSound(client);
- }
- return false;
- }
- else if (BhopTriggersJustTouched(client))
- {
- if (showError)
- {
- GOKZ_PrintToChat(client, true, "%t", "Can't Pause (Just Landed)");
- GOKZ_PlayErrorSound(client);
- }
- return false;
- }
- else if (AntiPauseTriggerIsTouched(client))
- {
- if (showError)
- {
- GOKZ_PrintToChat(client, true, "%t", "Can't Pause (Anti Pause Area)");
- GOKZ_PlayErrorSound(client);
- }
- return false;
- }
- }
-
- return true;
-}
-
-void Resume(int client, bool force = false)
-{
- if (!paused[client])
- {
- return;
- }
- if (!force && !CanResume(client, true))
- {
- return;
- }
-
- // Call Pre Forward
- Action result;
- Call_GOKZ_OnResume(client, result);
- if (result != Plugin_Continue)
- {
- GOKZ_PrintToChat(client, true, "%t", "Can't Resume (Generic)");
- GOKZ_PlayErrorSound(client);
- return;
- }
-
- // Resume
- if (pausedOnLadder[client])
- {
- Movement_SetMovetype(client, MOVETYPE_LADDER);
- }
- else
- {
- Movement_SetMovetype(client, MOVETYPE_WALK);
- }
-
- // Prevent noclip exploit
- SetEntProp(client, Prop_Send, "m_CollisionGroup", GOKZ_COLLISION_GROUP_STANDARD);
- paused[client] = false;
- if (GetTimerRunning(client))
- {
- hasResumedInThisRun[client] = true;
- lastResumeTime[client] = GetEngineTime();
- }
- Movement_SetDuckSpeed(client, lastDuckValue[client]);
- SetEntPropFloat(client, Prop_Send, "m_flStamina", lastStaminaValue[client]);
-
- // Call Post Forward
- Call_GOKZ_OnResume_Post(client);
-}
-
-bool CanResume(int client, bool showError = false)
-{
- if (GetTimerRunning(client) && hasPausedInThisRun[client]
- && GetEngineTime() - lastPauseTime[client] < GOKZ_PAUSE_COOLDOWN)
- {
- if (showError)
- {
- GOKZ_PrintToChat(client, true, "%t", "Can't Resume (Just Paused)");
- GOKZ_PlayErrorSound(client);
- }
- return false;
- }
- return true;
-}
-
-void TogglePause(int client)
-{
- if (paused[client])
- {
- Resume(client);
- }
- else
- {
- Pause(client);
- }
-}
-
-
-
-// =====[ EVENTS ]=====
-
-void OnClientPutInServer_Pause(int client)
-{
- paused[client] = false;
-}
-
-void OnTimerStart_Pause(int client)
-{
- hasPausedInThisRun[client] = false;
- hasResumedInThisRun[client] = false;
- Resume(client, true);
-}
-
-void OnChangeMovetype_Pause(int client, MoveType newMovetype)
-{
- // Check if player has escaped MOVETYPE_NONE
- if (!paused[client] || newMovetype == MOVETYPE_NONE)
- {
- return;
- }
-
- // Player has escaped MOVETYPE_NONE, so resume
- paused[client] = false;
- if (GetTimerRunning(client))
- {
- hasResumedInThisRun[client] = true;
- lastResumeTime[client] = GetEngineTime();
- }
-
- // Call Post Forward
- Call_GOKZ_OnResume_Post(client);
-}
-
-void OnPlayerSpawn_Pause(int client)
-{
- if (!paused[client])
- {
- return;
- }
-
- // Player has left paused state by spawning in, so resume
- paused[client] = false;
- if (GetTimerRunning(client))
- {
- hasResumedInThisRun[client] = true;
- lastResumeTime[client] = GetEngineTime();
- }
-
- Movement_SetDuckSpeed(client, lastDuckValue[client]);
- SetEntPropFloat(client, Prop_Send, "m_flStamina", lastStaminaValue[client]);
-
- // Call Post Forward
- Call_GOKZ_OnResume_Post(client);
-}
-
-void OnJoinTeam_Pause(int client, int team)
-{
- // Only handle joining spectators. Joining other teams is handled by OnPlayerSpawn.
- if (team == CS_TEAM_SPECTATOR)
- {
- paused[client] = true;
-
- if (GetTimerRunning(client))
- {
- hasPausedInThisRun[client] = true;
- lastPauseTime[client] = GetEngineTime();
- }
-
- // Call Post Forward
- Call_GOKZ_OnPause_Post(client);
- }
-} \ No newline at end of file
diff --git a/sourcemod/scripting/gokz-core/timer/timer.sp b/sourcemod/scripting/gokz-core/timer/timer.sp
deleted file mode 100644
index f6696ac..0000000
--- a/sourcemod/scripting/gokz-core/timer/timer.sp
+++ /dev/null
@@ -1,368 +0,0 @@
-static bool timerRunning[MAXPLAYERS + 1];
-static float currentTime[MAXPLAYERS + 1];
-static int currentCourse[MAXPLAYERS + 1];
-static float lastEndTime[MAXPLAYERS + 1];
-static float lastFalseEndTime[MAXPLAYERS + 1];
-static float lastStartSoundTime[MAXPLAYERS + 1];
-static int lastStartMode[MAXPLAYERS + 1];
-static bool validTime[MAXPLAYERS + 1];
-
-
-// =====[ PUBLIC ]=====
-
-bool GetTimerRunning(int client)
-{
- return timerRunning[client];
-}
-
-bool GetValidTimer(int client)
-{
- return validTime[client];
-}
-
-float GetCurrentTime(int client)
-{
- return currentTime[client];
-}
-
-void SetCurrentTime(int client, float time)
-{
- currentTime[client] = time;
- // The timer should be running if time is not negative.
- timerRunning[client] = time >= 0.0;
-}
-
-int GetCurrentCourse(int client)
-{
- return currentCourse[client];
-}
-
-void SetCurrentCourse(int client, int course)
-{
- currentCourse[client] = course;
-}
-
-int GetCurrentTimeType(int client)
-{
- if (GetTeleportCount(client) == 0)
- {
- return TimeType_Pro;
- }
- return TimeType_Nub;
-}
-
-bool TimerStart(int client, int course, bool allowMidair = false, bool playSound = true)
-{
- if (!IsPlayerAlive(client)
- || JustStartedTimer(client)
- || JustTeleported(client)
- || JustNoclipped(client)
- || !IsPlayerValidMoveType(client)
- || !allowMidair && (!Movement_GetOnGround(client) || JustLanded(client))
- || allowMidair && !Movement_GetOnGround(client) && (!GOKZ_GetValidJump(client) || GOKZ_GetHitPerf(client))
- || (GOKZ_GetTimerRunning(client) && GOKZ_GetCourse(client) != course))
- {
- return false;
- }
-
- // Call Pre Forward
- Action result;
- Call_GOKZ_OnTimerStart(client, course, result);
- if (result != Plugin_Continue)
- {
- return false;
- }
-
- // Prevent noclip exploit
- SetEntProp(client, Prop_Send, "m_CollisionGroup", GOKZ_COLLISION_GROUP_STANDARD);
-
- // Start Timer
- currentTime[client] = 0.0;
- timerRunning[client] = true;
- currentCourse[client] = course;
- lastStartMode[client] = GOKZ_GetCoreOption(client, Option_Mode);
- validTime[client] = true;
- if (playSound)
- {
- PlayTimerStartSound(client);
- }
-
- // Call Post Forward
- Call_GOKZ_OnTimerStart_Post(client, course);
-
- return true;
-}
-
-bool TimerEnd(int client, int course)
-{
- if (!IsPlayerAlive(client))
- {
- return false;
- }
-
- if (!timerRunning[client] || course != currentCourse[client])
- {
- PlayTimerFalseEndSound(client);
- lastFalseEndTime[client] = GetGameTime();
- return false;
- }
-
- float time = GetCurrentTime(client);
- int teleportsUsed = GetTeleportCount(client);
-
- // Call Pre Forward
- Action result;
- Call_GOKZ_OnTimerEnd(client, course, time, teleportsUsed, result);
- if (result != Plugin_Continue)
- {
- return false;
- }
-
- if (!validTime[client])
- {
- PlayTimerFalseEndSound(client);
- lastFalseEndTime[client] = GetGameTime();
- TimerStop(client, false);
- return false;
- }
- // End Timer
- timerRunning[client] = false;
- lastEndTime[client] = GetGameTime();
- PlayTimerEndSound(client);
-
- if (!IsFakeClient(client))
- {
- // Print end timer message
- Call_GOKZ_OnTimerEndMessage(client, course, time, teleportsUsed, result);
- if (result == Plugin_Continue)
- {
- PrintEndTimeString(client);
- }
- }
-
- // Call Post Forward
- Call_GOKZ_OnTimerEnd_Post(client, course, time, teleportsUsed);
-
- return true;
-}
-
-bool TimerStop(int client, bool playSound = true)
-{
- if (!timerRunning[client])
- {
- return false;
- }
-
- timerRunning[client] = false;
- if (playSound)
- {
- PlayTimerStopSound(client);
- }
-
- Call_GOKZ_OnTimerStopped(client);
-
- return true;
-}
-
-void TimerStopAll(bool playSound = true)
-{
- for (int client = 1; client <= MaxClients; client++)
- {
- if (IsValidClient(client))
- {
- TimerStop(client, playSound);
- }
- }
-}
-
-void PlayTimerStartSound(int client)
-{
- if (GetGameTime() - lastStartSoundTime[client] > GOKZ_TIMER_SOUND_COOLDOWN)
- {
- GOKZ_EmitSoundToClient(client, gC_ModeStartSounds[GOKZ_GetCoreOption(client, Option_Mode)], _, "Timer Start");
- GOKZ_EmitSoundToClientSpectators(client, gC_ModeStartSounds[GOKZ_GetCoreOption(client, Option_Mode)], _, "Timer Start");
- lastStartSoundTime[client] = GetGameTime();
- }
-}
-
-void InvalidateRun(int client)
-{
- if (validTime[client])
- {
- validTime[client] = false;
- Call_GOKZ_OnRunInvalidated(client);
- }
-}
-
-// =====[ EVENTS ]=====
-
-void OnClientPutInServer_Timer(int client)
-{
- timerRunning[client] = false;
- currentTime[client] = 0.0;
- currentCourse[client] = 0;
- lastEndTime[client] = 0.0;
- lastFalseEndTime[client] = 0.0;
- lastStartSoundTime[client] = 0.0;
- lastStartMode[client] = MODE_COUNT; // So it won't equal any mode
-}
-
-void OnPlayerRunCmdPost_Timer(int client)
-{
- if (IsPlayerAlive(client) && GetTimerRunning(client) && !GetPaused(client))
- {
- currentTime[client] += GetTickInterval();
- }
-}
-
-void OnChangeMovetype_Timer(int client, MoveType newMovetype)
-{
- if (!IsValidMovetype(newMovetype))
- {
- if (TimerStop(client))
- {
- GOKZ_PrintToChat(client, true, "%t", "Timer Stopped (Noclipped)");
- }
- }
-}
-
-void OnTeleportToStart_Timer(int client)
-{
- if (GetCurrentMapPrefix() == MapPrefix_KZPro)
- {
- TimerStop(client, false);
- }
-}
-
-void OnClientDisconnect_Timer(int client)
-{
- TimerStop(client);
-}
-
-void OnPlayerDeath_Timer(int client)
-{
- TimerStop(client);
-}
-
-void OnOptionChanged_Timer(int client, Option option)
-{
- if (option == Option_Mode)
- {
- if (TimerStop(client))
- {
- GOKZ_PrintToChat(client, true, "%t", "Timer Stopped (Changed Mode)");
- }
- }
-}
-
-void OnRoundStart_Timer()
-{
- TimerStopAll();
-}
-
-
-
-// =====[ PRIVATE ]=====
-
-static bool IsPlayerValidMoveType(int client)
-{
- return IsValidMovetype(Movement_GetMovetype(client));
-}
-
-static bool IsValidMovetype(MoveType movetype)
-{
- return movetype == MOVETYPE_WALK
- || movetype == MOVETYPE_LADDER
- || movetype == MOVETYPE_NONE
- || movetype == MOVETYPE_OBSERVER;
-}
-
-static bool JustTeleported(int client)
-{
- return gB_OriginTeleported[client] || gB_VelocityTeleported[client]
- || gI_CmdNum[client] - gI_TeleportCmdNum[client] <= GOKZ_TIMER_START_GROUND_TICKS;
-}
-
-static bool JustLanded(int client)
-{
- return !gB_OldOnGround[client]
- || gI_CmdNum[client] - Movement_GetLandingCmdNum(client) <= GOKZ_TIMER_START_NO_TELEPORT_TICKS;
-}
-
-static bool JustStartedTimer(int client)
-{
- return timerRunning[client] && GetCurrentTime(client) < EPSILON;
-}
-
-static bool JustEndedTimer(int client)
-{
- return GetGameTime() - lastEndTime[client] < 1.0;
-}
-
-static void PlayTimerEndSound(int client)
-{
- GOKZ_EmitSoundToClient(client, gC_ModeEndSounds[GOKZ_GetCoreOption(client, Option_Mode)], _, "Timer End");
- GOKZ_EmitSoundToClientSpectators(client, gC_ModeEndSounds[GOKZ_GetCoreOption(client, Option_Mode)], _, "Timer End");
-}
-
-static void PlayTimerFalseEndSound(int client)
-{
- if (!JustEndedTimer(client)
- && (GetGameTime() - lastFalseEndTime[client]) > GOKZ_TIMER_SOUND_COOLDOWN)
- {
- GOKZ_EmitSoundToClient(client, gC_ModeFalseEndSounds[GOKZ_GetCoreOption(client, Option_Mode)], _, "Timer False End");
- GOKZ_EmitSoundToClientSpectators(client, gC_ModeFalseEndSounds[GOKZ_GetCoreOption(client, Option_Mode)], _, "Timer False End");
- }
-}
-
-static void PlayTimerStopSound(int client)
-{
- GOKZ_EmitSoundToClient(client, GOKZ_SOUND_TIMER_STOP, _, "Timer Stop");
- GOKZ_EmitSoundToClientSpectators(client, GOKZ_SOUND_TIMER_STOP, _, "Timer Stop");
-}
-
-static void PrintEndTimeString(int client)
-{
- if (GetCurrentCourse(client) == 0)
- {
- switch (GetCurrentTimeType(client))
- {
- case TimeType_Nub:
- {
- GOKZ_PrintToChatAll(true, "%t", "Beat Map (NUB)",
- client,
- GOKZ_FormatTime(GetCurrentTime(client)),
- gC_ModeNamesShort[GOKZ_GetCoreOption(client, Option_Mode)]);
- }
- case TimeType_Pro:
- {
- GOKZ_PrintToChatAll(true, "%t", "Beat Map (PRO)",
- client,
- GOKZ_FormatTime(GetCurrentTime(client)),
- gC_ModeNamesShort[GOKZ_GetCoreOption(client, Option_Mode)]);
- }
- }
- }
- else
- {
- switch (GetCurrentTimeType(client))
- {
- case TimeType_Nub:
- {
- GOKZ_PrintToChatAll(true, "%t", "Beat Bonus (NUB)",
- client,
- currentCourse[client],
- GOKZ_FormatTime(GetCurrentTime(client)),
- gC_ModeNamesShort[GOKZ_GetCoreOption(client, Option_Mode)]);
- }
- case TimeType_Pro:
- {
- GOKZ_PrintToChatAll(true, "%t", "Beat Bonus (PRO)",
- client,
- currentCourse[client],
- GOKZ_FormatTime(GetCurrentTime(client)),
- gC_ModeNamesShort[GOKZ_GetCoreOption(client, Option_Mode)]);
- }
- }
- }
-} \ No newline at end of file
diff --git a/sourcemod/scripting/gokz-core/timer/virtual_buttons.sp b/sourcemod/scripting/gokz-core/timer/virtual_buttons.sp
deleted file mode 100644
index aa88a9d..0000000
--- a/sourcemod/scripting/gokz-core/timer/virtual_buttons.sp
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- Most commonly referred to in the KZ community as timer tech.
- Lets players press 'virtual' start and end buttons without looking.
-*/
-
-
-
-static int beamSprite;
-static int haloSprite;
-static float lastUsePressTime[MAXPLAYERS + 1];
-static int lastTeleportTick[MAXPLAYERS + 1];
-static bool startedTimerLastTick[MAXPLAYERS + 1];
-static bool onlyNaturalButtonPressed[MAXPLAYERS + 1];
-static int startTimerButtonPressTick[MAXPLAYERS + 1];
-static bool hasEndedTimerSincePressingUse[MAXPLAYERS + 1];
-static bool hasTeleportedSincePressingUse[MAXPLAYERS + 1];
-static bool hasVirtualStartButton[MAXPLAYERS + 1];
-static bool hasVirtualEndButton[MAXPLAYERS + 1];
-static bool wasInEndZone[MAXPLAYERS + 1];
-static float virtualStartOrigin[MAXPLAYERS + 1][3];
-static float virtualEndOrigin[MAXPLAYERS + 1][3];
-static int virtualStartCourse[MAXPLAYERS + 1];
-static int virtualEndCourse[MAXPLAYERS + 1];
-static bool virtualButtonsLocked[MAXPLAYERS + 1];
-
-
-
-// =====[ PUBLIC ]=====
-
-bool GetHasVirtualStartButton(int client)
-{
- return hasVirtualStartButton[client];
-}
-
-bool GetHasVirtualEndButton(int client)
-{
- return hasVirtualEndButton[client];
-}
-
-bool ToggleVirtualButtonsLock(int client)
-{
- virtualButtonsLocked[client] = !virtualButtonsLocked[client];
- return virtualButtonsLocked[client];
-}
-
-void LockVirtualButtons(int client)
-{
- virtualButtonsLocked[client] = true;
-}
-
-int GetVirtualButtonPosition(int client, float position[3], bool isStart)
-{
- if (isStart && hasVirtualStartButton[client])
- {
- position = virtualStartOrigin[client];
- return virtualStartCourse[client];
- }
- else if (!isStart && hasVirtualEndButton[client])
- {
- position = virtualEndOrigin[client];
- return virtualEndCourse[client];
- }
-
- return -1;
-}
-
-void SetVirtualButtonPosition(int client, float position[3], int course, bool isStart)
-{
- if (isStart)
- {
- virtualStartCourse[client] = course;
- virtualStartOrigin[client] = position;
- hasVirtualStartButton[client] = true;
- }
- else
- {
- virtualEndCourse[client] = course;
- virtualEndOrigin[client] = position;
- hasVirtualEndButton[client] = true;
- }
-}
-
-void ResetVirtualButtonPosition(int client, bool isStart)
-{
- if (isStart)
- {
- virtualStartCourse[client] = -1;
- virtualStartOrigin[client] = {0.0, 0.0, 0.0};
- hasVirtualStartButton[client] = false;
- }
- else
- {
- virtualEndCourse[client] = -1;
- virtualEndOrigin[client] = {0.0, 0.0, 0.0};
- hasVirtualEndButton[client] = false;
- }
-}
-
-// =====[ EVENTS ]=====
-
-void OnMapStart_VirtualButtons()
-{
- beamSprite = PrecacheModel("materials/sprites/laserbeam.vmt");
- haloSprite = PrecacheModel("materials/sprites/glow01.vmt");
-}
-
-void OnClientPutInServer_VirtualButtons(int client)
-{
- startedTimerLastTick[client] = false;
- hasVirtualEndButton[client] = false;
- hasVirtualStartButton[client] = false;
- virtualButtonsLocked[client] = false;
- onlyNaturalButtonPressed[client] = false;
- wasInEndZone[client] = false;
- startTimerButtonPressTick[client] = 0;
-}
-
-void OnStartButtonPress_VirtualButtons(int client, int course)
-{
- if (!virtualButtonsLocked[client] &&
- lastTeleportTick[client] + GOKZ_TIMER_START_NO_TELEPORT_TICKS < GetGameTickCount())
- {
- Movement_GetOrigin(client, virtualStartOrigin[client]);
- virtualStartCourse[client] = course;
- hasVirtualStartButton[client] = true;
- startTimerButtonPressTick[client] = GetGameTickCount();
- }
-}
-
-void OnEndButtonPress_VirtualButtons(int client, int course)
-{
- // Prevent setting end virtual button to where it would usually be unreachable
- if (IsPlayerStuck(client))
- {
- return;
- }
-
- if (!virtualButtonsLocked[client] &&
- lastTeleportTick[client] + GOKZ_TIMER_START_NO_TELEPORT_TICKS < GetGameTickCount())
- {
- Movement_GetOrigin(client, virtualEndOrigin[client]);
- virtualEndCourse[client] = course;
- hasVirtualEndButton[client] = true;
- }
-}
-
-void OnPlayerRunCmdPost_VirtualButtons(int client, int buttons, int cmdnum)
-{
- CheckForAndHandleUsage(client, buttons);
- UpdateIndicators(client, cmdnum);
-}
-
-void OnCountedTeleport_VirtualButtons(int client)
-{
- hasTeleportedSincePressingUse[client] = true;
-}
-
-void OnTeleport_DelayVirtualButtons(int client)
-{
- lastTeleportTick[client] = GetGameTickCount();
-}
-
-
-
-// =====[ PRIVATE ]=====
-
-static void CheckForAndHandleUsage(int client, int buttons)
-{
- if (buttons & IN_USE && !(gI_OldButtons[client] & IN_USE))
- {
- lastUsePressTime[client] = GetGameTime();
- hasEndedTimerSincePressingUse[client] = false;
- hasTeleportedSincePressingUse[client] = false;
- onlyNaturalButtonPressed[client] = startTimerButtonPressTick[client] == GetGameTickCount();
- }
-
- bool useCheck = PassesUseCheck(client);
-
- // Start button
- if ((useCheck || GOKZ_GetCoreOption(client, Option_TimerButtonZoneType) == TimerButtonZoneType_BothZones)
- && GetHasVirtualStartButton(client) && InRangeOfVirtualStart(client) && CanReachVirtualStart(client))
- {
- if (TimerStart(client, virtualStartCourse[client], .playSound = false))
- {
- startedTimerLastTick[client] = true;
- OnVirtualStartButtonPress_Teleports(client);
- }
- }
- else if (startedTimerLastTick[client])
- {
- // Without that check you get two sounds when pressing the natural timer button
- if (!onlyNaturalButtonPressed[client])
- {
- PlayTimerStartSound(client);
- }
- onlyNaturalButtonPressed[client] = false;
- startedTimerLastTick[client] = false;
- }
-
- // End button
- if ((useCheck || GOKZ_GetCoreOption(client, Option_TimerButtonZoneType) != TimerButtonZoneType_BothButtons)
- && GetHasVirtualEndButton(client) && InRangeOfVirtualEnd(client) && CanReachVirtualEnd(client))
- {
- if (!wasInEndZone[client])
- {
- TimerEnd(client, virtualEndCourse[client]);
- hasEndedTimerSincePressingUse[client] = true; // False end counts as well
- wasInEndZone[client] = true;
- }
- }
- else
- {
- wasInEndZone[client] = false;
- }
-}
-
-static bool PassesUseCheck(int client)
-{
- if (GetGameTime() - lastUsePressTime[client] < GOKZ_VIRTUAL_BUTTON_USE_DETECTION_TIME + EPSILON
- && !hasEndedTimerSincePressingUse[client]
- && !hasTeleportedSincePressingUse[client])
- {
- return true;
- }
-
- return false;
-}
-
-bool InRangeOfVirtualStart(int client)
-{
- return InRangeOfButton(client, virtualStartOrigin[client]);
-}
-
-static bool InRangeOfVirtualEnd(int client)
-{
- return InRangeOfButton(client, virtualEndOrigin[client]);
-}
-
-static bool InRangeOfButton(int client, const float buttonOrigin[3])
-{
- float origin[3];
- Movement_GetOrigin(client, origin);
- float distanceToButton = GetVectorDistance(origin, buttonOrigin);
- return distanceToButton <= gF_ModeVirtualButtonRanges[GOKZ_GetCoreOption(client, Option_Mode)];
-}
-
-bool CanReachVirtualStart(int client)
-{
- return CanReachButton(client, virtualStartOrigin[client]);
-}
-
-static bool CanReachVirtualEnd(int client)
-{
- return CanReachButton(client, virtualEndOrigin[client]);
-}
-
-static bool CanReachButton(int client, const float buttonOrigin[3])
-{
- float origin[3];
- Movement_GetOrigin(client, origin);
- Handle trace = TR_TraceRayFilterEx(origin, buttonOrigin, MASK_PLAYERSOLID, RayType_EndPoint, TraceEntityFilterPlayers);
- bool didHit = TR_DidHit(trace);
- delete trace;
- return !didHit;
-}
-
-
-
-// ===== [ INDICATOR ] =====
-
-static void UpdateIndicators(int client, int cmdnum)
-{
- if (cmdnum % 128 != 0 || !IsPlayerAlive(client)
- || GOKZ_GetCoreOption(client, Option_VirtualButtonIndicators) == VirtualButtonIndicators_Disabled)
- {
- return;
- }
-
- if (hasVirtualStartButton[client])
- {
- DrawIndicator(client, virtualStartOrigin[client], { 0, 255, 0, 255 } );
- }
-
- if (hasVirtualEndButton[client])
- {
- DrawIndicator(client, virtualEndOrigin[client], { 255, 0, 0, 255 } );
- }
-}
-
-static void DrawIndicator(int client, const float origin[3], const int colour[4])
-{
- float radius = gF_ModeVirtualButtonRanges[GOKZ_GetCoreOption(client, Option_Mode)];
- if (radius <= EPSILON) // Don't draw circle of radius 0
- {
- return;
- }
-
- float x, y, start[3], end[3];
-
- // Create the start position for the first part of the beam
- start[0] = origin[0] + radius;
- start[1] = origin[1];
- start[2] = origin[2];
-
- for (int i = 1; i <= 31; i++) // Circle is broken into 31 segments
- {
- float angle = 2 * PI / 31 * i;
- x = radius * Cosine(angle);
- y = radius * Sine(angle);
-
- end[0] = origin[0] + x;
- end[1] = origin[1] + y;
- end[2] = origin[2];
-
- TE_SetupBeamPoints(start, end, beamSprite, haloSprite, 0, 0, 0.97, 0.2, 0.2, 0, 0.0, colour, 0);
- TE_SendToClient(client);
-
- start[0] = end[0];
- start[1] = end[1];
- start[2] = end[2];
- }
-}