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

237 lines
6.3 KiB
SourcePawn

#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);
}
}
}