Initial commit

This commit is contained in:
2025-04-15 22:27:20 -04:00
parent 5b7b68f81f
commit 771d8fe8e8
597 changed files with 149544 additions and 0 deletions

View File

@@ -0,0 +1,178 @@
#pragma semicolon 1
#include <sourcemod>
#if defined INFO_INCLUDES
#include "../info/constants.sp"
#include "../info/enums.sp"
#include "../info/variables.sp"
#endif
enum TDLogLevel
{
TDLogLevel_None = 0, // disables all logging
TDLogLevel_Error = 1, // is for critical errors, the plugin may no longer work correctly
TDLogLevel_Warning = 2, // is for important warnings, the plugin will continue to work correctly
TDLogLevel_Info = 3, // is for informative messages, typically used for deployment
TDLogLevel_Debug = 4, // is for debug messages, this level is useful during development
TDLogLevel_Trace = 5 // is for trace messages, this level is usually only needed when debugging a problem
};
enum TDLogType
{
TDLogType_File = 0, // logs to SourceMod logs
TDLogType_Console = 1, // logs to server console
TDLogType_FileAndConsole = 2 // logs to SourceMod logs and server console
};
static TDLogLevel m_iLogLevel = TDLogLevel_Info;
static TDLogType m_iLogType = TDLogType_FileAndConsole;
stock void Log_Initialize(TDLogLevel iLogLevel = TDLogLevel_Info, TDLogType iLogType = TDLogType_FileAndConsole) {
m_iLogLevel = iLogLevel;
m_iLogType = iLogType;
}
stock void Log(TDLogLevel iLogLevel, const char[] sMessage, any...) {
if (m_iLogLevel >= iLogLevel) {
char sFormattedMessage[256];
VFormat(sFormattedMessage, sizeof(sFormattedMessage), sMessage, 3);
switch (m_iLogType) {
case TDLogType_File: {
switch (iLogLevel) {
case TDLogLevel_Error: {
LogError("[TF2TD > Error] %s", sFormattedMessage);
}
case TDLogLevel_Warning: {
LogError("[TF2TD > Warning] %s", sFormattedMessage);
}
case TDLogLevel_Info: {
LogMessage("[TF2TD > Info] %s", sFormattedMessage);
}
case TDLogLevel_Debug: {
LogMessage("[TF2TD > Debug] %s", sFormattedMessage);
}
case TDLogLevel_Trace: {
LogMessage("[TF2TD > Trace] %s", sFormattedMessage);
}
}
}
case TDLogType_Console: {
switch (iLogLevel) {
case TDLogLevel_Error: {
PrintToServer("[TF2TD > Error] %s", sFormattedMessage);
}
case TDLogLevel_Warning: {
PrintToServer("[TF2TD > Warning] %s", sFormattedMessage);
}
case TDLogLevel_Info: {
PrintToServer("[TF2TD > Info] %s", sFormattedMessage);
}
case TDLogLevel_Debug: {
PrintToServer("[TF2TD > Debug] %s", sFormattedMessage);
}
case TDLogLevel_Trace: {
PrintToServer("[TF2TD > Trace] %s", sFormattedMessage);
}
}
}
case TDLogType_FileAndConsole: {
switch (iLogLevel) {
case TDLogLevel_Error: {
LogError("[TF2TD > Error] %s", sFormattedMessage);
PrintToServer("[TF2TD > Error] %s", sFormattedMessage);
}
case TDLogLevel_Warning: {
LogError("[TF2TD > Warning] %s", sFormattedMessage);
PrintToServer("[TF2TD > Warning] %s", sFormattedMessage);
}
case TDLogLevel_Info: {
LogMessage("[TF2TD > Info] %s", sFormattedMessage);
PrintToServer("[TF2TD > Info] %s", sFormattedMessage);
}
case TDLogLevel_Debug: {
LogMessage("[TF2TD > Debug] %s", sFormattedMessage);
PrintToServer("[TF2TD > Debug] %s", sFormattedMessage);
}
case TDLogLevel_Trace: {
LogMessage("[TF2TD > Trace] %s", sFormattedMessage);
PrintToServer("[TF2TD > Trace] %s", sFormattedMessage);
}
}
}
}
}
}
stock void LogType(TDLogLevel iLogLevel, TDLogType iLogType, const char[] sMessage, any...) {
if (m_iLogLevel >= iLogLevel) {
char sFormattedMessage[256];
VFormat(sFormattedMessage, sizeof(sFormattedMessage), sMessage, 4);
switch (iLogType) {
case TDLogType_File: {
switch (iLogLevel) {
case TDLogLevel_Error: {
LogError("[TF2TD > Error] %s", sFormattedMessage);
}
case TDLogLevel_Warning: {
LogError("[TF2TD > Warning] %s", sFormattedMessage);
}
case TDLogLevel_Info: {
LogMessage("[TF2TD > Info] %s", sFormattedMessage);
}
case TDLogLevel_Debug: {
LogMessage("[TF2TD > Debug] %s", sFormattedMessage);
}
case TDLogLevel_Trace: {
LogMessage("[TF2TD > Trace] %s", sFormattedMessage);
}
}
}
case TDLogType_Console: {
switch (iLogLevel) {
case TDLogLevel_Error: {
PrintToServer("[TF2TD > Error] %s", sFormattedMessage);
}
case TDLogLevel_Warning: {
PrintToServer("[TF2TD > Warning] %s", sFormattedMessage);
}
case TDLogLevel_Info: {
PrintToServer("[TF2TD > Info] %s", sFormattedMessage);
}
case TDLogLevel_Debug: {
PrintToServer("[TF2TD > Debug] %s", sFormattedMessage);
}
case TDLogLevel_Trace: {
PrintToServer("[TF2TD > Trace] %s", sFormattedMessage);
}
}
}
case TDLogType_FileAndConsole: {
switch (iLogLevel) {
case TDLogLevel_Error: {
LogError("[TF2TD > Error] %s", sFormattedMessage);
PrintToServer("[TF2TD > Error] %s", sFormattedMessage);
}
case TDLogLevel_Warning: {
LogError("[TF2TD > Warning] %s", sFormattedMessage);
PrintToServer("[TF2TD > Warning] %s", sFormattedMessage);
}
case TDLogLevel_Info: {
LogMessage("[TF2TD > Info] %s", sFormattedMessage);
PrintToServer("[TF2TD > Info] %s", sFormattedMessage);
}
case TDLogLevel_Debug: {
LogMessage("[TF2TD > Debug] %s", sFormattedMessage);
PrintToServer("[TF2TD > Debug] %s", sFormattedMessage);
}
case TDLogLevel_Trace: {
LogMessage("[TF2TD > Trace] %s", sFormattedMessage);
PrintToServer("[TF2TD > Trace] %s", sFormattedMessage);
}
}
}
}
}
}

View File

@@ -0,0 +1,237 @@
#pragma semicolon 1
#include <sourcemod>
#if defined INFO_INCLUDES
#include "../info/constants.sp"
#include "../info/enums.sp"
#include "../info/variables.sp"
#endif
/**
* Gets a clients current metal amount.
*
* @param iClient The client.
* @return The clients current metal.
*/
stock int GetClientMetal(int iClient) {
return GetEntData(iClient, FindDataMapInfo(iClient, "m_iAmmo") + (3 * 4), 4);
}
/**
* Sets a clients metal amount.
*
* @param iClient The client.
* @param iMetal The metal amount the client should get.
* @noreturn
*/
stock void SetClientMetal(int iClient, int iMetal) {
SetEntData(iClient, FindDataMapInfo(iClient, "m_iAmmo") + (3 * 4), iMetal, 4);
Log(TDLogLevel_Trace, "Set %N's metal to %d", iClient, iMetal);
}
/**
* Resets a clients metal amount back to zero.
*
* @param iClient The client.
* @noreturn
*/
stock void ResetClientMetal(int iClient) {
CreateTimer(0.0, ResetClientMetalDelayed, iClient, TIMER_FLAG_NO_MAPCHANGE); // Process next frame
}
public Action ResetClientMetalDelayed(Handle hTimer, any iClient) {
SetClientMetal(iClient, 0);
return Plugin_Stop;
}
/**
* Add a amount to the clients metal amount.
*
* @param iClient The client.
* @param iMetal The metal amount to add.
* @return True if amount could be added, false otherwise.
*/
stock bool AddClientMetal(int iClient, int iMetal) {
if (iMetal < 0) {
if (GetClientMetal(iClient) + iMetal >= 0) {
SetClientMetal(iClient, GetClientMetal(iClient) + iMetal);
return true;
} else {
return false;
}
}
Player_CAddValue(iClient, PLAYER_METAL_PICK, iMetal);
SetClientMetal(iClient, GetClientMetal(iClient) + iMetal);
return true;
}
/**
* Spawns a metal pack.
*
* @param iMetalPackSpawnType The metal pack type.
* @param fLocation The location it should spawn at.
* @param iMetal The amount of metal it should spawn with.
* @return A TDMetalPackReturn value.
*/
stock TDMetalPackReturn SpawnMetalPack(TDMetalPackSpawnType iMetalPackSpawnType, float fLocation[3], int iMetal) {
int iEntity;
return SpawnMetalPack2(iMetalPackSpawnType, fLocation, iMetal, iEntity);
}
/**
* Spawns a metal pack.
*
* @param iMetalPackSpawnType The metal pack type.
* @param fLocation The location it should spawn at.
* @param iMetal The amount of metal it should spawn with.
* @param iEntity The entity reference to the metal pack.
* @return A TDMetalPackReturn value.
*/
stock TDMetalPackReturn SpawnMetalPack2(TDMetalPackSpawnType iMetalPackSpawnType, float fLocation[3], int iMetal, int &iEntity) {
Log(TDLogLevel_Trace, "SpawnMetalPack2: iMetalPackSpawnType=%d, fLocation=[%f, %f, %f], iMetal=%d", iMetalPackSpawnType, fLocation[0], fLocation[1], fLocation[2], iMetal);
if (iMetal <= 0) {
return TDMetalPack_InvalidMetal;
}
if (g_iMetalPackCount >= METALPACK_LIMIT) {
return TDMetalPack_LimitReached;
}
char sModelPath[PLATFORM_MAX_PATH];
switch (iMetalPackSpawnType) {
case TDMetalPack_Small: {
strcopy(sModelPath, sizeof(sModelPath), "models/items/ammopack_small.mdl");
}
case TDMetalPack_Medium: {
strcopy(sModelPath, sizeof(sModelPath), "models/items/ammopack_medium.mdl");
}
case TDMetalPack_Large: {
strcopy(sModelPath, sizeof(sModelPath), "models/items/ammopack_large.mdl");
}
default: {
return TDMetalPack_InvalidType;
}
}
int iMetalPack = CreateEntityByName("prop_dynamic");
DispatchKeyValue(iMetalPack, "model", sModelPath);
char sMetal[32];
IntToString(iMetal, sMetal, sizeof(sMetal));
DispatchKeyValue(iMetalPack, "targetname", sMetal);
if (DispatchSpawn(iMetalPack)) {
// Make it not solid, but still "collidable"
SetEntProp(iMetalPack, Prop_Send, "m_usSolidFlags", 12); // FSOLID_TRIGGER|FSOLID_NOT_SOLID
SetEntProp(iMetalPack, Prop_Data, "m_nSolidType", 6); // SOLID_VPHYSICS
SetEntProp(iMetalPack, Prop_Data, "m_CollisionGroup", 1); // COLLISION_GROUP_DEBRIS
SetVariantString("idle");
AcceptEntityInput(iMetalPack, "SetAnimation");
TeleportEntity(iMetalPack, fLocation, NULL_VECTOR, NULL_VECTOR);
SDKHook(iMetalPack, SDKHook_Touch, OnMetalPackPickup);
g_iMetalPackCount++;
iEntity = EntIndexToEntRef(iMetalPack);
}
Log(TDLogLevel_Debug, "Spawned metal pack (%d, Metal: %d)", iMetalPack, iMetal);
return TDMetalPack_SpawnedPack;
}
public void OnMetalPackPickup(int iMetalPack, int iClient) {
if (!IsDefender(iClient) || !IsValidEntity(iMetalPack)) {
return;
}
// TODO(hurp): Disperse / give metal to each client instead of just one.
char sMetal[32];
GetEntPropString(iMetalPack, Prop_Data, "m_iName", sMetal, sizeof(sMetal));
int iMetal = StringToInt(sMetal);
AddClientMetal(iClient, iMetal);
ResupplyClient(iClient, true, 0.25);
EmitSoundToClient(iClient, "items/gunpickup2.wav");
HideAnnotation(iMetalPack);
AcceptEntityInput(iMetalPack, "Kill");
g_iMetalPackCount--;
}
/**
* Refills a clients ammo, clip and/or ammo.
*
* @param iClient The client.
* @param bAmmoOnly Only refill ammo not clip.
* @param fPercent The percent to refill (0.5 would be 50%).
* @noreturn
*/
stock void ResupplyClient(int iClient, bool bAmmoOnly = false, float fPercent = 1.0) {
if (!IsDefender(iClient) || !IsPlayerAlive(iClient)) {
return;
}
int iWeapon = GetPlayerWeaponSlot(iClient, TFWeaponSlot_Primary);
if (IsValidEntity(iWeapon)) {
// Engineer's Shotgun
GivePlayerAmmo(iClient, RoundToFloor(32 * fPercent), GetEntProp(iWeapon, Prop_Send, "m_iPrimaryAmmoType"), true);
if (!bAmmoOnly) {
SetClientClip(iClient, TFWeaponSlot_Primary, 6);
}
}
iWeapon = GetPlayerWeaponSlot(iClient, TFWeaponSlot_Secondary);
if (IsValidEntity(iWeapon)) {
// Engineer's Pistol
GivePlayerAmmo(iClient, RoundToFloor(200 * fPercent), GetEntProp(iWeapon, Prop_Send, "m_iPrimaryAmmoType"), true);
if (!bAmmoOnly) {
SetClientClip(iClient, TFWeaponSlot_Secondary, 12);
}
}
}
/**
* Sets the clip of a weapon.
*
* @param iClient The client.
* @param iSlot The weapons slot index.
* @param iClip The clip the weapon should get.
* @noreturn
*/
stock void SetClientClip(int iClient, int iSlot, int iClip) {
if (IsValidClient(iClient) && IsClientInGame(iClient) && IsPlayerAlive(iClient)) {
int iWeapon = GetPlayerWeaponSlot(iClient, iSlot);
if (IsValidEntity(iWeapon)) {
int iAmmoTable = FindSendPropInfo("CTFWeaponBase", "m_iClip1");
SetEntData(iWeapon, iAmmoTable, iClip, 4, true);
}
}
}

View File

@@ -0,0 +1,48 @@
#pragma semicolon 1
#include <sourcemod>
#if defined INFO_INCLUDES
#include "../info/constants.sp"
#include "../info/enums.sp"
#include "../info/variables.sp"
#endif
/**
* Gets a clients steam community id.
*
* @param iClient The client.
* @param sBuffer The destination string buffer.
* @param iMaxLength The maximum length of the output string buffer.
* @return True on success, false otherwise.
*/
stock bool GetClientCommunityId(int iClient, char[] sBuffer, int iMaxLength) {
if (!IsClientConnected(iClient) || IsFakeClient(iClient)) {
return false;
}
int iSteamAccountId = GetSteamAccountID(iClient);
if (iSteamAccountId > 0) {
char sSteamAccountId[32];
char[] sBase = "76561197960265728";
// char[] sBase = { "7", "6", "5", "6", "1", "1", "9", "7", "9", "6", "0", "2", "6", "5", "7", "2", "8" };
char[] sSteamId = new char[iMaxLength];
IntToString((iSteamAccountId - iSteamAccountId % 2) / 2, sSteamAccountId, sizeof(sSteamAccountId));
int iCurrent, iCarryOver = iSteamAccountId % 2;
sSteamId[iMaxLength - 1] = '\0';
int iPos = FindCharInString(sSteamId, '7');
if (iPos > 0 && Substring(sBuffer, iMaxLength, sSteamId, iMaxLength, iPos, strlen(sSteamId))) {
return true;
}
}
return false;
}

View File

@@ -0,0 +1,111 @@
#pragma semicolon 1
#include <sourcemod>
#if defined INFO_INCLUDES
#include "../info/constants.sp"
#include "../info/enums.sp"
#include "../info/variables.sp"
#endif
/**
* Gives a weapon to a client.
* See https://wiki.alliedmods.net/Team_fortress_2_item_definition_indexes for item indexes and classnames.
*
* @param iClient The client who should get the weapon.
* @param iItemDefinitionIndex The weapons items index.
* @param iSlot The weapons slot.
* @param iLevel The weapons level. (must be between 0 an 100)
* @param iQuality The weapons quality. (must be between 0 an 10)
* @param bPreserveAttributes Should attributes be preserved?
* @param sClassname The weapons classname.
* @param sAttributes The attributes to apply tp the weapon. (Format: "<AttributeId1>=<Value1>;<AttributeId2>=<Value2>;...")
* @noreturn
*/
stock void TF2Items_GiveWeapon(int iClient, int iItemDefinitionIndex, int iSlot, int iLevel, int iQuality, bool bPreserveAttributes, char[] sClassname, char[] sAttributes) {
Log(TDLogLevel_Trace, "%d, %d, %d, %d, %d, %s, \"%s\", \"%s\"", iClient, iItemDefinitionIndex, iSlot, iLevel, iQuality, (bPreserveAttributes ? "true" : "false"), sClassname, sAttributes);
Handle hItem = TF2Items_CreateItem(OVERRIDE_ALL);
int iFlags = 0;
TF2Items_SetItemIndex(hItem, iItemDefinitionIndex);
if (iLevel >= 0 && iLevel <= 100) {
TF2Items_SetLevel(hItem, iLevel);
iFlags |= OVERRIDE_ITEM_LEVEL;
}
if (iQuality >= 0 && iQuality <= 10) {
TF2Items_SetQuality(hItem, iQuality);
iFlags |= OVERRIDE_ITEM_QUALITY;
}
if (bPreserveAttributes) {
iFlags |= PRESERVE_ATTRIBUTES;
}
char sAttributeList[15][16], sAttribute[2][16];
int iAttributeIndex;
int iNumAttributes = 0;
float fAttributeValue;
// More than 1 attribute
if (FindCharInString(sAttributes, ';') != -1) {
ExplodeString(sAttributes, ";", sAttributeList, sizeof(sAttributeList), sizeof(sAttributeList[]));
for (int i = 0; i < sizeof(sAttributeList); i++) {
if (!StrEqual(sAttributeList[i], "")) {
ExplodeString(sAttributeList[i], "=", sAttribute, sizeof(sAttribute), sizeof(sAttribute[]));
iAttributeIndex = StringToInt(sAttribute[0]);
fAttributeValue = StringToFloat(sAttribute[1]);
PrintToServer("Attribute: %d, Value: %f", iAttributeIndex, fAttributeValue);
TF2Items_SetAttribute(hItem, i, iAttributeIndex, fAttributeValue);
iNumAttributes++;
}
}
} else {
// Exactly 1 attribute
if (!StrEqual(sAttributes, "")) {
ExplodeString(sAttributes, "=", sAttribute, sizeof(sAttribute), sizeof(sAttribute[]));
iAttributeIndex = StringToInt(sAttribute[0]);
fAttributeValue = StringToFloat(sAttribute[1]);
PrintToServer("Attribute: %d, Value: %f", iAttributeIndex, fAttributeValue);
TF2Items_SetAttribute(hItem, 0, iAttributeIndex, fAttributeValue);
iNumAttributes++;
}
}
if (iNumAttributes != 0 && iNumAttributes <= 15) {
TF2Items_SetNumAttributes(hItem, iNumAttributes);
iFlags |= OVERRIDE_ATTRIBUTES;
}
TF2Items_SetFlags(hItem, iFlags | FORCE_GENERATION);
TF2Items_SetClassname(hItem, sClassname);
TF2_RemoveWeaponSlot(iClient, iSlot);
int iWeapon = TF2Items_GiveNamedItem(iClient, hItem);
if (IsValidEntity(iWeapon)) {
EquipPlayerWeapon(iClient, iWeapon);
Log(TDLogLevel_Debug, "Gave weapon (%d) to %N", iItemDefinitionIndex, iClient);
}
if (IsTower(iClient)) {
TDTowerId iTowerId = GetTowerId(iClient);
Tower_OnWeaponChanged(iClient, iTowerId, iItemDefinitionIndex, iSlot, iWeapon);
}
CloseHandle(hItem);
}

