Skip to content
5 changes: 4 additions & 1 deletion addons/sourcemod/configs/szf/classes.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// enable Player can select and play that class.
// health Max health to add/remove.
// regen Health regenerated every second.
// speed Speed in hu/s to add/remove

//Survivor
// ammo Primary ammo gained on a kill or assist.
Expand Down Expand Up @@ -46,6 +47,7 @@

"scout"
{
"speed" "-30"
"ammo" "2"
"menu" "Menu_ClassesSurvivorsScout"
}
Expand Down Expand Up @@ -326,6 +328,7 @@
"viewmodel" "models/kirillian/weapons/hank_viewmodel_v2f.mdl"
"viewmodel_anim" "1"

"speed" "230" // double its movement speed
"ragecooldown" "5"
"callback_spawn" "Infected_OnTankSpawn"
"callback_rage" "Infected_DoTankThrow"
Expand All @@ -336,7 +339,7 @@
"weapon"
{
"index" "5" // Fists
"attrib" "107 ; 2.0 ; 236 ; 1.0 ; 329 ; 0.0 ; 405 ; 0.0" // move speed bonus, weapon blocks healing, airblast immunity, vertical airblast immunity
"attrib" "236 ; 1.0 ; 329 ; 0.0 ; 405 ; 0.0" // weapon blocks healing, airblast immunity, vertical airblast immunity
"logname" "infection_heavy"
"iconname" "infection_heavy"
}
Expand Down
4 changes: 2 additions & 2 deletions addons/sourcemod/configs/szf/weapons.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@

"220" // Shortstop
{
"rarity" "rare"
"rarity" "uncommon"
"model" "models/weapons/c_models/c_shortstop/c_shortstop.mdl"
}

Expand All @@ -68,7 +68,7 @@

"772" // Baby Face's Blaster
{
"rarity" "uncommon"
"rarity" "rare"
"model" "models/weapons/c_models/c_pep_scattergun.mdl"
}

Expand Down
64 changes: 41 additions & 23 deletions addons/sourcemod/scripting/superzombiefortress.sp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

#include "include/superzombiefortress.inc"

#define PLUGIN_VERSION "4.7.2"
#define PLUGIN_VERSION "4.7.3"
#define PLUGIN_VERSION_REVISION "manual"

#define MAX_CONTROL_POINTS 8
Expand Down Expand Up @@ -193,6 +193,7 @@ enum struct ClientClasses
bool bEnabled;
int iHealth;
int iRegen;
float flSpeed;

//Survivor
int iAmmo;
Expand Down Expand Up @@ -1929,7 +1930,7 @@ ArrayList FastRespawnNearby(float flMinDistance, float flMaxDistance, int iForce
g_aFastRespawn.GetArray(i, vecPosOrigin);

bool bAllow = true;
bool bDistance = false;
int iDistanceCount = 0;

//Check if survivors can see it
for (int iClient = 1; iClient <= MaxClients; iClient++)
Expand All @@ -1947,14 +1948,15 @@ ArrayList FastRespawnNearby(float flMinDistance, float flMaxDistance, int iForce
vecPosClient[2] += (vecPosClient[2] - vecPosOrigin[2]) * 4.0;

float flDistance = GetVectorDistance(vecPosClient, vecPosOrigin);
if (flDistance < flMinDistance)
if (flMinDistance < flDistance)
{
// Never allow spawn if too close to any clients
bAllow = false;
break;
}
else if (flDistance <= flMaxDistance)
{
bDistance = true;
iDistanceCount++;
}

if (!iForceClient)
Expand All @@ -1975,7 +1977,11 @@ ArrayList FastRespawnNearby(float flMinDistance, float flMaxDistance, int iForce
break;
}

if (bAllow && bDistance)
if (!bAllow)
continue;

// Require to be nearby atleast 33% of survivors
if (iForceClient || float(iDistanceCount) >= float(GetSurvivorCount()) * 0.33)
aTombola.PushArray(vecPosOrigin);
}

Expand Down Expand Up @@ -2038,30 +2044,16 @@ void FastRespawnDataCollect()
{
float vecPos[3];
g_aFastRespawn.GetArray(i, vecPos);

bool bDelete = true;
for (int iClient = 1; iClient <= MaxClients; iClient++)
{
if (!IsValidLivingClient(iClient))
continue;

if (DistanceFromEntityToPoint(iClient, vecPos) > 1250.0)
continue;

bDelete = false;
break;
}

if (bDelete)
if (!IsValidFastRespawnSpot(vecPos))
g_aFastRespawn.Erase(i);
}

for (int iClient = 1; iClient <= MaxClients; iClient++)
{
if (!IsValidLivingClient(iClient) || GetEntityFlags(iClient) & FL_DUCKING || !(GetEntityFlags(iClient) & FL_ONGROUND))
if (!IsValidLivingClient(iClient) || !(GetEntityFlags(iClient) & FL_ONGROUND))
continue;

ArrayList aPos = FastRespawnNearby(0.0, 100.0, iClient);
ArrayList aPos = FastRespawnNearby(0.0, 50.0, iClient);
if (aPos)
{
delete aPos;
Expand All @@ -2070,11 +2062,37 @@ void FastRespawnDataCollect()
{
float vecPos[3];
GetClientAbsOrigin(iClient, vecPos);
g_aFastRespawn.PushArray(vecPos);
if (IsValidFastRespawnSpot(vecPos))
g_aFastRespawn.PushArray(vecPos);
}
}
}

bool IsValidFastRespawnSpot(const float vecPos[3])
{
// Is spot not stuck in something, like func_respawnroomvisualizer?
Handle hTrace = TR_TraceHullFilterEx(vecPos, vecPos, { -24.0, -24.0, 0.0 }, { 24.0, 24.0, 83.0 }, MASK_PLAYERSOLID, Trace_DontHitClients);
bool bHit = TR_DidHit(hTrace);
delete hTrace;

if (bHit)
return false;

// Is any survivors nearby it?
for (int iClient = 1; iClient <= MaxClients; iClient++)
{
if (!IsValidLivingSurvivor(iClient))
continue;

if (DistanceFromEntityToPoint(iClient, vecPos) > 1250.0)
continue;

return true;
}

return false;
}

void HandleSurvivorLoadout(int iClient)
{
if (!IsValidClient(iClient) || !IsPlayerAlive(iClient))
Expand Down
9 changes: 8 additions & 1 deletion addons/sourcemod/scripting/szf/config.sp
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ bool Config_LoadClassesSection(KeyValues kv, ClientClasses classes)
//Survivor, Zombie and Infected
classes.bEnabled = !!kv.GetNum("enable", classes.bEnabled);
classes.iRegen = kv.GetNum("regen", classes.iRegen);
classes.flSpeed = kv.GetFloat("speed", classes.flSpeed);

//Survivor
classes.iAmmo = kv.GetNum("ammo", classes.iAmmo);
Expand Down Expand Up @@ -606,8 +607,14 @@ void Config_GetRandomDebris(Debris debris)
delete aList;
}

bool Config_GetDebrisFromModel(const char[] sModel, Debris debris)
bool Config_GetDebrisFromEntity(int iEntity, Debris debris)
{
if (!IsClassname(iEntity, "prop_physics"))
return false;

char sModel[256];
GetEntityModel(iEntity, sModel, sizeof(sModel));

int iLength = g_aConfigDebris.Length;
for (int i = 0; i < iLength; i++)
{
Expand Down
7 changes: 7 additions & 0 deletions addons/sourcemod/scripting/szf/dhook.sp
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ public MRESReturn DHook_CalculateMaxSpeedPost(int iClient, DHookReturn hReturn)
if (IsClientInGame(iClient) && IsPlayerAlive(iClient))
{
float flSpeed = hReturn.Value;
if (flSpeed <= 1.0)
return MRES_Ignored;

flSpeed += g_ClientClasses[iClient].flSpeed;

if (IsZombie(iClient))
{
Expand Down Expand Up @@ -221,6 +225,9 @@ public MRESReturn DHook_CalculateMaxSpeedPost(int iClient, DHookReturn hReturn)
}
}

if (flSpeed <= 1.0) // Do not set speed to negative or you'll send em to the backrooms
flSpeed = 1.0;

hReturn.Value = flSpeed;
return MRES_Override;
}
Expand Down
7 changes: 2 additions & 5 deletions addons/sourcemod/scripting/szf/event.sp
Original file line number Diff line number Diff line change
Expand Up @@ -266,14 +266,11 @@ public Action Event_PlayerDeath(Event event, const char[] name, bool dontBroadca
if (IsValidZombie(iKillers[0]) && g_nInfected[iKillers[0]] == Infected_Spitter && event.GetInt("customkill") == TF_CUSTOM_BLEEDING)
event.SetString("weapon", "infection_acid_puddle");

if (iInflictor != INVALID_ENT_REFERENCE && IsClassname(iInflictor, "prop_physics"))
if (iInflictor != INVALID_ENT_REFERENCE)
{
// Could be a tank thorwing debris to set kill icon
char sModel[256];
GetEntityModel(iInflictor, sModel, sizeof(sModel));

Debris debris;
if (Config_GetDebrisFromModel(sModel, debris))
if (Config_GetDebrisFromEntity(iInflictor, debris))
event.SetString("weapon", debris.sIconName);
}

Expand Down
11 changes: 6 additions & 5 deletions addons/sourcemod/scripting/szf/infected.sp
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,6 @@ public void Infected_DoTankThrow(int iClient)

DispatchSpawn(iDebris);

SetEntPropFloat(iDebris, Prop_Data, "m_impactEnergyScale", 0.0); //After DispatchSpawn, otherwise 1 would be set

g_iTankDebris[iClient] = EntIndexToEntRef(iDebris);

CreateTimer(flThrow, Infected_DebrisTimer, GetClientSerial(iClient));
Expand Down Expand Up @@ -313,15 +311,18 @@ void Infected_DebrisFrameFadeOut(int iDebris)

public Action Infected_DebrisStartTouch(int iDebris, int iToucher)
{
if (iToucher <= 0 || iToucher > MaxClients)
return Plugin_Continue;

int iClient = GetEntPropEnt(iDebris, Prop_Send, "m_hOwnerEntity");

float vecVelocity[3];
SDKCall_GetVelocity(iDebris, vecVelocity);
float flSpeed = GetVectorLength(vecVelocity);
if (flSpeed < 100.0)
return Plugin_Continue;

if (0 < iToucher <= MaxClients && flSpeed >= 100.0)
SDKHooks_TakeDamage(iToucher, iDebris, iClient, flSpeed / 4.0);

SDKHooks_TakeDamage(iToucher, iDebris, iClient, flSpeed / 4.0);
return Plugin_Continue;
}

Expand Down
4 changes: 4 additions & 0 deletions addons/sourcemod/scripting/szf/sdkhook.sp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ public Action Client_OnTakeDamage(int iVictim, int &iAttacker, int &iInflicter,
if (!CanRecieveDamage(iVictim))
return Plugin_Continue;

Debris debris;
if (Config_GetDebrisFromEntity(iInflicter, debris) && GetEntPropEnt(iInflicter, Prop_Send, "m_hOwnerEntity") != iAttacker)
return Plugin_Stop; // Prevent TF2 game allowing debris to damage victim, we want to handle our own damages

bool bChanged = false;

if (g_ClientClasses[iVictim].callback_damage != INVALID_FUNCTION)
Expand Down
5 changes: 5 additions & 0 deletions addons/sourcemod/scripting/szf/stocks.sp
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,11 @@ bool Trace_DontHitEntity(int iEntity, int iMask, any iData)
return true;
}

bool Trace_DontHitClients(int iEntity, int iMask, any iData)
{
return iEntity <= 0 || iEntity > MaxClients;
}

bool Trace_DontHitTeammates(int iEntity, int iMask, any iData)
{
if (iEntity <= 0 || iEntity > MaxClients)
Expand Down
Loading