PHP Code:
#include <sdktools>
#include <sourcemod>
#include <tf2>
#undef REQUIRE_PLUGIN
#tryinclude <updater>
#pragma semicolon 1
#define PLUGIN_VERSION "1.0"
public Plugin:myinfo =
{
name = "Portable Resupply",
author = "nergal/assyrian",
description = "Allows Players to take their resupply lockers with them anywhere!",
version = PLUGIN_VERSION,
url = "hue"
}
//defines
#define SupplyModel "models/props_gameplay/resupply_locker.mdl"
#define SND_REGEN "items/regenerate.wav"
//cvar handles
new Handle:bEnabled = INVALID_HANDLE;
new Handle:Cooldown = INVALID_HANDLE;
new Handle:bAllOrNone = INVALID_HANDLE;
new Handle:ArenaMode = INVALID_HANDLE;
new Handle:AllowBlu = INVALID_HANDLE;
new Handle:AllowRed = INVALID_HANDLE;
//bools
//floats
new Float:g_flTimer[MAXPLAYERS+1];
new Float:g_fltime;
//ints
new g_iRefs[2];
new g_iAmmoTable[2049];
new g_iClipTable[2049];
new g_iResuppliesBuilt[2];
new Handle:Timer[MAXPLAYERS+1] = INVALID_HANDLE;
public OnPluginStart()
{
bEnabled = CreateConVar("sm_portablelocker_enabled", "1", "Enable Portable Resupply plugin", FCVAR_PLUGIN, true, 0.0, true, 1.0);
Cooldown = CreateConVar("sm_portablelocker_cooldown", "30.0", "cooldown time for the resupply locker to be used", FCVAR_PLUGIN, true, 1.0, true, 999.0);
bAllOrNone = CreateConVar("sm_portablelocker_allornone", "1", "sets whether individual players will be affected by cooldown rate or all, 1 for all, 0 for none", FCVAR_PLUGIN, true, 0.0, true, 1.0);
ArenaMode = CreateConVar("sm_portablelocker_arenamode", "0", "If set to 1, will simply give the player health+ammo rather than regenerate like normal resupply lockers, 0 for regenerate like normal", FCVAR_PLUGIN, true, 0.0, true, 1.0);
AllowBlu = CreateConVar("sm_portablelocker_blu", "0", "(Dis)Allow portable resupply lockers for BLU team", FCVAR_PLUGIN|FCVAR_NOTIFY, true, 0.0, true, 1.0);
AllowRed = CreateConVar("sm_portablelocker_red", "1", "(Dis)Allow portable resupply lockers for RED team", FCVAR_PLUGIN|FCVAR_NOTIFY, true, 0.0, true, 1.0);
//AddCommandListener(Listener_Voice, "voicemenu");
RegAdminCmd("sm_portableresupply", CreatePortableResupply, ADMFLAG_KICK);
for (new i = 1; i <= MaxClients; i++)
{
if (!IsClientInGame(i) || !IsValidClient(i)) continue;
OnClientPutInServer(i);
}
}
public OnClientPutInServer(client)
{
if (IsValidClient(client))
{
Timer[client] = CreateTimer(0.1, MyDearWatson, client, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
g_flTimer[client] = 0.0;
}
}
public OnMapStart()
{
decl String:s[PLATFORM_MAX_PATH];
PrecacheModel(SupplyModel, true);
g_fltime = GetGameTime();
g_iResuppliesBuilt[0] = 0;
g_iResuppliesBuilt[1] = 0;
PrecacheSound(SND_REGEN, true);
}
public Action:MyDearWatson(Handle:timer, any:client)
{
if (!IsValidClient(client)) return Plugin_Stop;
if (!GetConVarBool(AllowBlu) && GetClientTeam(client) == 3) return Plugin_Continue;
if (!GetConVarBool(AllowRed) && GetClientTeam(client) == 2) return Plugin_Continue;
if (IsClientObserver(client)) return Plugin_Continue;
new team = GetClientTeam(client);
new entity = EntRefToEntIndex(g_iRefs[team-2]);
if (!IsValidEntity(entity) || !IsValidEdict(entity)) return Plugin_Continue;
if (IsInRange(client, entity, 100.0) && g_flTimer[client] <= g_fltime)
{
SetVariantString("open");
AcceptEntityInput(entity, "SetAnimation");
ResupplyPlayer(client);
}
else if (!IsInRange(client, entity, 100.0) || g_flTimer[client] > g_fltime)
{
SetVariantString("close");
AcceptEntityInput(entity, "SetAnimation");
}
return Plugin_Continue;
}
/*public OnPreThink(client)
{
if (!IsValidClient(client) || !GetConVarBool(bEnabled) || IsClientObserver(client)) return;
if (!GetConVarBool(AllowBlu) && (GetClientTeam(client) == 3)) return;
if (!GetConVarBool(AllowRed) && (GetClientTeam(client) == 2)) return;
new team = GetClientTeam(client);
new entity = EntRefToEntIndex(g_iRefs[team-2]);
if (!IsValidEntity(entity) || !IsValidEdict(entity)) return;
if (IsInRange(client, entity, 100.0) && g_flTimer[client] < g_fltime)
{
SetVariantString("open");
AcceptEntityInput(entity, "SetAnimation");
ResupplyPlayer(client);
}
else if (!IsInRange(client, entity, 100.0) || g_flTimer[client] > g_fltime)
{
SetVariantString("close");
AcceptEntityInput(entity, "SetAnimation");
}
return;
}*/
public ResupplyPlayer(client)
{
if (IsValidClient(client) && IsPlayerAlive(client))
{
new Float:cooldown = GetConVarFloat(Cooldown);
if (!GetConVarBool(ArenaMode)) TF2_RegeneratePlayer(client);
else
{
for (new h = 0; h < 2; h++)
{
new weap = GetPlayerWeaponSlot(client, h);
if (weap == -1) continue;
new maxAmmo = g_iAmmoTable[weap];
new Ammo = GetWeaponAmmo(client, weap);
if (Ammo == maxAmmo) continue;
SetWeaponAmmo(client, weap, maxAmmo);
new maxClip = g_iClipTable[weap];
new clip = GetWeaponClip(weap);
if (clip == maxClip) continue;
SetWeaponClip(weap, maxClip);
}
SetEntityHealth(client, GetEntProp(client, Prop_Data, "m_iMaxHealth"));
}
EmitSoundToClient(client, "items/regenerate.wav");
if (GetConVarBool(bAllOrNone))
{
for (new i = 0; i <= MaxClients; i++)
{
if (IsValidClient(i))
{
if (GetClientTeam(i) == GetClientTeam(client)) g_flTimer[i] = g_fltime+cooldown;
}
}
}
else g_flTimer[client] = g_fltime+cooldown;
}
return;
}
public CreateResupply(client, Float:flOrigin[3], Float:flAngles[3], health)
{
new resupplier = CreateEntityByName("prop_dynamic_override");
//PrintToConsole(client, "created entity via name");
if (IsValidEdict(resupplier) && IsValidEntity(resupplier))
{
DispatchSpawn(resupplier);
//PrintToConsole(client, "spawned the entity");
//SetEntProp(resupplier, Prop_Send, "m_nModelIndex", SupplyModel);
// DispatchKeyValue(resupplier, "model", SupplyModel);
//PrintToConsole(client, "set the model");
SetEntityModel(resupplier, SupplyModel);
//SetEntProp(resupplier, Prop_Send, "m_iTeamNum", GetClientTeam(client), 1);
SetEntPropEnt(resupplier, Prop_Data, "m_hOwnerEntity", client);
//PrintToConsole(client, "set the owner");
SetEntProp(resupplier, Prop_Send, "m_nSolidType", 6);
//PrintToConsole(client, "set the m_nSolidType as #6");
DispatchKeyValue(resupplier, "targetname", "portable_resupply");
//PrintToConsole(client, "set entity name");
SetEntProp(resupplier, Prop_Data, "m_takedamage", 2);
//PrintToConsole(client, "set to take damage");
SetEntProp(resupplier, Prop_Data, "m_iHealth", health);
//PrintToConsole(client, "set health to %i", health);
TeleportEntity(resupplier, flOrigin, flAngles, NULL_VECTOR);
//PrintToConsole(client, "flOrigin[0] = %f, flOrigin[1] = %f, flOrigin[2] = %f", flOrigin[0], flOrigin[1], flOrigin[2]);
//PrintToConsole(client, "flAngles[0] = %f, flAngles[1] = %f, flAngles[2] = %f", flAngles[0], flAngles[1], flAngles[2]);
//PrintToConsole(client, "returned entity");
return resupplier;
//HookSingleEntityOutput(resupplier, "OnBreak", OnPropBreak, true);
}
return 0;
}
/*public OnPropBreak(const String:output[], caller, activator, Float:delay)
{
if (IsValidEntity(caller) && IsValidClient(activator))
{
//UnhookSingleEntityOutput(caller, "OnBreak", OnPropBreak);
new active = GetClientTeam(activator);
AcceptEntityInput(caller, "kill");
g_iResuppliesBuilt[active-2] -= 1;
}
}*/
//new bool:m_bMedicButtonBool[MAXPLAYERS+1] = false;
//public Action:Listener_Voice(client, const String:command[], argc)
public Action:CreatePortableResupply(client, args)
{
if (IsValidClient(client) && GetConVarBool(bEnabled) && IsPlayerAlive(client))
{
new team = GetClientTeam(client), Float:flPos[3], Float:flAng[3];
if (!GetConVarBool(AllowBlu) && (team == 3)) return Plugin_Handled;
if (!GetConVarBool(AllowRed) && (team == 2)) return Plugin_Handled;
//decl String:arguments[4];
//GetCmdArgString(arguments, sizeof(arguments));
//if (StrEqual(arguments, "0 0") && IsPlayerAlive(client))
//m_bMedicButtonBool[client] = true;
if (g_iResuppliesBuilt[team-2] == 0)
{
//PrintToConsole(client, "g_iResuppliesBuilt[team-2] = %i", g_iResuppliesBuilt[team-2]);
GetClientEyePosition(client, flPos);
//PrintToConsole(client, "flPos[0] = %f, flPos[1] = %f, flPos[2] = %f", flPos[0], flPos[1], flPos[2]);
GetClientEyeAngles(client, flAng);
//PrintToConsole(client, "flAng[0] = %f, flAng[1] = %f, flAng[2] = %f", flAng[0], flAng[1], flAng[2]);
new Handle:hTrace = TR_TraceRayFilterEx(flPos, flAng, MASK_SHOT, RayType_Infinite, TraceFilterIgnorePlayers, client);
if (hTrace != INVALID_HANDLE && TR_DidHit(hTrace))
{
//PrintToConsole(client, "TR_DidHit = true and hTrace is not invalid");
new Float:flEndPos[3];
TR_GetEndPosition(flEndPos, hTrace);
//PrintToConsole(client, "flEndPos[0] = %f, flEndPos[1] = %f, flEndPos[2] = %f", flEndPos[0], flEndPos[1], flEndPos[2]);
flEndPos[2] += 5.0;
//PrintToConsole(client, "flEndPos[0] = %f, flEndPos[1] = %f, flEndPos[2] = %f", flEndPos[0], flEndPos[1], flEndPos[2]);
new Float:mins[3] = {-24.0, -24.0, 0.0};
new Float:maxs[3] = {24.0, 24.0, 55.0};
//PrintToConsole(client, "mins[0] = %f, mins[1] = %f, mins[2] = %f", mins[0], mins[1], mins[2]);
//PrintToConsole(client, "maxs[0] = %f, maxs[1] = %f, maxs[2] = %f", maxs[0], maxs[1], maxs[2]);
if (CanBuildHere(flEndPos, mins, maxs))
{
//PrintToConsole(client, "Yes we can build here");
GetClientAbsAngles(client, flAng);
//PrintToConsole(client, "flAng[0] = %f, flAng[1] = %f, flAng[2] = %f", flAng[0], flAng[1], flAng[2]);
new portable = CreateResupply(client, flEndPos, flAng, 200);
g_iRefs[team-2] = EntIndexToEntRef(portable);
//PrintToConsole(client, "g_iRefs[team-2] = %i", g_iRefs[team-2]);
g_iResuppliesBuilt[team-2] += 1;
//PrintToConsole(client, "g_iResuppliesBuilt[team-2] = %i", g_iResuppliesBuilt[team-2]);
CloseHandle(hTrace);
//PrintToConsole(client, "hTrace handle is closed and plugin is returned handled.");
return Plugin_Handled;
}
PrintToChat(client, "Can't build Resupply there :3");
CloseHandle(hTrace);
PrintToConsole(client, "hTrace handle is closed and plugin is returned handled.");
return Plugin_Handled;
}
}
else
{
new ent = EntRefToEntIndex(g_iRefs[team-2]);
PrintToConsole(client, "made ent");
if (IsValidEntity(ent) && IsValidEdict(ent))
{
//PrintToConsole(client, "Entity is valid enough");
AcceptEntityInput(ent, "Kill");
//PrintToConsole(client, "Killed off Entity");
g_iResuppliesBuilt[team-2] -= 1;
//PrintToConsole(client, "g_iResuppliesBuilt[team-2] = %i", g_iResuppliesBuilt[team-2]);
PrintToChat(client, "Destroying old Resupply");
}
else PrintToConsole(client, "entity wasn't valid");
PrintToConsole(client, "returning Handled");
return Plugin_Handled;
}
}
return Plugin_Continue;
}
public OnEntityCreated(entity, const String:classname[])
{
if (entity < 0 || entity > 2048) return;
if (GetConVarBool(bEnabled) && !StrContains(classname, "tf_weapon_"))
CreateTimer(0.3, OnWeaponSpawned, EntIndexToEntRef(entity));
}
public Action:OnWeaponSpawned(Handle:timer, any:ref)
{
new wep = EntRefToEntIndex(ref);
if (IsValidEntity(wep) && IsValidEdict(wep))
{
new client = GetEntPropEnt(wep, Prop_Send, "m_hOwnerEntity");
if (!IsValidClient(client)) return Plugin_Continue;
g_iAmmoTable[wep] = GetWeaponAmmo(client, wep);
g_iClipTable[wep] = GetWeaponClip(wep);
}
return Plugin_Continue;
}
public OnEntityDestroyed(Ent)
{
if (Ent <= 0 || Ent > 2048) return;
g_iClipTable[Ent] = 0;
g_iAmmoTable[Ent] = 0;
}
//stocks
stock bool:IsInRange(entity, target, Float:distance)
{
new Float:pos[3], Float:entpos[3];
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", pos);
GetEntPropVector(target, Prop_Send, "m_vecOrigin", entpos);
new Float:dist = GetVectorDistance(pos, entpos);
if (dist <= distance) return true;
return false;
}
stock bool:IsValidClient(iClient, bool:bReplay = true)
{
if (iClient <= 0 || iClient > MaxClients) return false;
if (!IsClientInGame(iClient)) return false;
if (bReplay && (IsClientSourceTV(iClient) || IsClientReplay(iClient))) return false;
return true;
}
stock GetWeaponAmmo(client, weapon)
{
if (!IsValidClient(client)) return 0;
if (IsValidEntity(weapon))
{
new iOffset = GetEntProp(weapon, Prop_Send, "m_iPrimaryAmmoType", 1)*4;
new iAmmoTable = FindSendPropInfo("CTFPlayer", "m_iAmmo");
return GetEntData(client, iAmmoTable+iOffset);
}
return 0;
}
stock SetWeaponAmmo(client, weapon, ammo)
{
if (!IsValidClient(client)) return 0;
if (IsValidEntity(weapon))
{
new iOffset = GetEntProp(weapon, Prop_Send, "m_iPrimaryAmmoType", 1)*4;
new iAmmoTable = FindSendPropInfo("CTFPlayer", "m_iAmmo");
SetEntData(client, iAmmoTable+iOffset, ammo, 4, true);
}
return 0;
}
stock GetWeaponClip(weapon)
{
if (IsValidEntity(weapon))
{
new AmmoClipTable = FindSendPropInfo("CTFWeaponBase", "m_iClip1");
return GetEntData(weapon, AmmoClipTable);
}
return 0;
}
stock SetWeaponClip(weapon, ammo)
{
if (IsValidEntity(weapon))
{
new iAmmoTable = FindSendPropInfo("CTFWeaponBase", "m_iClip1");
SetEntData(weapon, iAmmoTable, ammo, 4, true);
}
return 0;
}
stock bool:CanBuildHere(Float:flPos[3], Float:flMins[3], Float:flMaxs[3])
{
TR_TraceHull(flPos, flPos, flMins, flMaxs, MASK_SOLID);
return !TR_DidHit();
}
public bool:TraceFilterIgnorePlayers(entity, contentsMask, any:client)
{
if (entity >= 1 && entity <= MaxClients) return false;
return true;
}