View File

@@ -0,0 +1,307 @@
#pragma semicolon 1
#include <sourcemod>
#if defined INFO_INCLUDES
#include "../info/constants.sp"
#include "../info/enums.sp"
#include "../info/variables.sp"
#endif
/**
* Creates a beam line.
*
* @param iClient The client.
* @param fStart The start point.
* @param fEnd The end point.
* @param fDuration The duration it should appear (in seconds).
* @param iColors The colors.
* @noreturn
*/
stock void CreateBeamLine(int iClient, float fStart[3], float fEnd[3], float fDuration = 5.0, const int[] iColors = { 255, 0, 0, 255 } ) {
int iColors2[4];
iColors2[0] = iColors[0];
iColors2[1] = iColors[1];
iColors2[2] = iColors[2];
iColors2[3] = iColors[3];
TE_SetupBeamPoints(fStart, fEnd, g_iLaserMaterial, g_iHaloMaterial, 0, 0, fDuration + 0.1, 1.0, 1.0, 1, 0.0, iColors2, 0);
if (fDuration == 0.0) {
DataPack hPack = new DataPack();
CreateDataTimer(fDuration, Timer_CreateBeam, hPack);
hPack.WriteCell(iClient);
hPack.WriteFloat(fDuration);
hPack.WriteFloat(fStart[0]);
hPack.WriteFloat(fStart[1]);
hPack.WriteFloat(fStart[2]);
hPack.WriteFloat(fEnd[0]);
hPack.WriteFloat(fEnd[1]);
hPack.WriteFloat(fEnd[2]);
hPack.WriteCell(iColors[0]);
hPack.WriteCell(iColors[1]);
hPack.WriteCell(iColors[2]);
hPack.WriteCell(iColors[3]);
}
TE_SendToAll();
}
public Action Timer_CreateBeam(Handle hTimer, DataPack hPack) {
int iClient, iColors[4];
float fDuration, fStart[3], fEnd[3];
hPack.Reset();
iClient = hPack.ReadCell();
fDuration = hPack.ReadFloat();
fStart[0] = hPack.ReadFloat();
fStart[1] = hPack.ReadFloat();
fStart[2] = hPack.ReadFloat();
fEnd[0] = hPack.ReadFloat();
fEnd[1] = hPack.ReadFloat();
fEnd[2] = hPack.ReadFloat();
iColors[0] = hPack.ReadCell();
iColors[1] = hPack.ReadCell();
iColors[2] = hPack.ReadCell();
iColors[3] = hPack.ReadCell();
CreateBeamLine(iClient, fStart, fEnd, fDuration, iColors);
return Plugin_Stop;
}
/**
* Creates a beam box.
*
* @param iClient The client.
* @param fStart The start point.
* @param fEnd The end point.
* @param fDuration The duration it should appear (in seconds).
* @param iColors The colors.
* @noreturn
*/
stock void CreateBeamBox(int iClient, float fStart[3], float fEnd[3], float fDuration = 5.0, const int[] iColors = { 255, 0, 0, 255 } ) {
float fPoint[8][3];
CopyVector(fStart, fPoint[0]);
CopyVector(fEnd, fPoint[7]);
CreateZonePoints(fPoint);
for (int i = 0, i2 = 3; i2 >= 0; i += i2--) {
for (int j = 1; j <= 7; j += (j / 2) + 1) {
if (j != 7 - i) {
CreateBeamLine(iClient, fPoint[i], fPoint[j], fDuration, iColors);
}
}
}
}
/**
* Creates all 8 zone points by using start and end point.
*
* @param fPoint The array to store the points in.
* @noreturn
*/
stock void CreateZonePoints(float fPoint[8][3]) {
for (int i = 1; i < 7; i++) {
for (int j = 0; j < 3; j++) {
fPoint[i][j] = fPoint[((i >> (2 - j)) & 1) * 7][j];
}
}
}
/**
* Creates all an beam box around a client.
*
* @param iClient The client.
* @param fStart The start point.
* @param fEnd The end point.
* @param fDuration The duration it should appear (in seconds).
* @param iColors The colors.
* @noreturn
*/
stock void CreateBeamBoxAroundClient(int iClient, float fDistance, bool OnlyPlayerHeight = true, float fDuration = 5.0, const int[] iColors = { 255, 0, 0, 255 } ) {
if (!IsValidClient(iClient) || !IsClientConnected(iClient) || !IsClientInGame(iClient) || !IsPlayerAlive(iClient)) {
return;
}
float fLocation[3], fStart[3], fEnd[3];
GetClientAbsOrigin(iClient, fLocation);
if (OnlyPlayerHeight) {
fStart[0] = fLocation[0] - fDistance;
fStart[1] = fLocation[1] - fDistance;
fStart[2] = fLocation[2];
fEnd[0] = fLocation[0] + fDistance;
fEnd[1] = fLocation[1] + fDistance;
fEnd[2] = fLocation[2] + 83;
} else {
fStart[0] = fLocation[0] - fDistance;
fStart[1] = fLocation[1] - fDistance;
fStart[2] = fLocation[2] - fDistance;
fEnd[0] = fLocation[0] + fDistance;
fEnd[1] = fLocation[1] + fDistance;
fEnd[2] = fLocation[2] + 83 + fDistance;
}
CreateBeamBox(iClient, fStart, fEnd, fDuration, iColors);
float fPoint[8][3];
CopyVector(fStart, fPoint[0]);
CopyVector(fEnd, fPoint[7]);
CreateZonePoints(fPoint);
CopyZone(fPoint, g_fBeamPoints[iClient]);
}
/**
* Copies one float vector onto another one.
*
* @param fSource The vector to copy.
* @param fDestination The destination vector.
* @noreturn
*/
stock void CopyVector(float fSource[3], float fDestination[3]) {
for (int i = 0; i < sizeof(fSource); i++) {
fDestination[i] = fSource[i];
}
}
/**
* Copies one zone array onto another one.
*
* @param fSource The array to copy.
* @param fDestination The destination array.
* @noreturn
*/
stock void CopyZone(float fSource[8][3], float fDestination[8][3]) {
for (int i = 0; i < sizeof(fSource); i++) {
for (int j = 0; j < sizeof(fSource[]); j++) {
fDestination[i][j] = fSource[i][j];
}
}
}
/**
* Checkes if an entity is inside a zone.
*
* @param iClient The entity.
* @param fZone The zone array.
* @return True if inside, false otherwise.
*/
stock bool IsEntityInZone(int iEntity, float fZone[8][3], float fDifferenceZ) {
float fEntityPosition[3];
GetEntPropVector(iEntity, Prop_Send, "m_vecOrigin", fEntityPosition);
fEntityPosition[2] += fDifferenceZ;
return IsPointInZone(fEntityPosition, fZone);
}
/**
* Checkes if a client is inside a zone.
*
* @param iClient The client.
* @param fPoint The zone array.
* @return True if inside, false otherwise.
*/
stock bool IsClientInZone(int iClient, float fPoint[8][3]) {
float fPlayerPosition[3], fPlayerPoint[8][3];
GetEntPropVector(iClient, Prop_Send, "m_vecOrigin", fPlayerPosition);
fPlayerPosition[2] += 41.5;
fPlayerPoint[0][0] = fPlayerPosition[0] - 12.0;
fPlayerPoint[0][1] = fPlayerPosition[1] - 12.0;
fPlayerPoint[0][2] = fPlayerPosition[2] - 20.0;
fPlayerPoint[7][0] = fPlayerPosition[0] + 12.0;
fPlayerPoint[7][1] = fPlayerPosition[1] + 12.0;
fPlayerPoint[7][2] = fPlayerPosition[2] + 20.0;
CreateZonePoints(fPlayerPoint);
return Box3DIntersects(fPlayerPoint, fPoint);
}
/**
* Draws a bounding box around a client.
*
* @param iClient The client.
* @noreturn
*/
stock void DrawClientBoundingBox(int iClient) {
float fPlayerPosition[3], fPlayerPoint[8][3];
GetEntPropVector(iClient, Prop_Send, "m_vecOrigin", fPlayerPosition);
fPlayerPosition[2] += 41.5;
fPlayerPoint[0][0] = fPlayerPosition[0] - 12.0;
fPlayerPoint[0][1] = fPlayerPosition[1] - 12.0;
fPlayerPoint[0][2] = fPlayerPosition[2] - 20.0;
fPlayerPoint[7][0] = fPlayerPosition[0] + 12.0;
fPlayerPoint[7][1] = fPlayerPosition[1] + 12.0;
fPlayerPoint[7][2] = fPlayerPosition[2] + 20.0;
CreateZonePoints(fPlayerPoint);
CreateBeamBox(iClient, fPlayerPoint[0], fPlayerPoint[7]);
}
/**
* Checkes if a zone intersects with another zone.
*
* @param fCheck The 1st zone array.
* @param fSource The 2nd zone array.
* @return True if intersects, false otherwise.
*/
stock bool Box3DIntersects(float fCheck[8][3], float fSource[8][3]) {
if (fCheck[0][0] > fSource[4][0] || // fCheck is right of fSource
fCheck[4][0] < fSource[0][0] || // fCheck is left of fSource
fCheck[1][2] < fSource[0][2] || // fCheck is below fSource
fCheck[0][2] > fSource[1][2] || // fCheck is above fSource
fCheck[3][1] < fSource[1][1] || // fCheck is behind fSource
fCheck[1][1] > fSource[3][1]) { // fCheck is in front fSource
return false;
}
return true;
}
/**
* Checkes if a point is inside a zone.
*
* @param fPoint The point vector.
* @param fZone The zone array.
* @return True if inside, false otherwise.
*/
stock bool IsPointInZone(float fPoint[3], float fZone[8][3]) {
if (fPoint[0] > fZone[4][0] || // fPoint is right of fZone
fPoint[0] < fZone[0][0] || // fPoint is left of fZone
fPoint[2] < fZone[0][2] || // fPoint is below fZone
fPoint[2] > fZone[1][2] || // fPoint is above fZone
fPoint[1] < fZone[1][1] || // fPoint is behind fZone
fPoint[1] > fZone[3][1]) { // fPoint is in front fZone
return false;
}
return true;
}