mirror of
https://github.com/Jackzmc/sourcemod-plugins.git
synced 2025-05-07 17:23:21 +00:00
Update
This commit is contained in:
parent
ea0bc8c543
commit
28796e46cf
19 changed files with 165 additions and 132 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -573,7 +573,6 @@ bool Filter_IgnoreForbidden(int entity, int mask, int data) {
|
||||||
bool CheckBlacklist(int entity) {
|
bool CheckBlacklist(int entity) {
|
||||||
static char buffer[64];
|
static char buffer[64];
|
||||||
GetEntityClassname(entity, buffer, sizeof(buffer));
|
GetEntityClassname(entity, buffer, sizeof(buffer));
|
||||||
PrintToServer("GrabEnt:CheckBlacklist | classname=\"%s\"", buffer);
|
|
||||||
for(int i = 0; i < MAX_FORBIDDEN_CLASSNAMES; i++) {
|
for(int i = 0; i < MAX_FORBIDDEN_CLASSNAMES; i++) {
|
||||||
if(StrEqual(FORBIDDEN_CLASSNAMES[i], buffer)) {
|
if(StrEqual(FORBIDDEN_CLASSNAMES[i], buffer)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -582,7 +581,6 @@ bool CheckBlacklist(int entity) {
|
||||||
if(StrContains(buffer, "prop_") > -1) {
|
if(StrContains(buffer, "prop_") > -1) {
|
||||||
GetEntPropString(entity, Prop_Data, "m_ModelName", buffer, sizeof(buffer));
|
GetEntPropString(entity, Prop_Data, "m_ModelName", buffer, sizeof(buffer));
|
||||||
for(int i = 0; i < MAX_FORBIDDEN_MODELS; i++) {
|
for(int i = 0; i < MAX_FORBIDDEN_MODELS; i++) {
|
||||||
PrintToServer("GrabEnt:CheckBlacklist | model=\"%s\" FORBIDDEN_MODELS[%d] = \"%s\"", buffer, i, FORBIDDEN_MODELS[i]);
|
|
||||||
if(StrEqual(FORBIDDEN_MODELS[i], buffer)) {
|
if(StrEqual(FORBIDDEN_MODELS[i], buffer)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include <sdktools>
|
#include <sdktools>
|
||||||
#include <sdkhooks>
|
#include <sdkhooks>
|
||||||
|
|
||||||
static int disableFFClient, ffDamageCount; //client to disable FF for
|
static int disableFFClient = -1, ffDamageCount; //client to disable FF for
|
||||||
static ConVar forceKickFFThreshold;
|
static ConVar forceKickFFThreshold;
|
||||||
|
|
||||||
public Plugin myinfo = {
|
public Plugin myinfo = {
|
||||||
|
|
|
@ -152,11 +152,14 @@ void OnTankBotSpawn(int client) {
|
||||||
if(!IsEPIActive() || !(cvEPISpecialSpawning.IntValue & 4)) return;
|
if(!IsEPIActive() || !(cvEPISpecialSpawning.IntValue & 4)) return;
|
||||||
// Only run on 6+ survivors
|
// Only run on 6+ survivors
|
||||||
if(g_realSurvivorCount < 6) return;
|
if(g_realSurvivorCount < 6) return;
|
||||||
if(g_finaleStage == Stage_FinaleTank2) {
|
// Check if any finale is active
|
||||||
if(hExtraFinaleTank.IntValue > 0 && g_extraFinaleTankEnabled) {
|
if(g_finaleStage != Stage_Inactive) {
|
||||||
float duration = GetRandomFloat(EXTRA_TANK_MIN_SEC, EXTRA_TANK_MAX_SEC);
|
if(g_finaleStage == Stage_FinaleTank2) {
|
||||||
// Pass it 0, which doesnt make it a split tank, has default health
|
if(hExtraFinaleTank.IntValue > 0 && g_extraFinaleTankEnabled) {
|
||||||
CreateTimer(duration, Timer_SpawnSplitTank, 0);
|
float duration = GetRandomFloat(EXTRA_TANK_MIN_SEC, EXTRA_TANK_MAX_SEC);
|
||||||
|
// Pass it 0, which doesnt make it a split tank, has default health
|
||||||
|
CreateTimer(duration, Timer_SpawnSplitTank, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if(g_newTankHealth > 0) {
|
} else if(g_newTankHealth > 0) {
|
||||||
// A split tank has spawned, set its health
|
// A split tank has spawned, set its health
|
||||||
|
@ -164,11 +167,13 @@ void OnTankBotSpawn(int client) {
|
||||||
SetEntProp(client, Prop_Send, "m_iHealth", g_newTankHealth);
|
SetEntProp(client, Prop_Send, "m_iHealth", g_newTankHealth);
|
||||||
g_newTankHealth = 0;
|
g_newTankHealth = 0;
|
||||||
} else {
|
} else {
|
||||||
// Normal (non-finale) tank spawned. Set its health
|
// This should not run on active finales (different than finale maps, such as swamp fever's, where finale isnt full map)
|
||||||
|
// Normal tank (not stage 2 / not secondary tank) spawned. Set its health and spawn split tank
|
||||||
int health = GetEntProp(client, Prop_Send, "m_iHealth");
|
int health = GetEntProp(client, Prop_Send, "m_iHealth");
|
||||||
float additionalHealth = float(g_survivorCount - 4) * cvEPITankHealth.FloatValue;
|
float additionalHealth = float(g_survivorCount - 4) * cvEPITankHealth.FloatValue;
|
||||||
health += RoundFloat(additionalHealth);
|
health += RoundFloat(additionalHealth);
|
||||||
|
|
||||||
|
// Only split if split tank chance, if enabled, and we aren't on 2nd finale tank
|
||||||
if(hExtraFinaleTank.IntValue & 1 && GetURandomFloat() <= hSplitTankChance.FloatValue) {
|
if(hExtraFinaleTank.IntValue & 1 && GetURandomFloat() <= hSplitTankChance.FloatValue) {
|
||||||
float duration = GetRandomFloat(EXTRA_TANK_MIN_SEC, EXTRA_TANK_MAX_SEC);
|
float duration = GetRandomFloat(EXTRA_TANK_MIN_SEC, EXTRA_TANK_MAX_SEC);
|
||||||
int splitHealth = health / 2;
|
int splitHealth = health / 2;
|
||||||
|
@ -183,6 +188,7 @@ void OnTankBotSpawn(int client) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Action Timer_SpawnSplitTank(Handle h, int health) {
|
Action Timer_SpawnSplitTank(Handle h, int health) {
|
||||||
|
PrintDebug(DEBUG_SPAWNLOGIC, "Timer_SpawnSplitTank(%d)", health);
|
||||||
g_newTankHealth = health;
|
g_newTankHealth = health;
|
||||||
DirectorSpawn(Special_Tank);
|
DirectorSpawn(Special_Tank);
|
||||||
return Plugin_Handled;
|
return Plugin_Handled;
|
||||||
|
@ -215,6 +221,7 @@ void Event_PlayerIncapped(Event event, const char[] name, bool dontBroadcast) {
|
||||||
TryGrantRest();
|
TryGrantRest();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// METHODS
|
/// METHODS
|
||||||
|
|
||||||
|
|
||||||
|
@ -237,7 +244,6 @@ void InitExtraWitches() {
|
||||||
// Calculate the number of witches we want to spawn.
|
// Calculate the number of witches we want to spawn.
|
||||||
// We bias the dice roll to the right. We slowly increase min based on player count to shift distribution to the right
|
// We bias the dice roll to the right. We slowly increase min based on player count to shift distribution to the right
|
||||||
int min = RoundToFloor(float(count - 5) / 4.0);
|
int min = RoundToFloor(float(count - 5) / 4.0);
|
||||||
// TODO: max based on count
|
|
||||||
int max = RoundToFloor(float(count) / 4.0);
|
int max = RoundToFloor(float(count) / 4.0);
|
||||||
|
|
||||||
// TODO: inc chance based on map max flow
|
// TODO: inc chance based on map max flow
|
||||||
|
@ -288,7 +294,7 @@ void Director_RandomizeLimits() {
|
||||||
}
|
}
|
||||||
void Director_RandomizeThings() {
|
void Director_RandomizeThings() {
|
||||||
g_maxStressIntensity = GetRandomFloat(DIRECTOR_STRESS_CUTOFF, 1.0);
|
g_maxStressIntensity = GetRandomFloat(DIRECTOR_STRESS_CUTOFF, 1.0);
|
||||||
g_minFlowSpawn = GetRandomFloat(FLOW_CUTOFF, FLOW_CUTOFF * 2);
|
g_minFlowSpawn = GetRandomFloat(500.0 + FLOW_CUTOFF, FLOW_CUTOFF * 2);
|
||||||
Director_RandomizeLimits();
|
Director_RandomizeLimits();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,8 +310,6 @@ bool Director_ShouldRest() {
|
||||||
void TryGrantRest() {
|
void TryGrantRest() {
|
||||||
if(GetURandomFloat() <= DIRECTOR_REST_CHANCE) {
|
if(GetURandomFloat() <= DIRECTOR_REST_CHANCE) {
|
||||||
g_restCount = GetRandomInt(0, DIRECTOR_REST_MAX_COUNT);
|
g_restCount = GetRandomInt(0, DIRECTOR_REST_MAX_COUNT);
|
||||||
if(g_restCount > 0)
|
|
||||||
PrintDebug(DEBUG_SPAWNLOGIC, "new rest period: %.1f s", g_restCount * DIRECTOR_TIMER_INTERVAL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,8 +351,7 @@ directorState Director_Think() {
|
||||||
// A. They reach minimum flow (little past start saferoom)
|
// A. They reach minimum flow (little past start saferoom)
|
||||||
// B. Under the total limited (equal to player count)
|
// B. Under the total limited (equal to player count)
|
||||||
// C. Special spawning is enabled
|
// C. Special spawning is enabled
|
||||||
// TODO: scaling chance, low chance when hitting g_infectedCount, higher on 0
|
if( ~cvEPISpecialSpawning.IntValue & 1 || !L4D_HasAnySurvivorLeftSafeArea() || g_highestFlowAchieved < g_minFlowSpawn) return DState_PendingMinFlowOrDisabled;
|
||||||
if(g_highestFlowAchieved < g_minFlowSpawn || ~cvEPISpecialSpawning.IntValue & 1) return DState_PendingMinFlowOrDisabled;
|
|
||||||
|
|
||||||
// Check if a rest period is given
|
// Check if a rest period is given
|
||||||
if(Director_ShouldRest()) {
|
if(Director_ShouldRest()) {
|
||||||
|
@ -424,7 +427,7 @@ Action Timer_DirectorWitch(Handle h) {
|
||||||
void DirectorSpawn(specialType special, int player = -1) {
|
void DirectorSpawn(specialType special, int player = -1) {
|
||||||
if(player <= 0)
|
if(player <= 0)
|
||||||
player = GetSuitableVictim();
|
player = GetSuitableVictim();
|
||||||
PrintDebug(DEBUG_SPAWNLOGIC, "Director: spawning %s(%d) around %N (cnt=%d,lim=%d)", SPECIAL_IDS[view_as<int>(special)], special, player, g_spawnCount[view_as<int>(special)], g_spawnLimit[view_as<int>(special)]);
|
// PrintDebug(DEBUG_SPAWNLOGIC, "Director: spawning %s(%d) around %N (cnt=%d,lim=%d)", SPECIAL_IDS[view_as<int>(special)], special, player, g_spawnCount[view_as<int>(special)], g_spawnLimit[view_as<int>(special)]);
|
||||||
if(special != Special_Witch && special != Special_Tank) {
|
if(special != Special_Witch && special != Special_Tank) {
|
||||||
// Bypass director
|
// Bypass director
|
||||||
int bot = CreateFakeClient("EPI_BOT");
|
int bot = CreateFakeClient("EPI_BOT");
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
int BUILDER_COLOR[4] = { 0, 255, 0, 235 };
|
int BUILDER_COLOR[4] = { 0, 255, 0, 235 };
|
||||||
int WALL_COLOR[4] = { 255, 0, 0, 235 };
|
int GLOW_BLUE[4] = { 3, 148, 252 };
|
||||||
|
int GLOW_RED[4] = { 255, 0, 0, 235 };
|
||||||
|
int GLOW_WHITE[4] = { 255, 255, 255, 255 };
|
||||||
|
int GLOW_GREEN[4] = { 3, 252, 53 };
|
||||||
float ORIGIN_SIZE[3] = { 2.0, 2.0, 2.0 };
|
float ORIGIN_SIZE[3] = { 2.0, 2.0, 2.0 };
|
||||||
|
|
||||||
enum wallMode {
|
enum wallMode {
|
||||||
|
@ -27,13 +30,13 @@ enum struct WallBuilderData {
|
||||||
bool isCopy;
|
bool isCopy;
|
||||||
|
|
||||||
void Reset(bool initial = false) {
|
void Reset(bool initial = false) {
|
||||||
|
this.entity = INVALID_ENT_REFERENCE;
|
||||||
this.isCopy = false;
|
this.isCopy = false;
|
||||||
this.size[0] = this.size[1] = this.size[2] = 5.0;
|
this.size[0] = this.size[1] = this.size[2] = 5.0;
|
||||||
this.angles[0] = this.angles[1] = this.angles[2] = 0.0;
|
this.angles[0] = this.angles[1] = this.angles[2] = 0.0;
|
||||||
this.axis = 1;
|
this.axis = 1;
|
||||||
this.canScale = true;
|
this.canScale = true;
|
||||||
this.moveDistance = 200.0;
|
this.moveDistance = 200.0;
|
||||||
this.entity = INVALID_ENT_REFERENCE;
|
|
||||||
this.hasCollision = true;
|
this.hasCollision = true;
|
||||||
this.CalculateMins();
|
this.CalculateMins();
|
||||||
this.SetMode(INACTIVE);
|
this.SetMode(INACTIVE);
|
||||||
|
@ -188,6 +191,7 @@ enum struct WallBuilderData {
|
||||||
DispatchKeyValueVector(blocker, "maxs", this.size);
|
DispatchKeyValueVector(blocker, "maxs", this.size);
|
||||||
DispatchKeyValueVector(blocker, "boxmins", this.mins);
|
DispatchKeyValueVector(blocker, "boxmins", this.mins);
|
||||||
DispatchKeyValueVector(blocker, "boxmaxs", this.size);
|
DispatchKeyValueVector(blocker, "boxmaxs", this.size);
|
||||||
|
DispatchKeyValue(blocker, "excludednpc", "player");
|
||||||
|
|
||||||
DispatchKeyValueVector(blocker, "angles", this.angles);
|
DispatchKeyValueVector(blocker, "angles", this.angles);
|
||||||
DispatchKeyValue(blocker, "model", DUMMY_MODEL);
|
DispatchKeyValue(blocker, "model", DUMMY_MODEL);
|
||||||
|
@ -207,8 +211,9 @@ enum struct WallBuilderData {
|
||||||
enteffects |= 32; //EF_NODRAW
|
enteffects |= 32; //EF_NODRAW
|
||||||
SetEntProp(blocker, Prop_Send, "m_fEffects", enteffects);
|
SetEntProp(blocker, Prop_Send, "m_fEffects", enteffects);
|
||||||
AcceptEntityInput(blocker, "Enable");
|
AcceptEntityInput(blocker, "Enable");
|
||||||
|
SDKHook(blocker, SDKHook_Use, OnWallClicked);
|
||||||
|
|
||||||
this.Draw(WALL_COLOR, 5.0, 1.0);
|
this.Draw(GLOW_GREEN, 5.0, 1.0);
|
||||||
this.Reset();
|
this.Reset();
|
||||||
return isEdit ? -2 : createdWalls.Push(EntIndexToEntRef(blocker));
|
return isEdit ? -2 : createdWalls.Push(EntIndexToEntRef(blocker));
|
||||||
}
|
}
|
||||||
|
@ -219,18 +224,22 @@ enum struct WallBuilderData {
|
||||||
GetEntityClassname(this.entity, classname, sizeof(classname));
|
GetEntityClassname(this.entity, classname, sizeof(classname));
|
||||||
|
|
||||||
int entity = CreateEntityByName(classname);
|
int entity = CreateEntityByName(classname);
|
||||||
PrintToServer("Created %s: %d", classname, entity);
|
|
||||||
if(entity == -1) return -1;
|
if(entity == -1) return -1;
|
||||||
GetEntPropString(this.entity, Prop_Data, "m_ModelName", classname, sizeof(classname));
|
GetEntPropString(this.entity, Prop_Data, "m_ModelName", classname, sizeof(classname));
|
||||||
DispatchKeyValueVector(entity, "origin", this.origin);
|
|
||||||
DispatchKeyValue(entity, "solid", "6");
|
|
||||||
DispatchKeyValue(entity, "model", classname);
|
DispatchKeyValue(entity, "model", classname);
|
||||||
PrintToServer("Set model %s: %d", classname, entity);
|
|
||||||
|
|
||||||
|
Format(classname, sizeof(classname), "hats_copy_%d", this.entity);
|
||||||
|
DispatchKeyValue(entity, "targetname", classname);
|
||||||
|
|
||||||
|
DispatchKeyValue(entity, "solid", "6");
|
||||||
|
|
||||||
DispatchSpawn(entity);
|
DispatchSpawn(entity);
|
||||||
|
// SetEntProp(entity, Prop_Send, "m_CollisionGroup", 1);
|
||||||
|
// SetEntProp(entity, Prop_Send, "m_nSolidType", 6);
|
||||||
TeleportEntity(entity, this.origin, this.angles, NULL_VECTOR);
|
TeleportEntity(entity, this.origin, this.angles, NULL_VECTOR);
|
||||||
this.entity = entity;
|
this.entity = entity;
|
||||||
this.isCopy = true;
|
this.isCopy = true;
|
||||||
SetEntProp(entity, Prop_Send, "m_nSolidType", 2);
|
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,6 +264,17 @@ enum struct WallBuilderData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Action OnWallClicked(int entity, int activator, int caller, UseType type, float value) {
|
||||||
|
int wallId = FindWallId(entity);
|
||||||
|
if(wallId > 0) {
|
||||||
|
GlowWall(wallId, GLOW_BLUE);
|
||||||
|
AcceptEntityInput(entity, "Toggle");
|
||||||
|
} else {
|
||||||
|
PrintHintText(activator, "Invalid wall entity (%d)", entity);
|
||||||
|
}
|
||||||
|
return Plugin_Continue;
|
||||||
|
}
|
||||||
|
|
||||||
WallBuilderData WallBuilder[MAXPLAYERS+1];
|
WallBuilderData WallBuilder[MAXPLAYERS+1];
|
||||||
|
|
||||||
|
|
||||||
|
@ -301,7 +321,7 @@ public Action Command_ManageWalls(int client, int args) {
|
||||||
if(args == 0) {
|
if(args == 0) {
|
||||||
PrintToChat(client, "\x04[Hats]\x01 Created Walls: \x05%d\x01", createdWalls.Length);
|
PrintToChat(client, "\x04[Hats]\x01 Created Walls: \x05%d\x01", createdWalls.Length);
|
||||||
for(int i = 1; i <= createdWalls.Length; i++) {
|
for(int i = 1; i <= createdWalls.Length; i++) {
|
||||||
GlowWall(i, 20.0);
|
GlowWall(i, GLOW_WHITE, 20.0);
|
||||||
}
|
}
|
||||||
return Plugin_Handled;
|
return Plugin_Handled;
|
||||||
}
|
}
|
||||||
|
@ -381,7 +401,7 @@ public Action Command_ManageWalls(int client, int args) {
|
||||||
for(int i = 1; i <= createdWalls.Length; i++) {
|
for(int i = 1; i <= createdWalls.Length; i++) {
|
||||||
int entity = GetWallEntity(i);
|
int entity = GetWallEntity(i);
|
||||||
AcceptEntityInput(entity, "Toggle");
|
AcceptEntityInput(entity, "Toggle");
|
||||||
GlowWall(i);
|
GlowWall(i, GLOW_BLUE);
|
||||||
}
|
}
|
||||||
PrintToChat(client, "\x04[Hats]\x01 Toggled \x05%d\x01 walls", walls);
|
PrintToChat(client, "\x04[Hats]\x01 Toggled \x05%d\x01 walls", walls);
|
||||||
} else {
|
} else {
|
||||||
|
@ -389,7 +409,7 @@ public Action Command_ManageWalls(int client, int args) {
|
||||||
if(id > -1) {
|
if(id > -1) {
|
||||||
int entity = GetWallEntity(id);
|
int entity = GetWallEntity(id);
|
||||||
AcceptEntityInput(entity, "Toggle");
|
AcceptEntityInput(entity, "Toggle");
|
||||||
GlowWall(id);
|
GlowWall(id, GLOW_BLUE);
|
||||||
PrintToChat(client, "\x04[Hats]\x01 Toggled Wall: \x05#%d\x01", id);
|
PrintToChat(client, "\x04[Hats]\x01 Toggled Wall: \x05#%d\x01", id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -487,7 +507,7 @@ int GetWallId(int client, const char[] arg) {
|
||||||
int entity = GetWallEntity(id);
|
int entity = GetWallEntity(id);
|
||||||
if(!IsValidEntity(entity)) {
|
if(!IsValidEntity(entity)) {
|
||||||
ReplyToCommand(client, "\x04[Hats]\x01 The wall with specified id no longer exists.");
|
ReplyToCommand(client, "\x04[Hats]\x01 The wall with specified id no longer exists.");
|
||||||
createdWalls.Erase(id);
|
createdWalls.Erase(id - 1);
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
return id;
|
return id;
|
||||||
|
@ -504,7 +524,19 @@ int GetWallEntity(int id) {
|
||||||
return createdWalls.Get(id - 1);
|
return createdWalls.Get(id - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlowWall(int id, float lifetime = 5.0) {
|
/// Tries to find the id of the wall based off entity
|
||||||
|
int FindWallId(int entity) {
|
||||||
|
for(int i = 1; i <= createdWalls.Length; i++) {
|
||||||
|
int entRef = createdWalls.Get(i - 1);
|
||||||
|
int ent = EntRefToEntIndex(entRef);
|
||||||
|
if(ent == entity) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlowWall(int id, int glowColor[4], float lifetime = 5.0) {
|
||||||
int ref = GetWallEntity(id);
|
int ref = GetWallEntity(id);
|
||||||
if(IsValidEntity(ref)) {
|
if(IsValidEntity(ref)) {
|
||||||
float pos[3], mins[3], maxs[3], angles[3];
|
float pos[3], mins[3], maxs[3], angles[3];
|
||||||
|
@ -512,12 +544,12 @@ void GlowWall(int id, float lifetime = 5.0) {
|
||||||
GetEntPropVector(ref, Prop_Send, "m_vecOrigin", pos);
|
GetEntPropVector(ref, Prop_Send, "m_vecOrigin", pos);
|
||||||
GetEntPropVector(ref, Prop_Send, "m_vecMins", mins);
|
GetEntPropVector(ref, Prop_Send, "m_vecMins", mins);
|
||||||
GetEntPropVector(ref, Prop_Send, "m_vecMaxs", maxs);
|
GetEntPropVector(ref, Prop_Send, "m_vecMaxs", maxs);
|
||||||
Effect_DrawBeamBoxRotatableToAll(pos, mins, maxs, angles, g_iLaserIndex, 0, 0, 30, lifetime, 0.4, 0.4, 0, 1.0, WALL_COLOR, 0);
|
Effect_DrawBeamBoxRotatableToAll(pos, mins, maxs, angles, g_iLaserIndex, 0, 0, 30, lifetime, 0.4, 0.4, 0, 1.0, glowColor, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeleteWall(int id) {
|
void DeleteWall(int id) {
|
||||||
GlowWall(id);
|
GlowWall(id, GLOW_RED);
|
||||||
int ref = GetWallEntity(id);
|
int ref = GetWallEntity(id);
|
||||||
if(IsValidEntity(ref)) {
|
if(IsValidEntity(ref)) {
|
||||||
RemoveEntity(ref);
|
RemoveEntity(ref);
|
||||||
|
|
|
@ -965,3 +965,11 @@ stock void GetMenuDisplayName(int client, char[] display, int maxlen) {
|
||||||
GetClientName(client, display, maxlen);
|
GetClientName(client, display, maxlen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stock int MathMax(int a, int b) {
|
||||||
|
return a > b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
stock int MathMin(int a, int b) {
|
||||||
|
return a < b ? a : b;
|
||||||
|
}
|
|
@ -408,8 +408,8 @@ stock int GetWeaponName(WeaponId wepid, char[] nameBuffer, int length) {
|
||||||
return IsValidWeaponId(wepid) ? strcopy(nameBuffer, length, WeaponNames[wepid]) : 0;
|
return IsValidWeaponId(wepid) ? strcopy(nameBuffer, length, WeaponNames[wepid]) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
stock int GetMeleeWeaponName(WeaponId wepid, char[] nameBuffer, int length) {
|
stock int GetMeleeWeaponName(MeleeWeaponId wepid, char[] nameBuffer, int length) {
|
||||||
return IsValidWeaponId(wepid) ? strcopy(nameBuffer, length, MeleeWeaponNames[wepid]) : 0;
|
return IsValidMeleeWeaponId(wepid) ? strcopy(nameBuffer, length, MeleeWeaponNames[wepid]) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -278,41 +278,22 @@ void Event_PlayerDisconnect(Event event, const char[] name, bool dontBroadcast)
|
||||||
|
|
||||||
Action Event_OnTakeDamage(int victim, int& attacker, int& inflictor, float& damage, int& damagetype, int& weapon, float damageForce[3], float damagePosition[3]) {
|
Action Event_OnTakeDamage(int victim, int& attacker, int& inflictor, float& damage, int& damagetype, int& weapon, float damageForce[3], float damagePosition[3]) {
|
||||||
if(isEnabled && damage > 0.0 && victim <= MaxClients && attacker <= MaxClients && attacker > 0 && victim > 0) {
|
if(isEnabled && damage > 0.0 && victim <= MaxClients && attacker <= MaxClients && attacker > 0 && victim > 0) {
|
||||||
if(GetClientTeam(victim) != GetClientTeam(attacker) || attacker == victim)
|
if(GetClientTeam(attacker) != 2 || GetClientTeam(victim) != 2 || attacker == victim)
|
||||||
return Plugin_Continue;
|
return Plugin_Continue;
|
||||||
else if(damagetype & DMG_BURN && hFFAutoScaleActivateTypes.IntValue & view_as<int>(RffActType_MolotovDamage) && IsFakeClient(attacker) && GetClientTeam(attacker) == 2) {
|
else if(IsFakeClient(attacker) && attacker != victim) {
|
||||||
// Ignore damage from fire caused by bots (players who left after causing fire)
|
// Ignore damage from fire/explosives caused by bots (players who left after causing fire)
|
||||||
damage = 0.0;
|
if(damagetype & DMG_BURN && hFFAutoScaleActivateTypes.IntValue & view_as<int>(RffActType_MolotovDamage)) {
|
||||||
return Plugin_Changed;
|
damage = 0.0;
|
||||||
} else if((damagetype & DMG_BLAST || damagetype & DMG_BLAST_SURFACE) && hFFAutoScaleActivateTypes.IntValue & view_as<int>(RffActType_BlastDamage) && IsFakeClient(attacker) && GetClientTeam(attacker) == 2) {
|
return Plugin_Changed;
|
||||||
damage = 0.0;
|
} else if((damagetype & DMG_BLAST || damagetype & DMG_BLAST_SURFACE) && hFFAutoScaleActivateTypes.IntValue & view_as<int>(RffActType_BlastDamage)) {
|
||||||
return Plugin_Changed;
|
damage = 0.0;
|
||||||
|
return Plugin_Changed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Otherwise if attacker was ignored or is a bot, stop here and let vanilla handle it
|
|
||||||
else if(pData[attacker].immunityFlags & Immune_RFF || IsFakeClient(attacker) || IsFakeClient(victim)) return Plugin_Continue;
|
|
||||||
// If victim is black and white and rff damage isnt turned on for it, allow it:
|
|
||||||
else if(damagetype & DMG_DIRECT && GetEntProp(victim, Prop_Send, "m_isGoingToDie") && ~hFFAutoScaleActivateTypes.IntValue & view_as<int>(RffActType_BlackAndWhiteDamage)) {
|
|
||||||
return Plugin_Continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//Allow friendly firing BOTS that aren't idle players:
|
|
||||||
//if(IsFakeClient(victim) && !HasEntProp(attacker, Prop_Send, "m_humanSpectatorUserID") || GetEntProp(attacker, Prop_Send, "m_humanSpectatorUserID") == 0) return Plugin_Continue;
|
|
||||||
|
|
||||||
// Stop all damage early if already marked as troll
|
|
||||||
else if(pData[attacker].isTroll) {
|
|
||||||
SDKHooks_TakeDamage(attacker, attacker, attacker, pData[attacker].autoRFFScaleFactor * damage);
|
|
||||||
return Plugin_Stop;
|
|
||||||
}
|
|
||||||
// Allow vanilla-damage if being attacked by special (example, charger carry)
|
|
||||||
else if(pData[victim].underAttack) return Plugin_Continue;
|
|
||||||
|
|
||||||
bool isAdmin = GetUserAdmin(attacker) != INVALID_ADMIN_ID;
|
bool isAdmin = GetUserAdmin(attacker) != INVALID_ADMIN_ID;
|
||||||
// Is damage not caused by fire or pipebombs?
|
|
||||||
bool isDamageDirect = damagetype & (DMG_BURN) == 0;
|
|
||||||
int time = GetTime();
|
int time = GetTime();
|
||||||
// If is a fall within first 2 minutes, do appropiate action
|
// If is a fall within first 2 minutes, do appropiate action
|
||||||
if(!isAdmin && damagetype & DMG_FALL && attacker == victim && damage > 0.0 && time - pData[victim].joinTime <= hJoinTime.IntValue * 60) {
|
if(damagetype & DMG_FALL && attacker == victim && damage > 0.0 && time - pData[victim].joinTime <= hJoinTime.IntValue * 60) {
|
||||||
pData[victim].jumpAttempts++;
|
pData[victim].jumpAttempts++;
|
||||||
float pos[3];
|
float pos[3];
|
||||||
GetNearestPlayerPosition(victim, pos);
|
GetNearestPlayerPosition(victim, pos);
|
||||||
|
@ -336,6 +317,30 @@ Action Event_OnTakeDamage(int victim, int& attacker, int& inflictor, float& dam
|
||||||
}
|
}
|
||||||
return Plugin_Stop;
|
return Plugin_Stop;
|
||||||
}
|
}
|
||||||
|
// Disregard any self inflicted damage from here:
|
||||||
|
else if(attacker == victim) return Plugin_Continue;
|
||||||
|
|
||||||
|
// Stop all damage early if already marked as troll
|
||||||
|
else if(pData[attacker].isTroll) {
|
||||||
|
SDKHooks_TakeDamage(attacker, attacker, attacker, pData[attacker].autoRFFScaleFactor * damage);
|
||||||
|
return Plugin_Stop;
|
||||||
|
}
|
||||||
|
// Otherwise if attacker is immune, is a bot, or victim is a bot, let it continue
|
||||||
|
else if(pData[attacker].immunityFlags & Immune_RFF || IsFakeClient(attacker) || IsFakeClient(victim)) return Plugin_Continue;
|
||||||
|
// If victim is black and white and rff damage isnt turned on for it, allow it:
|
||||||
|
else if(GetEntProp(victim, Prop_Send, "m_isGoingToDie") && ~hFFAutoScaleActivateTypes.IntValue & view_as<int>(RffActType_BlackAndWhiteDamage)) {
|
||||||
|
return Plugin_Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Allow friendly firing BOTS that aren't idle players:
|
||||||
|
//if(IsFakeClient(victim) && !HasEntProp(attacker, Prop_Send, "m_humanSpectatorUserID") || GetEntProp(attacker, Prop_Send, "m_humanSpectatorUserID") == 0) return Plugin_Continue;
|
||||||
|
|
||||||
|
// Allow vanilla-damage if being attacked by special (example, charger carry)
|
||||||
|
// We don't want to track someone accidently ffing them when theres a window where you can
|
||||||
|
else if(pData[victim].underAttack) return Plugin_Continue;
|
||||||
|
|
||||||
|
// Is damage not caused by fire or pipebombs?
|
||||||
|
bool isDamageDirect = (damagetype & DMG_BURN) == 0;
|
||||||
|
|
||||||
// Forgive player teamkill based on threshold, resetting accumlated damage
|
// Forgive player teamkill based on threshold, resetting accumlated damage
|
||||||
if(time - pData[attacker].lastFFTime > hForgivenessTime.IntValue) {
|
if(time - pData[attacker].lastFFTime > hForgivenessTime.IntValue) {
|
||||||
|
@ -498,13 +503,13 @@ Action Command_TKInfo(int client, int args) {
|
||||||
float activeRate = GetActiveRate(target);
|
float activeRate = GetActiveRate(target);
|
||||||
CReplyToCommand(client, "FF Frequency: {yellow}%d {default}(recent: %d, %d forgiven)", pData[target].totalFFCount, pData[target].ffCount, (pData[target].totalFFCount - pData[target].ffCount));
|
CReplyToCommand(client, "FF Frequency: {yellow}%d {default}(recent: %d, %d forgiven)", pData[target].totalFFCount, pData[target].ffCount, (pData[target].totalFFCount - pData[target].ffCount));
|
||||||
if(pData[client].lastFFTime == 0)
|
if(pData[client].lastFFTime == 0)
|
||||||
CReplyToCommand(client, "Total FF Damage: {yellow}%.1f HP{default} (last fff Never)", pData[target].totalDamageFF);
|
CReplyToCommand(client, "Total FF Damage: {yellow}%.1f HP{default} (last ff Never)", pData[target].totalDamageFF);
|
||||||
else
|
else
|
||||||
CReplyToCommand(client, "Total FF Damage: {yellow}%.1f HP{default} (last fff %.1f min ago)", pData[target].totalDamageFF, minutesSinceiLastFFTime);
|
CReplyToCommand(client, "Total FF Damage: {yellow}%.1f HP{default} (last ff %.1f min ago)", pData[target].totalDamageFF, minutesSinceiLastFFTime);
|
||||||
if(~pData[target].immunityFlags & Immune_TK)
|
if(~pData[target].immunityFlags & Immune_TK)
|
||||||
CReplyToCommand(client, "Recent FF (TKDetectBuffer): {yellow}%.1f", pData[target].TKDamageBuffer);
|
CReplyToCommand(client, "Recent FF (TKDetectBuffer): {yellow}%.1f", pData[target].TKDamageBuffer);
|
||||||
if(~pData[target].immunityFlags & Immune_RFF)
|
if(~pData[target].immunityFlags & Immune_RFF)
|
||||||
CReplyToCommand(client, "Auto Reverse-FF: {yellow}%.1fx return rate", activeRate);
|
CReplyToCommand(client, "Auto Reverse-FF: {yellow}%.1fx rate", activeRate);
|
||||||
CReplyToCommand(client, "Attempted suicide jumps: {yellow}%d", pData[target].jumpAttempts);
|
CReplyToCommand(client, "Attempted suicide jumps: {yellow}%d", pData[target].jumpAttempts);
|
||||||
} else {
|
} else {
|
||||||
for(int i = 1; i <= MaxClients; i++) {
|
for(int i = 1; i <= MaxClients; i++) {
|
||||||
|
|
|
@ -48,7 +48,7 @@ Action Command_Status(int client, int args) {
|
||||||
int exceedRestartMin = exceedRestart / 60;
|
int exceedRestartMin = exceedRestart / 60;
|
||||||
int exceedRestartHour = exceedRestartMin / 60;
|
int exceedRestartHour = exceedRestartMin / 60;
|
||||||
ReplyToCommand(client, "Overdue restart time: %d hr / %d min / %d s", exceedRestartHour, exceedRestartMin, exceedRestart);
|
ReplyToCommand(client, "Overdue restart time: %d hr / %d min / %d s", exceedRestartHour, exceedRestartMin, exceedRestart);
|
||||||
ReplyToCommand(client, "triesBots = %d\ttriesEmpty = %d / %d", triesBots, triesEmpty);
|
ReplyToCommand(client, "triesBots = %d\ttriesEmpty = %d / %d", triesBots, triesEmpty, 4);
|
||||||
return Plugin_Handled;
|
return Plugin_Handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
extraitems = (playerCount) * (cabinetAmount/4) - cabinetAmount
|
extraitems = (playerCount) * (cabinetAmount/4) - cabinetAmount
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//TODO: On 3rd/4th kit pickup in area, add more
|
|
||||||
//TODO: Add extra pills too, on pickup
|
|
||||||
|
|
||||||
#pragma semicolon 1
|
#pragma semicolon 1
|
||||||
#pragma newdecls required
|
#pragma newdecls required
|
||||||
|
@ -35,7 +33,7 @@
|
||||||
#define FLOW_CUTOFF 500.0 // The cutoff of flow, so that witches / tanks don't spawn in saferooms / starting areas, [0 + FLOW_CUTOFF, MapMaxFlow - FLOW_CUTOFF]
|
#define FLOW_CUTOFF 500.0 // The cutoff of flow, so that witches / tanks don't spawn in saferooms / starting areas, [0 + FLOW_CUTOFF, MapMaxFlow - FLOW_CUTOFF]
|
||||||
|
|
||||||
#define EXTRA_TANK_MIN_SEC 2.0
|
#define EXTRA_TANK_MIN_SEC 2.0
|
||||||
#define EXTRA_TANK_MAX_SEC 20.0
|
#define EXTRA_TANK_MAX_SEC 16.0
|
||||||
#define DATE_FORMAT "%F at %I:%M %p"
|
#define DATE_FORMAT "%F at %I:%M %p"
|
||||||
|
|
||||||
|
|
||||||
|
@ -196,8 +194,8 @@ enum struct PlayerInventory {
|
||||||
bool isAlive;
|
bool isAlive;
|
||||||
|
|
||||||
WeaponId itemID[6]; //int -> char?
|
WeaponId itemID[6]; //int -> char?
|
||||||
|
MeleeWeaponId meleeID; // If itemID[1] == WeaponId_Melee, pull from this
|
||||||
bool lasers;
|
bool lasers;
|
||||||
char meleeID[32];
|
|
||||||
|
|
||||||
int primaryHealth;
|
int primaryHealth;
|
||||||
int tempHealth;
|
int tempHealth;
|
||||||
|
@ -225,7 +223,7 @@ Restore from saved inventory
|
||||||
static StringMap weaponMaxClipSizes;
|
static StringMap weaponMaxClipSizes;
|
||||||
static StringMap pInv;
|
static StringMap pInv;
|
||||||
static int g_lastInvSave[MAXPLAYERS+1];
|
static int g_lastInvSave[MAXPLAYERS+1];
|
||||||
static Handle g_saveTimer[MAXPLAYERS+1];
|
static Handle g_saveTimer[MAXPLAYERS+1] = { null, ... };
|
||||||
|
|
||||||
static char HUD_SCRIPT_DATA[] = "eph <- { Fields = { players = { slot = g_ModeScript.HUD_RIGHT_BOT, dataval = \"%s\", flags = g_ModeScript.HUD_FLAG_ALIGN_LEFT | g_ModeScript.HUD_FLAG_TEAM_SURVIVORS | g_ModeScript.HUD_FLAG_NOBG } } }\nHUDSetLayout(eph)\nHUDPlace(g_ModeScript.HUD_RIGHT_BOT,0.78,0.77,0.3,0.3)\ng_ModeScript;";
|
static char HUD_SCRIPT_DATA[] = "eph <- { Fields = { players = { slot = g_ModeScript.HUD_RIGHT_BOT, dataval = \"%s\", flags = g_ModeScript.HUD_FLAG_ALIGN_LEFT | g_ModeScript.HUD_FLAG_TEAM_SURVIVORS | g_ModeScript.HUD_FLAG_NOBG } } }\nHUDSetLayout(eph)\nHUDPlace(g_ModeScript.HUD_RIGHT_BOT,0.78,0.77,0.3,0.3)\ng_ModeScript;";
|
||||||
|
|
||||||
|
@ -360,7 +358,6 @@ public void OnPluginStart() {
|
||||||
if(IsClientConnected(i) && IsClientInGame(i)) {
|
if(IsClientConnected(i) && IsClientInGame(i)) {
|
||||||
if(GetClientTeam(i) == 2) {
|
if(GetClientTeam(i) == 2) {
|
||||||
SaveInventory(i, true);
|
SaveInventory(i, true);
|
||||||
SDKHook(i, SDKHook_WeaponEquip, Event_Pickup);
|
|
||||||
}
|
}
|
||||||
playerData[i].Setup(i);
|
playerData[i].Setup(i);
|
||||||
}
|
}
|
||||||
|
@ -539,7 +536,7 @@ public void Event_DifficultyChange(ConVar cvar, const char[] oldValue, const cha
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
/// COMMANDS
|
/// COMMANDS
|
||||||
////////////////////////////////////
|
////////////////////////////////////
|
||||||
void ValBool(int client, const char[] name, bool &value, const char[] input) {
|
public void ValBool(int client, const char[] name, bool &value, const char[] input) {
|
||||||
if(input[0] != '\0') {
|
if(input[0] != '\0') {
|
||||||
value = input[0] == '1' || input[0] == 't';
|
value = input[0] == '1' || input[0] == 't';
|
||||||
CReplyToCommand(client, "Set {olive}%s{default} to {yellow}%b", name, value);
|
CReplyToCommand(client, "Set {olive}%s{default} to {yellow}%b", name, value);
|
||||||
|
@ -547,7 +544,7 @@ void ValBool(int client, const char[] name, bool &value, const char[] input) {
|
||||||
CReplyToCommand(client, "Value of {olive}%s{default}: {yellow}%b", name, value);
|
CReplyToCommand(client, "Value of {olive}%s{default}: {yellow}%b", name, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void ValInt(int client, const char[] name, int &value, const char[] input) {
|
public void ValInt(int client, const char[] name, int &value, const char[] input) {
|
||||||
if(input[0] != '\0') {
|
if(input[0] != '\0') {
|
||||||
value = StringToInt(input);
|
value = StringToInt(input);
|
||||||
CReplyToCommand(client, "Set {olive}%s{default} to {yellow}%d", name, value);
|
CReplyToCommand(client, "Set {olive}%s{default} to {yellow}%d", name, value);
|
||||||
|
@ -555,7 +552,7 @@ void ValInt(int client, const char[] name, int &value, const char[] input) {
|
||||||
CReplyToCommand(client, "Value of {olive}%s{default}: {yellow}%d", name, value);
|
CReplyToCommand(client, "Value of {olive}%s{default}: {yellow}%d", name, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void ValFloat(int client, const char[] name, float &value, const char[] input) {
|
public void ValFloat(int client, const char[] name, float &value, const char[] input) {
|
||||||
if(input[0] != '\0') {
|
if(input[0] != '\0') {
|
||||||
value = StringToFloat(input);
|
value = StringToFloat(input);
|
||||||
CReplyToCommand(client, "Set {olive}%s{default} to {yellow}%f", name, value);
|
CReplyToCommand(client, "Set {olive}%s{default} to {yellow}%f", name, value);
|
||||||
|
@ -794,7 +791,6 @@ Action Command_DebugStats(int client, int args) {
|
||||||
ReplyToCommand(client, "\x04%d. \x05%s", i, arg);
|
ReplyToCommand(client, "\x04%d. \x05%s", i, arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ReplyToCommand(client, "%s", inv.meleeID);
|
|
||||||
}
|
}
|
||||||
return Plugin_Handled;
|
return Plugin_Handled;
|
||||||
}
|
}
|
||||||
|
@ -812,7 +808,7 @@ void Event_PlayerToIdle(Event event, const char[] name, bool dontBroadcast) {
|
||||||
if(GetClientTeam(client) != 2) return;
|
if(GetClientTeam(client) != 2) return;
|
||||||
PrintToServer("%N -> idle %N", client, bot);
|
PrintToServer("%N -> idle %N", client, bot);
|
||||||
}
|
}
|
||||||
public Action L4D2_OnChangeFinaleStage(int &finaleType, const char[] arg) {
|
public void L4D2_OnChangeFinaleStage_PostHandled(int finaleType, const char[] arg) {
|
||||||
if(finaleType == FINALE_STARTED && g_realSurvivorCount > 4) {
|
if(finaleType == FINALE_STARTED && g_realSurvivorCount > 4) {
|
||||||
g_finaleStage = Stage_FinaleActive;
|
g_finaleStage = Stage_FinaleActive;
|
||||||
PrintToConsoleAll("[EPI] Finale started and over threshold");
|
PrintToConsoleAll("[EPI] Finale started and over threshold");
|
||||||
|
@ -822,10 +818,9 @@ public Action L4D2_OnChangeFinaleStage(int &finaleType, const char[] arg) {
|
||||||
PrintToConsoleAll("[EPI] First tank stage has started");
|
PrintToConsoleAll("[EPI] First tank stage has started");
|
||||||
} else if(g_finaleStage == Stage_FinaleTank1) {
|
} else if(g_finaleStage == Stage_FinaleTank1) {
|
||||||
g_finaleStage = Stage_FinaleTank2;
|
g_finaleStage = Stage_FinaleTank2;
|
||||||
PrintToConsoleAll("[EPI] Second stage started, waiting for tank");
|
PrintToConsoleAll("[EPI] Second tank stage started. Waiting for tank");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Plugin_Continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Event_TankSpawn(Event event, const char[] name, bool dontBroadcast) {
|
void Event_TankSpawn(Event event, const char[] name, bool dontBroadcast) {
|
||||||
|
@ -962,7 +957,7 @@ void Event_PlayerFirstSpawn(Event event, const char[] name, bool dontBroadcast)
|
||||||
// New client has connected, late on the first chapter or on any other chapter
|
// New client has connected, late on the first chapter or on any other chapter
|
||||||
// If 5 survivors, then set them up, TP them.
|
// If 5 survivors, then set them up, TP them.
|
||||||
if(g_realSurvivorCount > 4) {
|
if(g_realSurvivorCount > 4) {
|
||||||
CreateTimer(0.1, Timer_SetupNewClient, userid);
|
CreateTimer(0.2, Timer_SetupNewClient, userid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -990,7 +985,6 @@ void Event_PlayerSpawn(Event event, const char[] name, bool dontBroadcast) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CreateTimer(0.5, Timer_GiveClientKit, userid);
|
CreateTimer(0.5, Timer_GiveClientKit, userid);
|
||||||
SDKHook(client, SDKHook_WeaponEquip, Event_Pickup);
|
|
||||||
}
|
}
|
||||||
TryStartHud();
|
TryStartHud();
|
||||||
UpdatePlayerInventory(client);
|
UpdatePlayerInventory(client);
|
||||||
|
@ -1005,9 +999,10 @@ void Event_PlayerDisconnect(Event event, const char[] name, bool dontBroadcast)
|
||||||
playerData[client].nameCache[0] = '\0';
|
playerData[client].nameCache[0] = '\0';
|
||||||
PrintToServer("debug: Player (index %d, uid %d) now pending empty", client, client, userid);
|
PrintToServer("debug: Player (index %d, uid %d) now pending empty", client, client, userid);
|
||||||
CreateTimer(cvDropDisconnectTime.FloatValue, Timer_DropSurvivor, client);
|
CreateTimer(cvDropDisconnectTime.FloatValue, Timer_DropSurvivor, client);
|
||||||
if(g_saveTimer[client] != null)
|
|
||||||
delete g_saveTimer[client];
|
|
||||||
}
|
}
|
||||||
|
if(g_saveTimer[client] != null)
|
||||||
|
delete g_saveTimer[client];
|
||||||
}
|
}
|
||||||
|
|
||||||
void Event_PlayerInfo(Event event, const char[] name, bool dontBroadcast) {
|
void Event_PlayerInfo(Event event, const char[] name, bool dontBroadcast) {
|
||||||
|
@ -1328,7 +1323,7 @@ public void OnMapEnd() {
|
||||||
public void Event_RoundFreezeEnd(Event event, const char[] name, bool dontBroadcast) {
|
public void Event_RoundFreezeEnd(Event event, const char[] name, bool dontBroadcast) {
|
||||||
CreateTimer(50.0, Timer_Populate);
|
CreateTimer(50.0, Timer_Populate);
|
||||||
}
|
}
|
||||||
public Action Timer_Populate(Handle h) {
|
Action Timer_Populate(Handle h) {
|
||||||
PopulateItems();
|
PopulateItems();
|
||||||
return Plugin_Continue;
|
return Plugin_Continue;
|
||||||
|
|
||||||
|
@ -1368,13 +1363,12 @@ public void EntityOutput_OnStartTouchSaferoom(const char[] output, int caller, i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Action Event_RoundEnd(Event event, const char[] name, bool dontBroadcast) {
|
void Event_RoundEnd(Event event, const char[] name, bool dontBroadcast) {
|
||||||
if(!g_isFailureRound) g_isFailureRound = true;
|
if(!g_isFailureRound) g_isFailureRound = true;
|
||||||
g_areItemsPopulated = false;
|
g_areItemsPopulated = false;
|
||||||
return Plugin_Continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Action Event_MapTransition(Event event, const char[] name, bool dontBroadcast) {
|
void Event_MapTransition(Event event, const char[] name, bool dontBroadcast) {
|
||||||
#if defined DEBUG
|
#if defined DEBUG
|
||||||
PrintToServer("Map transition | %d Extra Kits", g_extraKitsAmount);
|
PrintToServer("Map transition | %d Extra Kits", g_extraKitsAmount);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1383,19 +1377,6 @@ public Action Event_MapTransition(Event event, const char[] name, bool dontBroad
|
||||||
// Update g_survivorCount, people may have dipped right before transition
|
// Update g_survivorCount, people may have dipped right before transition
|
||||||
UpdateSurvivorCount();
|
UpdateSurvivorCount();
|
||||||
g_prevPlayerCount = g_survivorCount;
|
g_prevPlayerCount = g_survivorCount;
|
||||||
return Plugin_Continue;
|
|
||||||
}
|
|
||||||
//TODO: Possibly hacky logic of on third different ent id picked up, in short timespan, detect as set of 4 (pills, kits) & give extra
|
|
||||||
public Action Event_Pickup(int client, int weapon) {
|
|
||||||
static char name[32];
|
|
||||||
GetEntityClassname(weapon, name, sizeof(name));
|
|
||||||
if(StrEqual(name, "weapon_first_aid_kit", true)) {
|
|
||||||
if(playerData[client].itemGiven) return Plugin_Continue;
|
|
||||||
if((L4D_IsInFirstCheckpoint(client) || L4D_IsInLastCheckpoint(client)) && UseExtraKit(client)) {
|
|
||||||
return Plugin_Handled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Plugin_Continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnEntityCreated(int entity, const char[] classname) {
|
public void OnEntityCreated(int entity, const char[] classname) {
|
||||||
|
@ -1416,7 +1397,7 @@ public void OnEntityCreated(int entity, const char[] classname) {
|
||||||
|
|
||||||
//TODO: Implement extra kit amount to this
|
//TODO: Implement extra kit amount to this
|
||||||
//TODO: Possibly check ammo stash and kit (relv. distance). Would fire on Last Stand 2nd .
|
//TODO: Possibly check ammo stash and kit (relv. distance). Would fire on Last Stand 2nd .
|
||||||
public Action Hook_CabinetItemSpawn(int entity) {
|
Action Hook_CabinetItemSpawn(int entity) {
|
||||||
int cabinet = FindNearestEntityInRange(entity, "prop_health_cabinet", 60.0);
|
int cabinet = FindNearestEntityInRange(entity, "prop_health_cabinet", 60.0);
|
||||||
if(cabinet > 0) {
|
if(cabinet > 0) {
|
||||||
int ci = FindCabinetIndex(cabinet);
|
int ci = FindCabinetIndex(cabinet);
|
||||||
|
@ -1432,11 +1413,10 @@ public Action Hook_CabinetItemSpawn(int entity) {
|
||||||
}
|
}
|
||||||
//If Cabinet is full, spawner can not be a part of cabinet and is ignored.
|
//If Cabinet is full, spawner can not be a part of cabinet and is ignored.
|
||||||
}
|
}
|
||||||
return Plugin_Continue;
|
return Plugin_Handled;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Action Hook_CabinetSpawn(int entity) {
|
Action Hook_CabinetSpawn(int entity) {
|
||||||
for(int i = 0; i < sizeof(cabinets); i++) {
|
for(int i = 0; i < sizeof(cabinets); i++) {
|
||||||
if(cabinets[i].id == 0) {
|
if(cabinets[i].id == 0) {
|
||||||
cabinets[i].id = entity;
|
cabinets[i].id = entity;
|
||||||
|
@ -1444,11 +1424,10 @@ public Action Hook_CabinetSpawn(int entity) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PrintDebug(DEBUG_SPAWNLOGIC, "Adding cabinet %d", entity);
|
PrintDebug(DEBUG_SPAWNLOGIC, "Adding cabinet %d", entity);
|
||||||
return Plugin_Continue;
|
return Plugin_Handled;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Action OnUpgradePackUse(int entity, int activator, int caller, UseType type, float value) {
|
Action OnUpgradePackUse(int entity, int activator, int caller, UseType type, float value) {
|
||||||
if (entity > 2048 || entity <= MaxClients || !IsValidEntity(entity)) return Plugin_Continue;
|
if (entity > 2048 || entity <= MaxClients || !IsValidEntity(entity)) return Plugin_Continue;
|
||||||
|
|
||||||
int primaryWeapon = GetPlayerWeaponSlot(activator, 0);
|
int primaryWeapon = GetPlayerWeaponSlot(activator, 0);
|
||||||
|
@ -1520,18 +1499,7 @@ public Action Hook_Use(int entity, int activator, int caller, UseType type, floa
|
||||||
Prioritize first aid kits somehow? Or split two groups: "utility" (throwables, kits, pill/shots), and "weapon" (all other spawns)
|
Prioritize first aid kits somehow? Or split two groups: "utility" (throwables, kits, pill/shots), and "weapon" (all other spawns)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public Action Timer_ResetAmmoPack(Handle h, int entity) {
|
Action Timer_OpenSaferoomDoor(Handle h) {
|
||||||
if(IsValidEntity(entity)) {
|
|
||||||
int index = g_ammoPacks.FindValue(entity, AMMOPACK_ENTID);
|
|
||||||
if(index == -1) return Plugin_Continue;
|
|
||||||
|
|
||||||
ArrayList clients = g_ammoPacks.Get(index, AMMOPACK_USERS);
|
|
||||||
clients.Clear();
|
|
||||||
}
|
|
||||||
return Plugin_Continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Action Timer_OpenSaferoomDoor(Handle h) {
|
|
||||||
UnlockDoor(1);
|
UnlockDoor(1);
|
||||||
return Plugin_Continue;
|
return Plugin_Continue;
|
||||||
}
|
}
|
||||||
|
@ -1770,14 +1738,12 @@ Action Timer_SaveInventory(Handle h, int userid) {
|
||||||
int client = GetClientOfUserId(userid);
|
int client = GetClientOfUserId(userid);
|
||||||
if(client > 0) {
|
if(client > 0) {
|
||||||
// Force save to bypass our timeout
|
// Force save to bypass our timeout
|
||||||
g_saveTimer[client] = null;
|
|
||||||
SaveInventory(client, true);
|
SaveInventory(client, true);
|
||||||
}
|
}
|
||||||
return Plugin_Stop;
|
return Plugin_Stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveInventory(int client, bool force = false) {
|
void SaveInventory(int client, bool force = false) {
|
||||||
// TODO: dont save during join time
|
|
||||||
int time = GetTime();
|
int time = GetTime();
|
||||||
if(!force) {
|
if(!force) {
|
||||||
if(time - playerData[client].joinTime < MIN_JOIN_TIME) return;
|
if(time - playerData[client].joinTime < MIN_JOIN_TIME) return;
|
||||||
|
@ -1787,6 +1753,8 @@ void SaveInventory(int client, bool force = false) {
|
||||||
if(g_saveTimer[client] != null)
|
if(g_saveTimer[client] != null)
|
||||||
delete g_saveTimer[client];
|
delete g_saveTimer[client];
|
||||||
g_saveTimer[client] = CreateTimer(INV_SAVE_TIME, Timer_SaveInventory, GetClientUserId(client));
|
g_saveTimer[client] = CreateTimer(INV_SAVE_TIME, Timer_SaveInventory, GetClientUserId(client));
|
||||||
|
} else {
|
||||||
|
g_saveTimer[client] = null;
|
||||||
}
|
}
|
||||||
PlayerInventory inventory;
|
PlayerInventory inventory;
|
||||||
inventory.timestamp = time;
|
inventory.timestamp = time;
|
||||||
|
@ -1803,8 +1771,12 @@ void SaveInventory(int client, bool force = false) {
|
||||||
for(int i = 5; i >= 0; i--) {
|
for(int i = 5; i >= 0; i--) {
|
||||||
weapon = GetPlayerWeaponSlot(client, i);
|
weapon = GetPlayerWeaponSlot(client, i);
|
||||||
inventory.itemID[i] = IdentifyWeapon(weapon);
|
inventory.itemID[i] = IdentifyWeapon(weapon);
|
||||||
|
// If slot 1 is melee, get the melee ID
|
||||||
|
if(i == 1 && inventory.itemID[i] == WEPID_MELEE) {
|
||||||
|
inventory.meleeID = IdentifyMeleeWeapon(weapon);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(inventory.itemID[0] != WEPID_MELEE && inventory.itemID[0] != WEPID_NONE)
|
if(inventory.itemID[0] != WEPID_NONE)
|
||||||
inventory.lasers = GetEntProp(weapon, Prop_Send, "m_upgradeBitVec") == 4;
|
inventory.lasers = GetEntProp(weapon, Prop_Send, "m_upgradeBitVec") == 4;
|
||||||
|
|
||||||
GetClientAuthId(client, AuthId_Steam3, buffer, sizeof(buffer));
|
GetClientAuthId(client, AuthId_Steam3, buffer, sizeof(buffer));
|
||||||
|
@ -1827,10 +1799,11 @@ void RestoreInventory(int client, PlayerInventory inventory) {
|
||||||
for(int i = 5; i >= 0; i--) {
|
for(int i = 5; i >= 0; i--) {
|
||||||
WeaponId id = inventory.itemID[i];
|
WeaponId id = inventory.itemID[i];
|
||||||
if(id != WEPID_NONE) {
|
if(id != WEPID_NONE) {
|
||||||
if(id == WEPID_MELEE)
|
if(id == WEPID_MELEE) {
|
||||||
GetWeaponName(id, buffer, sizeof(buffer));
|
GetWeaponName(id, buffer, sizeof(buffer));
|
||||||
else
|
} else {
|
||||||
GetMeleeWeaponName(id, buffer, sizeof(buffer));
|
GetMeleeWeaponName(inventory.meleeID, buffer, sizeof(buffer));
|
||||||
|
}
|
||||||
weapon = GiveClientWeapon(client, buffer);
|
weapon = GiveClientWeapon(client, buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1872,7 +1845,6 @@ bool DoesInventoryDiffer(int client) {
|
||||||
return currentPrimary != storedPrimary || currentSecondary != storedSecondary;
|
return currentPrimary != storedPrimary || currentSecondary != storedSecondary;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: disable by cvar as well (replace abm_autohard)
|
|
||||||
bool IsEPIActive() {
|
bool IsEPIActive() {
|
||||||
return g_epiEnabled;
|
return g_epiEnabled;
|
||||||
}
|
}
|
||||||
|
@ -1908,7 +1880,7 @@ void UpdateSurvivorCount() {
|
||||||
}
|
}
|
||||||
g_survivorCount = countTotal;
|
g_survivorCount = countTotal;
|
||||||
g_realSurvivorCount = countReal;
|
g_realSurvivorCount = countReal;
|
||||||
PrintDebug(DEBUG_GENERIC, "UpdateSurvivorCount: total=%d real=%d active=%d", countTotal, countReal, countActive);
|
// PrintDebug(DEBUG_GENERIC, "UpdateSurvivorCount: total=%d real=%d active=%d", countTotal, countReal, countActive);
|
||||||
// Temporarily for now use g_realSurvivorCount, as players joining have a brief second where they are 5 players
|
// Temporarily for now use g_realSurvivorCount, as players joining have a brief second where they are 5 players
|
||||||
|
|
||||||
// 1 = 5+ official
|
// 1 = 5+ official
|
||||||
|
|
|
@ -93,6 +93,7 @@ public void OnPluginStart() {
|
||||||
GetEntPropString(entity, Prop_Data, "m_iName", targetName, sizeof(targetName));
|
GetEntPropString(entity, Prop_Data, "m_iName", targetName, sizeof(targetName));
|
||||||
if(StrContains(targetName, "l4d2_hats_") == 0) {
|
if(StrContains(targetName, "l4d2_hats_") == 0) {
|
||||||
createdWalls.Push(EntIndexToEntRef(entity));
|
createdWalls.Push(EntIndexToEntRef(entity));
|
||||||
|
SDKHook(entity, SDKHook_Use, OnWallClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -563,6 +563,13 @@ public Action Timer_RemoveGlow(Handle h, int userid) {
|
||||||
return Plugin_Handled;
|
return Plugin_Handled;
|
||||||
}
|
}
|
||||||
GameState prevState;
|
GameState prevState;
|
||||||
|
|
||||||
|
// #define HEARTBEAT_NEAR_DIST 1_000_000
|
||||||
|
// #define HEARTBEAT_CLOSE_DIST 250_000
|
||||||
|
|
||||||
|
#define HEARTBEAT_NEAR_DIST 1000
|
||||||
|
#define HEARTBEAT_CLOSE_DIST 300
|
||||||
|
|
||||||
public Action Timer_Music(Handle h) {
|
public Action Timer_Music(Handle h) {
|
||||||
static float seekerLoc[3];
|
static float seekerLoc[3];
|
||||||
static float playerLoc[3];
|
static float playerLoc[3];
|
||||||
|
@ -586,13 +593,14 @@ public Action Timer_Music(Handle h) {
|
||||||
for(int i = 1; i <= MaxClients; i++) {
|
for(int i = 1; i <= MaxClients; i++) {
|
||||||
if(IsClientConnected(i) && IsClientInGame(i) && i != currentSeeker) {
|
if(IsClientConnected(i) && IsClientInGame(i) && i != currentSeeker) {
|
||||||
playerCount++;
|
playerCount++;
|
||||||
GetClientAbsOrigin(i, playerLoc);
|
// GetClientAbsOrigin(i, playerLoc);
|
||||||
float dist = GetVectorDistance(seekerLoc, playerLoc, true);
|
// float dist = GetVectorDistance(seekerLoc, playerLoc, true);
|
||||||
if(dist <= 250000.0) {
|
float dist = GetFlowDistance(currentSeeker, i);
|
||||||
|
if(dist <= HEARTBEAT_CLOSE_DIST) {
|
||||||
StopSound(i, SNDCHAN_AUTO, SOUND_SUSPENSE_1);
|
StopSound(i, SNDCHAN_AUTO, SOUND_SUSPENSE_1);
|
||||||
EmitSoundToClient(i, SOUND_SUSPENSE_1_FAST, i, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_CHANGEPITCH, 1.0, 100, currentSeeker, seekerLoc, playerLoc, true);
|
EmitSoundToClient(i, SOUND_SUSPENSE_1_FAST, i, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_CHANGEPITCH, 1.0, 100, currentSeeker, seekerLoc, playerLoc, true);
|
||||||
isNearbyPlaying[i] = true;
|
isNearbyPlaying[i] = true;
|
||||||
} else if(dist <= 1000000.0) {
|
} else if(dist <= HEARTBEAT_CLOSE_DIST) {
|
||||||
EmitSoundToClient(i, SOUND_SUSPENSE_1, i, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_CHANGEPITCH, 0.4, 90, currentSeeker, seekerLoc, playerLoc, true);
|
EmitSoundToClient(i, SOUND_SUSPENSE_1, i, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_CHANGEPITCH, 0.4, 90, currentSeeker, seekerLoc, playerLoc, true);
|
||||||
isNearbyPlaying[i] = true;
|
isNearbyPlaying[i] = true;
|
||||||
StopSound(i, SNDCHAN_AUTO, SOUND_SUSPENSE_1_FAST);
|
StopSound(i, SNDCHAN_AUTO, SOUND_SUSPENSE_1_FAST);
|
||||||
|
@ -605,6 +613,12 @@ public Action Timer_Music(Handle h) {
|
||||||
}
|
}
|
||||||
return Plugin_Continue;
|
return Plugin_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float GetFlowDistance(int survivorA, int survivorB) {
|
||||||
|
return FloatAbs(L4D2Direct_GetFlowDistance(survivorA) - L4D2Direct_GetFlowDistance(survivorB));
|
||||||
|
}
|
||||||
|
|
||||||
public Action Timer_RoundStart(Handle h) {
|
public Action Timer_RoundStart(Handle h) {
|
||||||
PrintToServer("[H&S] Running round entity tweaks");
|
PrintToServer("[H&S] Running round entity tweaks");
|
||||||
CreateTimer(0.1, Timer_CheckWeapons);
|
CreateTimer(0.1, Timer_CheckWeapons);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue