diff options
Diffstat (limited to 'sourcemod/scripting/include/gokz.inc')
| -rw-r--r-- | sourcemod/scripting/include/gokz.inc | 1097 |
1 files changed, 0 insertions, 1097 deletions
diff --git a/sourcemod/scripting/include/gokz.inc b/sourcemod/scripting/include/gokz.inc deleted file mode 100644 index edbd896..0000000 --- a/sourcemod/scripting/include/gokz.inc +++ /dev/null @@ -1,1097 +0,0 @@ -/* - GOKZ General Include - - Website: https://bitbucket.org/kztimerglobalteam/gokz -*/ - -#if defined _gokz_included_ -#endinput -#endif -#define _gokz_included_ -#include <cstrike> -#include <movement> - -#include <gokz/version> - - - -// =====[ ENUMS ]===== - -enum ObsMode -{ - ObsMode_None = 0, // Not in spectator mode - ObsMode_DeathCam, // Special mode for death cam animation - ObsMode_FreezeCam, // Zooms to a target, and freeze-frames on them - ObsMode_Fixed, // View from a fixed camera position - ObsMode_InEye, // Follow a player in first person view - ObsMode_Chase, // Follow a player in third person view - ObsMode_Roaming // Free roaming -}; - - - -// =====[ CONSTANTS ]===== - -#define GOKZ_SOURCE_URL "https://github.com/KZGlobalTeam/gokz" -#define GOKZ_UPDATER_BASE_URL "http://updater.gokz.org/v2/" -#define GOKZ_COLLISION_GROUP_STANDARD 2 -#define GOKZ_COLLISION_GROUP_NOTRIGGER 1 -#define GOKZ_TP_FREEZE_TICKS 5 -#define EPSILON 0.000001 -#define PI 3.14159265359 -#define SPEED_NORMAL 250.0 -#define SPEED_NO_WEAPON 260.0 -#define FLOAT_MAX view_as<float>(0x7F7FFFFF) -#define SF_BUTTON_USE_ACTIVATES 1024 -#define IGNORE_JUMP_TIME 0.2 -stock float PLAYER_MINS[3] = {-16.0, -16.0, 0.0}; -stock float PLAYER_MAXS[3] = {16.0, 16.0, 72.0}; -stock float PLAYER_MAXS_DUCKED[3] = {16.0, 16.0, 54.0}; - - - -// =====[ STOCKS ]===== - -/** - * Represents a time float as a string e.g. 01:23.45. - * - * @param time Time in seconds. - * @param precise Whether to include fractional seconds. - * @return String representation of time. - */ -stock char[] GOKZ_FormatTime(float time, bool precise = true) -{ - char formattedTime[12]; - - int roundedTime = RoundFloat(time * 100); // Time rounded to number of centiseconds - - int centiseconds = roundedTime % 100; - roundedTime = (roundedTime - centiseconds) / 100; - int seconds = roundedTime % 60; - roundedTime = (roundedTime - seconds) / 60; - int minutes = roundedTime % 60; - roundedTime = (roundedTime - minutes) / 60; - int hours = roundedTime; - - if (hours == 0) - { - if (precise) - { - FormatEx(formattedTime, sizeof(formattedTime), "%02d:%02d.%02d", minutes, seconds, centiseconds); - } - else - { - FormatEx(formattedTime, sizeof(formattedTime), "%d:%02d", minutes, seconds); - } - } - else - { - if (precise) - { - FormatEx(formattedTime, sizeof(formattedTime), "%d:%02d:%02d.%02d", hours, minutes, seconds, centiseconds); - } - else - { - FormatEx(formattedTime, sizeof(formattedTime), "%d:%02d:%02d", hours, minutes, seconds); - } - } - return formattedTime; -} - -/** - * Checks if the value is a valid client entity index, if they are in-game and not GOTV. - * - * @param client Client index. - * @return Whether client is valid. - */ -stock bool IsValidClient(int client) -{ - return client >= 1 && client <= MaxClients && IsClientInGame(client) && !IsClientSourceTV(client); -} - -/** - * Returns the greater of two float values. - * - * @param value1 First value. - * @param value2 Second value. - * @return Greatest value. - */ -stock float FloatMax(float value1, float value2) -{ - if (value1 >= value2) - { - return value1; - } - return value2; -} - -/** - * Returns the lesser of two float values. - * - * @param value1 First value. - * @param value2 Second value. - * @return Lesser value. - */ -stock float FloatMin(float value1, float value2) -{ - if (value1 <= value2) - { - return value1; - } - return value2; -} - -/** - * Clamp a float value between an upper and lower bound. - * - * @param value Preferred value. - * @param min Minimum value. - * @param max Maximum value. - * @return The closest value to the preferred value. - */ -stock float FloatClamp(float value, float min, float max) -{ - if (value >= max) - { - return max; - } - if (value <= min) - { - return min; - } - return value; -} - - -/** - * Returns the greater of two int values. - * - * @param value1 First value. - * @param value2 Second value. - * @return Greatest value. - */ -stock int IntMax(int value1, int value2) -{ - if (value1 >= value2) - { - return value1; - } - return value2; -} - -/** - * Returns the lesser of two int values. - * - * @param value1 First value. - * @param value2 Second value. - * @return Lesser value. - */ -stock int IntMin(int value1, int value2) -{ - if (value1 <= value2) - { - return value1; - } - return value2; -} - -/** - * Rounds a float to the nearest specified power of 10. - * - * @param value Value to round. - * @param power Power of 10 to round to. - * @return Rounded value. - */ -stock float RoundToPowerOfTen(float value, int power) -{ - float pow = Pow(10.0, float(power)); - return RoundFloat(value / pow) * pow; -} - -/** - * Sets all characters in a string to lower case. - * - * @param input Input string. - * @param output Output buffer. - * @param size Maximum size of output. - */ -stock void String_ToLower(const char[] input, char[] output, int size) -{ - size--; - int i = 0; - while (input[i] != '\0' && i < size) - { - output[i] = CharToLower(input[i]); - i++; - } - output[i] = '\0'; -} - -/** - * Gets the client's observer mode. - * - * @param client Client index. - * @return Current observer mode. - */ -stock ObsMode GetObserverMode(int client) -{ - return view_as<ObsMode>(GetEntProp(client, Prop_Send, "m_iObserverMode")); -} - -/** - * Gets the player a client is spectating. - * - * @param client Client index. - * @return Client index of target, or -1 if not spectating anyone. - */ -stock int GetObserverTarget(int client) -{ - if (!IsValidClient(client)) - { - return -1; - } - ObsMode mode = GetObserverMode(client); - if (mode == ObsMode_InEye || mode == ObsMode_Chase) - { - return GetEntPropEnt(client, Prop_Send, "m_hObserverTarget"); - } - return -1; -} - -/** - * Emits a sound to other players that are spectating the client. - * - * @param client Client being spectated. - * @param sound Sound to play. - */ -stock void EmitSoundToClientSpectators(int client, const char[] sound) -{ - for (int i = 1; i <= MaxClients; i++) - { - if (IsValidClient(i) && GetObserverTarget(i) == client) - { - EmitSoundToClient(i, sound); - } - } -} - -/** - * Calculates the lowest angle from angle A to angle B. - * Input and result angles are between -180 and 180. - * - * @param angleA Angle A. - * @param angleB Angle B. - * @return Delta angle. - */ -stock float CalcDeltaAngle(float angleA, float angleB) -{ - float difference = angleB - angleA; - - if (difference > 180.0) - { - difference = difference - 360.0; - } - else if (difference <= -180.0) - { - difference = difference + 360.0; - } - - return difference; -} - -/** - * Strips all color control characters in a string. - * The Output buffer can be the same as the input buffer. - * Original code by Psychonic, thanks. - * Source: smlib - * - * @param input Input String. - * @param output Output String. - * @param size Max Size of the Output string - */ -stock void Color_StripFromChatText(const char[] input, char[] output, int size) -{ - int x = 0; - for (int i = 0; input[i] != '\0'; i++) { - - if (x + 1 == size) - { - break; - } - - int character = input[i]; - - if (character > 0x08) - { - output[x++] = character; - } - } - - output[x] = '\0'; -} - -/** - * Returns an integer as a string. - * - * @param num Integer to stringify. - * @return Integer as a string. - */ -stock char[] IntToStringEx(int num) -{ - char string[12]; - IntToString(num, string, sizeof(string)); - return string; -} - -/** - * Returns a float as a string. - * - * @param num Float to stringify. - * @return Float as a string. - */ -stock char[] FloatToStringEx(float num) -{ - char string[32]; - FloatToString(num, string, sizeof(string)); - return string; -} - -/** - * Increment an index, looping back to 0 if the max value is reached. - * - * @param index Current index. - * @param buffer Max value of index. - * @return Current index incremented, or 0 if max value is reached. - */ -stock int NextIndex(int index, int max) -{ - index++; - if (index == max) - { - return 0; - } - return index; -} - -/** - * Reorders an array with current index at the front, and previous - * values after, including looping back to the end after reaching - * the start of the array. - * - * @param input Array to reorder. - * @param inputSize Size of input array. - * @param buffer Output buffer. - * @param bufferSize Size of buffer. - * @param index Index of current/most recent value of input array. - */ -stock void SortByRecent(const int[] input, int inputSize, int[] buffer, int bufferSize, int index) -{ - int reorderedIndex = 0; - for (int i = index; reorderedIndex < bufferSize && i >= 0; i--) - { - buffer[reorderedIndex] = input[i]; - reorderedIndex++; - } - for (int i = inputSize - 1; reorderedIndex < bufferSize && i > index; i--) - { - buffer[reorderedIndex] = input[i]; - reorderedIndex++; - } -} - -/** - * Returns the Steam account ID for a given SteamID2. - * Checks for invalid input are not very extensive. - * - * @param steamID2 SteamID2 to convert. - * @return Steam account ID, or -1 if invalid. - */ -stock int Steam2ToSteamAccountID(const char[] steamID2) -{ - char pieces[3][16]; - if (ExplodeString(steamID2, ":", pieces, sizeof(pieces), sizeof(pieces[])) != 3) - { - return -1; - } - - int IDNumberPart1 = StringToInt(pieces[1]); - int IDNumberPart2 = StringToInt(pieces[2]); - if (pieces[1][0] != '0' && IDNumberPart1 == 0 || IDNumberPart1 != 0 && IDNumberPart1 != 1 || IDNumberPart2 <= 0) - { - return -1; - } - - return IDNumberPart1 + (IDNumberPart2 << 1); -} - -/** - * Teleports a player and removes their velocity and base velocity - * immediately and also every tick for the next 5 ticks. Automatically - * makes the player crouch if there is a ceiling above them. - * - * @param client Client index. - * @param origin Origin to teleport to. - * @param angles Eye angles to set. - */ -stock void TeleportPlayer(int client, const float origin[3], const float angles[3], bool setAngles = true, bool holdStill = true) -{ - // Clear the player's parent before teleporting to fix being - // teleported into seemingly random places if the player has a parent. - AcceptEntityInput(client, "ClearParent"); - - Movement_SetOrigin(client, origin); - Movement_SetVelocity(client, view_as<float>( { 0.0, 0.0, 0.0 } )); - Movement_SetBaseVelocity(client, view_as<float>( { 0.0, 0.0, 0.0 } )); - if (setAngles) - { - // NOTE: changing angles with TeleportEntity can fail due to packet loss!!! - // (Movement_SetEyeAngles is a thin wrapper of TeleportEntity) - Movement_SetEyeAngles(client, angles); - } - // Duck the player if there is something blocking them from above - Handle trace = TR_TraceHullFilterEx(origin, - origin, - view_as<float>( { -16.0, -16.0, 0.0 } ), // Standing players are 32 x 32 x 72 - view_as<float>( { 16.0, 16.0, 72.0 } ), - MASK_PLAYERSOLID, - TraceEntityFilterPlayers, - client); - bool ducked = TR_DidHit(trace); - - if (holdStill) - { - // Prevent noclip exploit - SetEntProp(client, Prop_Send, "m_CollisionGroup", GOKZ_COLLISION_GROUP_STANDARD); - - // Intelligently hold player still to prevent booster and trigger exploits - StartHoldStill(client, ducked); - } - else if (ducked) - { - ForcePlayerDuck(client); - } - - delete trace; -} - -static void StartHoldStill(int client, bool ducked) -{ - DataPack data = new DataPack(); - data.WriteCell(GetClientUserId(client)); - data.WriteCell(0); // tick counter - data.WriteCell(GOKZ_TP_FREEZE_TICKS); // number of ticks to hold still - data.WriteCell(ducked); - ContinueHoldStill(data); -} - -public void ContinueHoldStill(DataPack data) -{ - data.Reset(); - int client = GetClientOfUserId(data.ReadCell()); - int ticks = data.ReadCell(); - int tickCount = data.ReadCell(); - bool ducked = data.ReadCell(); - delete data; - - if (!IsValidClient(client)) - { - return; - } - - if (ticks < tickCount) - { - Movement_SetVelocity(client, view_as<float>( { 0.0, 0.0, 0.0 } )); - Movement_SetBaseVelocity(client, view_as<float>( { 0.0, 0.0, 0.0 } )); - Movement_SetGravity(client, 1.0); - - // Don't drop the player off of ladders. - // The game will automatically change the movetype back to MOVETYPE_WALK if it can't find a ladder. - // Don't change the movetype if it's currently MOVETYPE_NONE, as that means the player is paused. - if (Movement_GetMovetype(client) != MOVETYPE_NONE) - { - Movement_SetMovetype(client, MOVETYPE_LADDER); - } - - // Prevent noclip exploit - SetEntProp(client, Prop_Send, "m_CollisionGroup", GOKZ_COLLISION_GROUP_STANDARD); - - // Force duck on player and make sure that the player can't trigger triggers above them. - // they can still trigger triggers even when we force ducking. - if (ducked) - { - ForcePlayerDuck(client); - - if (ticks < tickCount - 1) - { - // Don't trigger triggers - SetEntProp(client, Prop_Send, "m_CollisionGroup", GOKZ_COLLISION_GROUP_NOTRIGGER); - } - else - { - // Let the player trigger triggers on the last tick - SetEntProp(client, Prop_Send, "m_CollisionGroup", GOKZ_COLLISION_GROUP_STANDARD); - } - } - - ++ticks; - data = new DataPack(); - data.WriteCell(GetClientUserId(client)); - data.WriteCell(ticks); - data.WriteCell(tickCount); - data.WriteCell(ducked); - RequestFrame(ContinueHoldStill, data); - } -} - -/** - * Forces the player to instantly duck. - * - * @param client Client index. - */ -stock void ForcePlayerDuck(int client) -{ - // these are both necessary, because on their own the player will sometimes still be in a state that isn't fully ducked. - SetEntPropFloat(client, Prop_Send, "m_flDuckAmount", 1.0, 0); - SetEntProp(client, Prop_Send, "m_bDucking", false); - SetEntProp(client, Prop_Send, "m_bDucked", true); -} - -/** - * Returns whether the player is stuck e.g. in a wall after noclipping. - * - * @param client Client index. - * @return Whether player is stuck. - */ -stock bool IsPlayerStuck(int client) -{ - float vecMin[3], vecMax[3], vecOrigin[3]; - - GetClientMins(client, vecMin); - GetClientMaxs(client, vecMax); - GetClientAbsOrigin(client, vecOrigin); - - TR_TraceHullFilter(vecOrigin, vecOrigin, vecMin, vecMax, MASK_PLAYERSOLID, TraceEntityFilterPlayers); - return TR_DidHit(); // head in wall ? -} - -/** - * Retrieves the absolute origin of an entity. - * - * @param entity Index of the entity. - * @param result Entity's origin if successful. - * @return Returns true if successful. - */ -stock bool GetEntityAbsOrigin(int entity, float result[3]) -{ - if (!IsValidEntity(entity)) - { - return false; - } - - if (!HasEntProp(entity, Prop_Data, "m_vecAbsOrigin")) - { - return false; - } - - GetEntPropVector(entity, Prop_Data, "m_vecAbsOrigin", result); - return true; -} - -/** - * Retrieves the name of an entity. - * - * @param entity Index of the entity. - * @param buffer Buffer to store the name. - * @param maxlength Maximum length of the buffer. - * @return Number of non-null bytes written. - */ -stock int GetEntityName(int entity, char[] buffer, int maxlength) -{ - return GetEntPropString(entity, Prop_Data, "m_iName", buffer, maxlength); -} - -/** - * Finds an entity by name or by name and classname. - * Taken from smlib https://github.com/bcserv/smlib - * This can take anywhere from ~0.2% to ~11% of frametime (i5-7600k) in the worst case scenario where - * every entity which has a name (4096 of them) is iterated over. Your mileage may vary. - * - * @param name Name of the entity to find. - * @param className Optional classname to match along with name. - * @param ignorePlayers Ignore player entities. - * @return Entity index if successful, INVALID_ENT_REFERENCE if not. - */ -stock int GOKZFindEntityByName(const char[] name, const char[] className = "", bool ignorePlayers = false) -{ - int result = INVALID_ENT_REFERENCE; - if (className[0] == '\0') - { - // HACK: Double the limit to get non-networked entities too. - // https://developer.valvesoftware.com/wiki/Entity_limit - int realMaxEntities = GetMaxEntities() * 2; - int startEntity = 1; - if (ignorePlayers) - { - startEntity = MaxClients + 1; - } - for (int entity = startEntity; entity < realMaxEntities; entity++) - { - if (!IsValidEntity(entity)) - { - continue; - } - - char entName[65]; - GetEntityName(entity, entName, sizeof(entName)); - if (StrEqual(entName, name)) - { - result = entity; - break; - } - } - } - else - { - int entity = INVALID_ENT_REFERENCE; - while ((entity = FindEntityByClassname(entity, className)) != INVALID_ENT_REFERENCE) - { - char entName[65]; - GetEntityName(entity, entName, sizeof(entName)); - if (StrEqual(entName, name)) - { - result = entity; - break; - } - } - } - return result; -} - -/** - * Gets the current map's display name in lower case. - * - * @param buffer Buffer to store the map name. - * @param maxlength Maximum length of buffer. - */ -stock void GetCurrentMapDisplayName(char[] buffer, int maxlength) -{ - char map[PLATFORM_MAX_PATH]; - GetCurrentMap(map, sizeof(map)); - GetMapDisplayName(map, map, sizeof(map)); - String_ToLower(map, buffer, maxlength); -} - -/** - * Gets the current map's file size. - */ -stock int GetCurrentMapFileSize() -{ - char mapBuffer[PLATFORM_MAX_PATH]; - GetCurrentMap(mapBuffer, sizeof(mapBuffer)); - Format(mapBuffer, sizeof(mapBuffer), "maps/%s.bsp", mapBuffer); - return FileSize(mapBuffer); -} - -/** - * Copies the elements of a source vector to a destination vector. - * - * @param src Source vector. - * @param dest Destination vector. - */ -stock void CopyVector(const any src[3], any dest[3]) -{ - dest[0] = src[0]; - dest[1] = src[1]; - dest[2] = src[2]; -} - -/** - * Returns whether the player is spectating. - * - * @param client Client index. - */ -stock bool IsSpectating(int client) -{ - int team = GetClientTeam(client); - return team == CS_TEAM_SPECTATOR || team == CS_TEAM_NONE; -} - -/** - * Rotate a vector on an axis. - * - * @param vec Vector to rotate. - * @param axis Axis to rotate around. - * @param theta Angle in radians. - * @param result Rotated vector. - */ -stock void RotateVectorAxis(float vec[3], float axis[3], float theta, float result[3]) -{ - float cosTheta = Cosine(theta); - float sinTheta = Sine(theta); - - float axisVecCross[3]; - GetVectorCrossProduct(axis, vec, axisVecCross); - - for (int i = 0; i < 3; i++) - { - result[i] = (vec[i] * cosTheta) + (axisVecCross[i] * sinTheta) + (axis[i] * GetVectorDotProduct(axis, vec)) * (1.0 - cosTheta); - } -} - -/** - * Rotate a vector by pitch and yaw. - * - * @param vec Vector to rotate. - * @param pitch Pitch angle (in degrees). - * @param yaw Yaw angle (in degrees). - * @param result Rotated vector. - */ -stock void RotateVectorPitchYaw(float vec[3], float pitch, float yaw, float result[3]) -{ - if (pitch != 0.0) - { - RotateVectorAxis(vec, view_as<float>({0.0, 1.0, 0.0}), DegToRad(pitch), result); - } - if (yaw != 0.0) - { - RotateVectorAxis(result, view_as<float>({0.0, 0.0, 1.0}), DegToRad(yaw), result); - } -} - -/** - * Attempts to return a valid spawn location. - * - * @param origin Spawn origin if found. - * @param angles Spawn angles if found. - * @return Whether a valid spawn point is found. - */ -stock bool GetValidSpawn(float origin[3], float angles[3]) -{ - // Return true if the spawn found is truly valid (not in the ground or out of bounds) - bool foundValidSpawn; - bool searchCT; - float spawnOrigin[3]; - float spawnAngles[3]; - int spawnEntity = -1; - while (!foundValidSpawn) - { - if (searchCT) - { - spawnEntity = FindEntityByClassname(spawnEntity, "info_player_counterterrorist"); - } - else - { - spawnEntity = FindEntityByClassname(spawnEntity, "info_player_terrorist"); - } - - if (spawnEntity != -1) - { - GetEntPropVector(spawnEntity, Prop_Data, "m_vecOrigin", spawnOrigin); - GetEntPropVector(spawnEntity, Prop_Data, "m_angRotation", spawnAngles); - if (IsSpawnValid(spawnOrigin)) - { - origin = spawnOrigin; - angles = spawnAngles; - foundValidSpawn = true; - } - } - else if (!searchCT) - { - searchCT = true; - } - else - { - break; - } - } - return foundValidSpawn; -} - -/** - * Check whether a position is a valid spawn location. - * A spawn location is considered valid if it is in bounds and not stuck inside the ground. - * - * @param origin Origin vector. - * @return Whether the origin is a valid spawn location. - */ -stock bool IsSpawnValid(float origin[3]) -{ - Handle trace = TR_TraceHullFilterEx(origin, origin, PLAYER_MINS, PLAYER_MAXS, MASK_PLAYERSOLID, TraceEntityFilterPlayers); - if (!TR_StartSolid(trace) && !TR_AllSolid(trace) && TR_GetFraction(trace) == 1.0) - { - delete trace; - return true; - } - delete trace; - return false; -} - -/** - * Get an entity's origin, angles, its bounding box's center and the distance from the center to its bounding box's edges. - * - * @param entity Index of the entity. - * @param origin Entity's origin. - * @param center Center of the entity's bounding box. - * @param angles Entity's angles. - * @param distFromCenter The distance between the center of the entity's bounding box and its edges. - */ -stock void GetEntityPositions(int entity, float origin[3], float center[3], float angles[3], float distFromCenter[3]) -{ - int ent = entity; - float maxs[3], mins[3]; - GetEntPropVector(ent, Prop_Send, "m_vecOrigin", origin); - // Take parent entities into account. - while (GetEntPropEnt(ent, Prop_Send, "moveparent") != -1) - { - ent = GetEntPropEnt(ent, Prop_Send, "moveparent"); - float tempOrigin[3]; - GetEntPropVector(ent, Prop_Send, "m_vecOrigin", tempOrigin); - for (int i = 0; i < 3; i++) - { - origin[i] += tempOrigin[i]; - } - } - - GetEntPropVector(ent, Prop_Data, "m_angRotation", angles); - - GetEntPropVector(ent, Prop_Send, "m_vecMaxs", maxs); - GetEntPropVector(ent, Prop_Send, "m_vecMins", mins); - for (int i = 0; i < 3; i++) - { - center[i] = origin[i] + (maxs[i] + mins[i]) / 2; - distFromCenter[i] = (maxs[i] - mins[i]) / 2; - } -} - -/** - * Find a valid position around a timer. - * - * @param entity Index of the timer entity. - * @param originDest Result origin if a valid position is found. - * @param anglesDest Result angles if a valid position is found. - * @return Whether a valid position is found. - */ -stock bool FindValidPositionAroundTimerEntity(int entity, float originDest[3], float anglesDest[3], bool isButton) -{ - float origin[3], center[3], angles[3], distFromCenter[3]; - GetEntityPositions(entity, origin, center, angles, distFromCenter); - float extraOffset[3]; - if (isButton) // Test several positions within button press range. - { - extraOffset[0] = 32.0; - extraOffset[1] = 32.0; - extraOffset[2] = 32.0; - } - else // Test positions at the inner surface of the zone. - { - extraOffset[0] = -(PLAYER_MAXS[0] - PLAYER_MINS[0]) - 1.03125; - extraOffset[1] = -(PLAYER_MAXS[1] - PLAYER_MINS[1]) - 1.03125; - extraOffset[2] = -(PLAYER_MAXS[2] - PLAYER_MINS[2]) - 1.03125; - } - if (FindValidPositionAroundCenter(center, distFromCenter, extraOffset, originDest, anglesDest)) - { - return true; - } - // Test the positions right next to the timer button/zones if the tests above fail. - // This can fail when the timer has a cover brush over it. - extraOffset[0] = 0.03125; - extraOffset[1] = 0.03125; - extraOffset[2] = 0.03125; - return FindValidPositionAroundCenter(center, distFromCenter, extraOffset, originDest, anglesDest); -} - -static bool FindValidPositionAroundCenter(float center[3], float distFromCenter[3], float extraOffset[3], float originDest[3], float anglesDest[3]) -{ - float testOrigin[3]; - int x, y; - - for (int i = 0; i < 3; i++) - { - // The search starts from the center then outwards to opposite directions. - x = i == 2 ? -1 : i; - for (int j = 0; j < 3; j++) - { - y = j == 2 ? -1 : j; - for (int z = -1; z <= 1; z++) - { - testOrigin = center; - testOrigin[0] = testOrigin[0] + (distFromCenter[0] + extraOffset[0]) * x + (PLAYER_MAXS[0] - PLAYER_MINS[0]) * x * 0.5; - testOrigin[1] = testOrigin[1] + (distFromCenter[1] + extraOffset[1]) * y + (PLAYER_MAXS[1] - PLAYER_MINS[1]) * y * 0.5; - testOrigin[2] = testOrigin[2] + (distFromCenter[2] + extraOffset[2]) * z + (PLAYER_MAXS[2] - PLAYER_MINS[2]) * z; - - // Check if there's a line of sight towards the zone as well. - if (IsSpawnValid(testOrigin) && CanSeeBox(testOrigin, center, distFromCenter)) - { - originDest = testOrigin; - // Always look towards the center. - float offsetVector[3]; - offsetVector[0] = -(distFromCenter[0] + extraOffset[0]) * x; - offsetVector[1] = -(distFromCenter[1] + extraOffset[1]) * y; - offsetVector[2] = -(distFromCenter[2] + extraOffset[2]) * z; - GetVectorAngles(offsetVector, anglesDest); - anglesDest[2] = 0.0; // Roll should always be 0.0 - return true; - } - } - } - } - return false; -} - -static bool CanSeeBox(float origin[3], float center[3], float distFromCenter[3]) -{ - float traceOrigin[3], traceDest[3], mins[3], maxs[3]; - - CopyVector(origin, traceOrigin); - - - SubtractVectors(center, distFromCenter, mins); - AddVectors(center, distFromCenter, maxs); - - for (int i = 0; i < 3; i++) - { - mins[i] += 0.03125; - maxs[i] -= 0.03125; - traceDest[i] = FloatClamp(traceOrigin[i], mins[i], maxs[i]); - } - int mask = (MASK_NPCSOLID_BRUSHONLY | MASK_OPAQUE_AND_NPCS) & ~CONTENTS_OPAQUE; - Handle trace = TR_TraceRayFilterEx(traceOrigin, traceDest, mask, RayType_EndPoint, TraceEntityFilterPlayers); - if (TR_DidHit(trace)) - { - float end[3]; - TR_GetEndPosition(end, trace); - for (int i = 0; i < 3; i++) - { - if (end[i] != traceDest[i]) - { - delete trace; - return false; - } - } - } - delete trace; - return true; -} - -/** - * Gets entity index from the address to an entity. - * - * @param pEntity Entity address. - * @return Entity index. - * @error Couldn't find offset for m_angRotation, m_vecViewOffset, couldn't confirm offset of m_RefEHandle. - */ -stock int GOKZGetEntityFromAddress(Address pEntity) -{ - static int offs_RefEHandle; - if (offs_RefEHandle) - { - return EntRefToEntIndex(LoadFromAddress(pEntity + view_as<Address>(offs_RefEHandle), NumberType_Int32) | (1 << 31)); - } - - // if we don't have it already, attempt to lookup offset based on SDK information - // CWorld is derived from CBaseEntity so it should have both offsets - int offs_angRotation = FindDataMapInfo(0, "m_angRotation"), offs_vecViewOffset = FindDataMapInfo(0, "m_vecViewOffset"); - if (offs_angRotation == -1) - { - SetFailState("Could not find offset for ((CBaseEntity) CWorld)::m_angRotation"); - } - else if (offs_vecViewOffset == -1) - { - SetFailState("Could not find offset for ((CBaseEntity) CWorld)::m_vecViewOffset"); - } - else if ((offs_angRotation + 0x0C) != (offs_vecViewOffset - 0x04)) - { - char game[32]; - GetGameFolderName(game, sizeof(game)); - SetFailState("Could not confirm offset of CBaseEntity::m_RefEHandle (incorrect assumption for game '%s'?)", game); - } - - // offset seems right, cache it for the next call - offs_RefEHandle = offs_angRotation + 0x0C; - return GOKZGetEntityFromAddress(pEntity); -} - -/** - * Gets client index from CGameMovement class. - * - * @param addr Address of CGameMovement class. - * @param offsetCGameMovement_player Offset of CGameMovement::player. - * @return Client index. - * @error Couldn't find offset for m_angRotation, m_vecViewOffset, couldn't confirm offset of m_RefEHandle. - */ -stock int GOKZGetClientFromGameMovementAddress(Address addr, int offsetCGameMovement_player) -{ - Address playerAddr = view_as<Address>(LoadFromAddress(view_as<Address>(view_as<int>(addr) + offsetCGameMovement_player), NumberType_Int32)); - return GOKZGetEntityFromAddress(playerAddr); -} - -/** - * Gets the nearest point in the oriented bounding box of an entity to a point. - * - * @param entity Entity index. - * @param origin Point's origin. - * @param result Result point. - */ -stock void CalcNearestPoint(int entity, float origin[3], float result[3]) -{ - float entOrigin[3], entMins[3], entMaxs[3], trueMins[3], trueMaxs[3]; - GetEntPropVector(entity, Prop_Send, "m_vecOrigin", entOrigin); - GetEntPropVector(entity, Prop_Send, "m_vecMaxs", entMaxs); - GetEntPropVector(entity, Prop_Send, "m_vecMins", entMins); - - AddVectors(entOrigin, entMins, trueMins); - AddVectors(entOrigin, entMaxs, trueMaxs); - - for (int i = 0; i < 3; i++) - { - result[i] = FloatClamp(origin[i], trueMins[i], trueMaxs[i]); - } -} - -/** - * Get the shortest distance from P to the (infinite) line through vLineA and vLineB. - * - * @param P Point's origin. - * @param vLineA Origin of the first point of the line. - * @param vLineB Origin of the first point of the line. - * @return The shortest distance from the point to the line. - */ -stock float CalcDistanceToLine(float P[3], float vLineA[3], float vLineB[3]) -{ - float vClosest[3]; - float vDir[3]; - float t; - float delta[3]; - SubtractVectors(vLineB, vLineA, vDir); - float div = GetVectorDotProduct(vDir, vDir); - if (div < EPSILON) - { - t = 0.0; - } - else - { - t = (GetVectorDotProduct(vDir, P) - GetVectorDotProduct(vDir, vLineA)) / div; - } - for (int i = 0; i < 3; i++) - { - vClosest[i] = vLineA[i] + vDir[i]*t; - } - SubtractVectors(P, vClosest, delta); - return GetVectorLength(delta); -} - -/** - * Gets the ideal amount of time the text should be held for HUD messages. - * - * The message buffer is only 16 slots long, and it is shared between 6 channels maximum. - * Assuming a message is sent every game frame, each channel used should be only taking around 2.5 slots on average. - * This also assumes all channels are used equally (so no other plugin taking all the channel buffer for itself). - * We want to use as much of the message buffer as possible to take into account latency variances. - * - * @param interval HUD message update interval, in tick intervals. - * @return How long the text should be held for. - */ -stock float GetTextHoldTime(int interval) -{ - return 3 * interval * GetTickInterval(); -} |
