Files
2025-04-15 22:27:20 -04:00

393 lines
10 KiB
SourcePawn

#pragma semicolon 1
#include <sourcemod>
#if defined INFO_INCLUDES
#include "../info/constants.sp"
#include "../info/enums.sp"
#include "../info/variables.sp"
#endif
/**
* Checks if an entity is a corner.
*
* @param iCorner The corner.
* @return True if valid, false otherwise.
*/
stock bool Corner_IsValid(int iCorner) {
if (!IsValidEntity(iCorner)) {
return false;
}
char sBuffer[64];
GetEntityClassname(iCorner, sBuffer, sizeof(sBuffer));
if (StrEqual(sBuffer, "trigger_multiple")) {
GetEntPropString(iCorner, Prop_Data, "m_iName", sBuffer, sizeof(sBuffer));
return (StrContains(sBuffer, "corner_") != -1);
}
return false;
}
/**
* Finds a corner by name.
*
* @param sName The corners name.
* @return The corners entity index, or -1 on failure.
*/
stock int Corner_FindByName(const char[] sName) {
int iCorner = -1;
char sCornerName[64];
while ((iCorner = FindEntityByClassname(iCorner, "trigger_multiple")) != -1) {
Corner_GetName(iCorner, sCornerName, sizeof(sCornerName));
if (StrEqual(sCornerName, sName)) {
return iCorner;
}
}
return -1;
}
/**
* Finds a corner by it's next corners name.
*
* @param sName The next corners name.
* @return The corners entity index, or -1 on failure.
*/
stock int Corner_FindByNextName(const char[] sName) {
int iCorner = -1;
char sCornerName[64];
while ((iCorner = FindEntityByClassname(iCorner, "trigger_multiple")) != -1) {
Corner_GetNextName(iCorner, sCornerName, sizeof(sCornerName));
if (StrEqual(sCornerName, sName)) {
return iCorner;
}
}
return -1;
}
/**
* Gets a corners name.
*
* @param iCorner The corner.
* @param bValidate Validate the corner.
* @return The corner number, or -1 on failure.
*/
stock int Corner_GetNumber(int iCorner, bool bValidate = true) {
if (!bValidate) {
char sName[64];
Corner_GetName(iCorner, sName, sizeof(sName), false);
if (!StrEqual(sName, "corner_final")) {
char sNameParts[2][32];
ExplodeString(sName, "_", sNameParts, sizeof(sNameParts), sizeof(sNameParts[]));
return StringToInt(sNameParts[1]);
}
} else if (Corner_IsValid(iCorner)) {
char sName[64];
Corner_GetName(iCorner, sName, sizeof(sName), false);
if (!StrEqual(sName, "corner_final")) {
char sNameParts[2][32];
ExplodeString(sName, "_", sNameParts, sizeof(sNameParts), sizeof(sNameParts[]));
return StringToInt(sNameParts[1]);
}
}
return -1;
}
/**
* Gets a corners name.
*
* @param iCorner The corner.
* @param sBuffer The destination string buffer.
* @param iMaxLength The maximum length of the output string buffer.
* @param bValidate Validate the corner.
* @return True on success, false if corner was not found.
*/
stock bool Corner_GetName(int iCorner, char[] sBuffer, int iMaxLength, bool bValidate = true) {
if (!bValidate) {
GetEntPropString(iCorner, Prop_Data, "m_iName", sBuffer, iMaxLength);
return true;
} else if (Corner_IsValid(iCorner)) {
GetEntPropString(iCorner, Prop_Data, "m_iName", sBuffer, iMaxLength);
return true;
}
return false;
}
/**
* Gets a corners next corner name.
*
* @param iCorner The corner.
* @param sBuffer The destination string buffer.
* @param iMaxLength The maximum length of the output string buffer.
* @param bValidate Validate the corner.
* @return True on success, false if corner was not found.
*/
stock bool Corner_GetNextName(int iCorner, char[] sBuffer, int iMaxLength, bool bValidate = true) {
if (!bValidate) {
GetEntPropString(iCorner, Prop_Data, "m_iParent", sBuffer, iMaxLength);
return true;
} else if (Corner_IsValid(iCorner)) {
GetEntPropString(iCorner, Prop_Data, "m_iParent", sBuffer, iMaxLength);
return true;
}
return false;
}
/**
* Gets a corners location.
*
* @param iCorner The corner.
* @param fLocation The location vector.
* @param bValidate Validate the corner.
* @return True on success, false if corner was not found.
*/
stock bool Corner_GetLocation(int iCorner, float fLocation[3], bool bValidate = true) {
if (!bValidate) {
GetEntPropVector(iCorner, Prop_Data, "m_vecAbsOrigin", fLocation);
return true;
} else if (Corner_IsValid(iCorner)) {
GetEntPropVector(iCorner, Prop_Data, "m_vecAbsOrigin", fLocation);
return true;
}
return false;
}
/**
* Gets the angle between two corners.
*
* @param iCornerA The first corner.
* @param iCornerB The second corner.
* @param fAngles The angles vector.
* @param bValidate Validate the corner.
* @return True on success, false if corner was not found.
*/
stock bool Corner_GetAngles(int iCornerA, int iCornerB, float fAngles[3], bool bValidate = true) {
float fLocationCornerA[3], fLocationCornerB[3], fVector[3];
if (!bValidate) {
Corner_GetLocation(iCornerA, fLocationCornerA, false);
Corner_GetLocation(iCornerB, fLocationCornerB, false);
MakeVectorFromPoints(fLocationCornerA, fLocationCornerB, fVector);
GetVectorAngles(fVector, fAngles);
} else if (Corner_IsValid(iCornerA) && Corner_IsValid(iCornerB)) {
Corner_GetLocation(iCornerA, fLocationCornerA, false);
Corner_GetLocation(iCornerB, fLocationCornerB, false);
MakeVectorFromPoints(fLocationCornerA, fLocationCornerB, fVector);
GetVectorAngles(fVector, fAngles);
}
return false;
}
/**
* Gets the next corner.
*
* @param iCorner The current corner.
* @param sName The current corners name (optional).
* @return The next corners entity index, or -1 on failure.
*/
stock int Corner_GetNext(int iCorner = -1, const char[] sName = "") {
char sCornerName[64];
if (StrEqual(sName, "") && Corner_IsValid(iCorner)) {
Corner_GetName(iCorner, sCornerName, sizeof(sCornerName));
} else if (!StrEqual(sName, "") && !Corner_IsValid(iCorner)) {
strcopy(sCornerName, sizeof(sCornerName), sName);
iCorner = Corner_FindByName(sCornerName);
} else {
return -1;
}
if (StrContains(sCornerName, "corner_") != -1 && !StrEqual(sCornerName, "corner_final")) {
char sNextName[64];
Corner_GetNextName(iCorner, sNextName, sizeof(sNextName));
return Corner_FindByName(sNextName);
}
return -1;
}
/**
* Gets the previous corner.
*
* @param iCorner The current corner.
* @param sName The current corners name (optional).
* @return The previous corners entity index, or -1 on failure.
*/
stock int Corner_GetPrevious(int iCorner = -1, const char[] sName = "") {
char sCornerName[64];
if (StrEqual(sName, "") && Corner_IsValid(iCorner)) {
Corner_GetName(iCorner, sCornerName, sizeof(sCornerName));
} else if (!StrEqual(sName, "") && !Corner_IsValid(iCorner)) {
strcopy(sCornerName, sizeof(sCornerName), sName);
iCorner = Corner_FindByName(sCornerName);
} else {
return -1;
}
if (StrContains(sCornerName, "corner_") != -1) {
return Corner_FindByNextName(sCornerName);
}
return -1;
}
/**
* Gets the nearest corner to a client.
*
* @param iClient The client.
* @return The corners entity index, or -1 on failure.
*/
stock int Corner_GetNearest(int iClient) {
if (!IsValidClient(iClient) || !IsClientInGame(iClient) || !IsPlayerAlive(iClient)) {
return -1;
}
float fCornerLocation[3], fClientLocation[3];
GetClientAbsOrigin(iClient, fClientLocation);
int iCorner = -1, iNearestCorner = -1;
float fNearestDistance = 2147483647.0, fDistance;
while ((iCorner = FindEntityByClassname(iCorner, "trigger_multiple")) != -1) {
if (Corner_IsValid(iCorner)) {
Corner_GetLocation(iCorner, fCornerLocation, false);
fDistance = GetVectorDistance(fCornerLocation, fClientLocation);
if (fDistance < fNearestDistance) {
iNearestCorner = iCorner;
fNearestDistance = fDistance;
}
}
}
return iNearestCorner;
}
/**
* Gets the two corners a client is in between.
*
* @param iClient The client.
* @param iCornerA The first corner.
* @param iCornerB The second corner.
* @param fEpsilon The possible deviation.
* @return False if not between any corners, true otherwise.
*/
stock bool Corner_GetBetween(int iClient, int &iCornerA, int &iCornerB, float fEpsilon = 15.0) {
if (!IsValidClient(iClient) || !IsClientInGame(iClient) || !IsPlayerAlive(iClient)) {
return false;
}
static int iNearBefore[MAXPLAYERS + 1];
int iNear = Corner_GetNearest(iClient);
float fLocationNear[3], fLocationClient[3];
Corner_GetLocation(iNear, fLocationNear, false);
GetClientAbsOrigin(iClient, fLocationClient);
float fVector[3], fAngles[3], fAnglesClient[3];
MakeVectorFromPoints(fLocationNear, fLocationClient, fVector);
GetVectorAngles(fVector, fAngles);
GetClientEyeAngles(iClient, fAnglesClient);
float fAnglesDiff = FloatAbs(fAngles[1] - fAnglesClient[1]);
if (fAnglesDiff != 0.0 && fAnglesDiff != 45.0 && fAnglesDiff != 90.0 && fAnglesDiff != 135.0 && fAnglesDiff != 180.0 &&
fAnglesDiff != 225.0 && fAnglesDiff != 270.0 && fAnglesDiff != 315.0 && fAnglesDiff != 360.0 && fAnglesDiff > 5.0) {
return false;
}
int iNumberNearBefore = Corner_GetNumber(iNearBefore[iClient]);
if (iNumberNearBefore != -1 && IsValidEntity(iNear)) {
int iNumberNear = Corner_GetNumber(iNear);
if (iNumberNear != -1) {
if (Abs(iNumberNearBefore - iNumberNear) > 1) {
iNearBefore[iClient] = iNear;
return false;
}
}
}
int iNext = Corner_GetNext(iNear);
float fLocationNext[3];
Corner_GetLocation(iNext, fLocationNext);
float fResultA[3], fResultB[3];
SubtractVectors(fLocationNear, fLocationNext, fResultA);
SubtractVectors(fLocationClient, fLocationNext, fResultB);
float fScale = GetVectorDotProduct(fResultA, fResultB) / GetVectorDotProduct(fResultA, fResultA);
ScaleVector(fResultA, fScale);
float fResult[3];
SubtractVectors(fResultB, fResultA, fResult);
if (FloatAbs(fResult[0]) <= fEpsilon && FloatAbs(fResult[1]) <= fEpsilon) {
iCornerA = iNear;
iCornerB = iNext;
iNearBefore[iClient] = iNear;
return true;
}
int iPrev = Corner_GetPrevious(iNear);
float fLocationPrev[3];
Corner_GetLocation(iPrev, fLocationPrev);
SubtractVectors(fLocationNear, fLocationPrev, fResultA);
SubtractVectors(fLocationClient, fLocationPrev, fResultB);
fScale = GetVectorDotProduct(fResultA, fResultB) / GetVectorDotProduct(fResultA, fResultA);
ScaleVector(fResultA, fScale);
SubtractVectors(fResultB, fResultA, fResult);
if (FloatAbs(fResult[0]) <= fEpsilon && FloatAbs(fResult[1]) <= fEpsilon) {
iCornerA = iPrev;
iCornerB = iNear;
iNearBefore[iClient] = iNear;
return true;
}
return false;
}