diff --git a/addons/sourcemod/plugins/confoglcompmod.smx b/addons/sourcemod/plugins/confoglcompmod.smx index 19b14ed31..30c28bb92 100644 Binary files a/addons/sourcemod/plugins/confoglcompmod.smx and b/addons/sourcemod/plugins/confoglcompmod.smx differ diff --git a/addons/sourcemod/scripting/archive/confoglcompmod.sp b/addons/sourcemod/scripting/archive/confoglcompmod.sp new file mode 100644 index 000000000..f02d13bd8 --- /dev/null +++ b/addons/sourcemod/scripting/archive/confoglcompmod.sp @@ -0,0 +1,157 @@ +#pragma semicolon 1 + +#if defined(AUTOVERSION) +#include "version.inc" +#else +#define PLUGIN_VERSION "2.2.4" +#endif + +#if !defined(DEBUG_ALL) +#define DEBUG_ALL 0 +#endif + +#include +#include +#include +#include +#include +#include "includes/constants.sp" +#include "includes/functions.sp" +#include "includes/debug.sp" +#include "includes/survivorindex.sp" +#include "includes/configs.sp" +#include "includes/customtags.inc" + +#include "modules/MapInfo.sp" +#include "modules/WeaponInformation.sp" +#include "modules/ReqMatch.sp" +#include "modules/CvarSettings.sp" +#include "modules/GhostTank.sp" +#include "modules/WaterSlowdown.sp" +#include "modules/UnreserveLobby.sp" +//#include "modules/GhostWarp.sp" +#include "modules/UnprohibitBosses.sp" +#include "modules/PasswordSystem.sp" +#include "modules/BotKick.sp" +//#include "modules/EntityRemover.sp" +#include "modules/ScoreMod.sp" +#include "modules/FinaleSpawn.sp" +#include "modules/BossSpawning.sp" +//#include "modules/WeaponCustomization.sp" +#include "modules/l4dt_forwards.sp" +#include "modules/ClientSettings.sp" +#include "modules/ItemTracking.sp" +//#include "modules/SpectatorHud.sp" + +public Plugin:myinfo = +{ + name = "Confogl's Competitive Mod", + author = "Confogl Team", + description = "A competitive mod for L4D2", + version = PLUGIN_VERSION, + url = "http://confogl.googlecode.com/" +} + +public OnPluginStart() +{ + Debug_OnModuleStart(); + Configs_OnModuleStart(); + MI_OnModuleStart(); + SI_OnModuleStart(); + WI_OnModuleStart(); + + RM_OnModuleStart(); + + CVS_OnModuleStart(); + PS_OnModuleStart(); + UL_OnModuleStart(); + + //ER_OnModuleStart(); + //GW_OnModuleStart(); + WS_OnModuleStart(); + GT_OnModuleStart(); + UB_OnModuleStart(); + + BK_OnModuleStart(); + + SM_OnModuleStart(); + FS_OnModuleStart(); + BS_OnModuleStart(); + //WC_OnModuleStart(); + CLS_OnModuleStart(); + IT_OnModuleStart(); + //SH_OnModuleStart(); + + AddCustomServerTag("confogl", true); +} + +public APLRes:AskPluginLoad2(Handle:myself, bool:late, String:error[], err_max) +{ + RM_APL(); + Configs_APL(); + MI_APL(); + RegPluginLibrary("confogl"); +} + +public OnPluginEnd() +{ + CVS_OnModuleEnd(); + PS_OnModuleEnd(); + //ER_OnModuleEnd(); + SM_OnModuleEnd(); + + WS_OnModuleEnd(); + RemoveCustomServerTag("confogl"); +} + +public OnGameFrame() +{ + WS_OnGameFrame(); +} + +public OnMapStart() +{ + MI_OnMapStart(); + RM_OnMapStart(); + + SM_OnMapStart(); + BS_OnMapStart(); + IT_OnMapStart(); +} + +public OnMapEnd() +{ + MI_OnMapEnd(); + WI_OnMapEnd(); + PS_OnMapEnd(); + WS_OnMapEnd(); +} + +public OnConfigsExecuted() +{ + CVS_OnConfigsExecuted(); +} + +public OnClientDisconnect(client) +{ + RM_OnClientDisconnect(client); + //GT_OnClientDisconnect(client); + //SH_OnClientDisconnect(client); +} + +public OnClientPutInServer(client) +{ + RM_OnClientPutInServer(); + UL_OnClientPutInServer(); + PS_OnClientPutInServer(client); +} + +/*public Action:OnPlayerRunCmd(client, &buttons, &impulse, Float:vel[3], Float:angles[3], &weapon) +{ + if(GW_OnPlayerRunCmd(client, buttons)) + { + return Plugin_Handled; + } + + return Plugin_Continue; +}*/ diff --git a/addons/sourcemod/scripting/archive/include/confogl.inc b/addons/sourcemod/scripting/archive/include/confogl.inc new file mode 100644 index 000000000..064fed3fe --- /dev/null +++ b/addons/sourcemod/scripting/archive/include/confogl.inc @@ -0,0 +1,169 @@ +/* * + * ============================================================================= + * Confogl.inc + * Confogl (C)2011 Confogl Team + * ============================================================================= + * + * This file is part of the Confogl competitive L4D2 plugin suite. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, Confogl Team gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, Confogl Team grants + * this exception to all derivative works. Confogl defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + */ +#if defined _confogl_Included + #endinput +#endif +#define _confogl_Included + +/* Forwards */ + +/** + * @brief Called when matchmode is fully loaded, before map restart. + * @remarks Called just before confogl_plugins.cfg executes + * + * @noreturn + */ +forward void LGO_OnMatchModeLoaded(); + +/** + * @brief Called when matchmode is un-loaded, before map restart. + * @remarks Plugins are unloaded immediately after this call finishes + * + * @noreturn + */ +forward void LGO_OnMatchModeUnloaded(); + +/* NATIVES */ + +/** + * @brief Tells if a confogl match is currently running + * @remarks Formerly IsPluginEnabled() internally + * + * @return True if matchmode is loaded, false otherwise + */ +native bool LGO_IsMatchModeLoaded(); + +/** + * @brief Build a filepath relative to the current running config. + * @remarks Should produce a path in cfg/cfgogl/CONFIG/ or addons/sourcemod/configs/confogl + * + * @param buffer Buffer to write the path to + * @param maxlength Buffer size + * @param sFileName Name of the file to look for in the config + * @noreturn + */ +native void LGO_BuildConfigPath(char[] buffer, int maxlength, const char[] sFileName); + +/** + * @brief Execute a cfg file for the current config + * @remarks Should execute the named .cfg in cfg/ or cfg/cfgogl/CURRENT_CONFIG/ + * + * @param sFileName Name of the cfg file to execute + * @noreturn + */ +native void LGO_ExecuteConfigCfg(const char[] sFileName); + +/** + * @brief Tells if map data is available + * @remarks Map data should be available when any map is loaded, after OnMapStart() + * + * @return True if map data is available, false if it is not. + */ +native bool LGO_IsMapDataAvailable(); + +/** + * @brief Get an Int value from the MapInfo keyvalues for the current map with a specific key + * @remarks Mapinfo keyvalues is used to store static data about maps + * + * @param key Key to read the value from + * @param defvalue Default value to return if key is not found (default 0) + * @return Integer value for given key, or defvalue if key is not found + */ +native int LGO_GetMapValueInt(const char[] key, const int defvalue = 0); + +/** + * @brief Get a Float value from the MapInfo keyvalues for the current map with a specific key + * @remarks Mapinfo keyvalues is used to store static data about maps + * + * @param key Key to read the value from + * @param defvalue Default value to return if key is not found (default 0.0) + * @return Float value for given key, or defvalue if key is not found + */ +native float LGO_GetMapValueFloat(const char[] key, const float defvalue = 0.0); + +/** + * @brief Get a Vector from the MapInfo keyvalues for the current map with a specific key + * @remarks Mapinfo keyvalues is used to store static data about maps + * + * @param key Key to read the value from + * @param vector Vector to store the result in + * @param defvalue Default value to use if key is not found (default NULL_VECTOR) + * @noreturn + */ +native void LGO_GetMapValueVector(const char[] key, float vector[3], const float defvalue[3] = NULL_VECTOR); + +/** + * @brief Get a String from the MapInfo keyvalues for the current map with a specific key + * @remarks Mapinfo keyvalues is used to store static data about maps + * + * @param key Key to read the value from + * @param value String to store the result in + * @param maxlength Maximum length to write to the value String buffer + * @param defvalue Default value to use if key is not found (default "") + * @noreturn + */ +native void LGO_GetMapValueString(const char[] key, char[] value, int maxlength, const char[] defvalue = ""); + +/** + * @brief Copy a Subsection from the MapInfo keyvalues for the current map + * @remarks Mapinfo keyvalues is used to store static data about maps + * + * @param kv KeyValues Handle to copy to + * @param section Name of the section to copy + * @noreturn + */ +native void LGO_CopyMapSubsection(KeyValues kv, const char[] section); + +public SharedPlugin __pl_confogl = +{ + name = "confogl", + file = "confoglcompmod.smx", +#if defined REQUIRE_PLUGIN + required = 1, +#else + required = 0, +#endif +}; + +#if !defined REQUIRE_PLUGIN +public void __pl_confogl_SetNTVOptional() +{ + MarkNativeAsOptional("LGO_BuildConfigPath"); + MarkNativeAsOptional("LGO_ExecuteConfigCfg"); + MarkNativeAsOptional("LGO_IsMapDataAvailable"); + MarkNativeAsOptional("LGO_GetMapValueInt"); + MarkNativeAsOptional("LGO_GetMapValueFloat"); + MarkNativeAsOptional("LGO_GetMapValueVector"); + MarkNativeAsOptional("LGO_GetMapValueString"); + MarkNativeAsOptional("LGO_CopyMapSubsection"); + MarkNativeAsOptional("LGO_IsMatchModeLoaded"); +} +#endif diff --git a/addons/sourcemod/scripting/includes/configs.sp b/addons/sourcemod/scripting/archive/includes/configs.sp similarity index 100% rename from addons/sourcemod/scripting/includes/configs.sp rename to addons/sourcemod/scripting/archive/includes/configs.sp diff --git a/addons/sourcemod/scripting/includes/constants.sp b/addons/sourcemod/scripting/archive/includes/constants.sp similarity index 100% rename from addons/sourcemod/scripting/includes/constants.sp rename to addons/sourcemod/scripting/archive/includes/constants.sp diff --git a/addons/sourcemod/scripting/includes/customtags.inc b/addons/sourcemod/scripting/archive/includes/customtags.inc similarity index 100% rename from addons/sourcemod/scripting/includes/customtags.inc rename to addons/sourcemod/scripting/archive/includes/customtags.inc diff --git a/addons/sourcemod/scripting/includes/debug.sp b/addons/sourcemod/scripting/archive/includes/debug.sp similarity index 100% rename from addons/sourcemod/scripting/includes/debug.sp rename to addons/sourcemod/scripting/archive/includes/debug.sp diff --git a/addons/sourcemod/scripting/includes/functions.sp b/addons/sourcemod/scripting/archive/includes/functions.sp similarity index 100% rename from addons/sourcemod/scripting/includes/functions.sp rename to addons/sourcemod/scripting/archive/includes/functions.sp diff --git a/addons/sourcemod/scripting/includes/survivorindex.sp b/addons/sourcemod/scripting/archive/includes/survivorindex.sp similarity index 100% rename from addons/sourcemod/scripting/includes/survivorindex.sp rename to addons/sourcemod/scripting/archive/includes/survivorindex.sp diff --git a/addons/sourcemod/scripting/modules/BossSpawning.sp b/addons/sourcemod/scripting/archive/modules/BossSpawning.sp similarity index 100% rename from addons/sourcemod/scripting/modules/BossSpawning.sp rename to addons/sourcemod/scripting/archive/modules/BossSpawning.sp diff --git a/addons/sourcemod/scripting/modules/BotKick.sp b/addons/sourcemod/scripting/archive/modules/BotKick.sp similarity index 100% rename from addons/sourcemod/scripting/modules/BotKick.sp rename to addons/sourcemod/scripting/archive/modules/BotKick.sp diff --git a/addons/sourcemod/scripting/modules/CheckVersion.sp b/addons/sourcemod/scripting/archive/modules/CheckVersion.sp similarity index 100% rename from addons/sourcemod/scripting/modules/CheckVersion.sp rename to addons/sourcemod/scripting/archive/modules/CheckVersion.sp diff --git a/addons/sourcemod/scripting/modules/ClientSettings.sp b/addons/sourcemod/scripting/archive/modules/ClientSettings.sp similarity index 100% rename from addons/sourcemod/scripting/modules/ClientSettings.sp rename to addons/sourcemod/scripting/archive/modules/ClientSettings.sp diff --git a/addons/sourcemod/scripting/modules/CvarSettings.sp b/addons/sourcemod/scripting/archive/modules/CvarSettings.sp similarity index 100% rename from addons/sourcemod/scripting/modules/CvarSettings.sp rename to addons/sourcemod/scripting/archive/modules/CvarSettings.sp diff --git a/addons/sourcemod/scripting/modules/EntityRemover.sp b/addons/sourcemod/scripting/archive/modules/EntityRemover.sp similarity index 100% rename from addons/sourcemod/scripting/modules/EntityRemover.sp rename to addons/sourcemod/scripting/archive/modules/EntityRemover.sp diff --git a/addons/sourcemod/scripting/modules/FinaleSpawn.sp b/addons/sourcemod/scripting/archive/modules/FinaleSpawn.sp similarity index 100% rename from addons/sourcemod/scripting/modules/FinaleSpawn.sp rename to addons/sourcemod/scripting/archive/modules/FinaleSpawn.sp diff --git a/addons/sourcemod/scripting/modules/GhostTank.sp b/addons/sourcemod/scripting/archive/modules/GhostTank.sp similarity index 100% rename from addons/sourcemod/scripting/modules/GhostTank.sp rename to addons/sourcemod/scripting/archive/modules/GhostTank.sp diff --git a/addons/sourcemod/scripting/modules/GhostWarp.sp b/addons/sourcemod/scripting/archive/modules/GhostWarp.sp similarity index 100% rename from addons/sourcemod/scripting/modules/GhostWarp.sp rename to addons/sourcemod/scripting/archive/modules/GhostWarp.sp diff --git a/addons/sourcemod/scripting/modules/ItemTracking.sp b/addons/sourcemod/scripting/archive/modules/ItemTracking.sp similarity index 100% rename from addons/sourcemod/scripting/modules/ItemTracking.sp rename to addons/sourcemod/scripting/archive/modules/ItemTracking.sp diff --git a/addons/sourcemod/scripting/modules/MapInfo.sp b/addons/sourcemod/scripting/archive/modules/MapInfo.sp similarity index 100% rename from addons/sourcemod/scripting/modules/MapInfo.sp rename to addons/sourcemod/scripting/archive/modules/MapInfo.sp diff --git a/addons/sourcemod/scripting/modules/PasswordSystem.sp b/addons/sourcemod/scripting/archive/modules/PasswordSystem.sp similarity index 100% rename from addons/sourcemod/scripting/modules/PasswordSystem.sp rename to addons/sourcemod/scripting/archive/modules/PasswordSystem.sp diff --git a/addons/sourcemod/scripting/modules/ReqMatch.sp b/addons/sourcemod/scripting/archive/modules/ReqMatch.sp similarity index 100% rename from addons/sourcemod/scripting/modules/ReqMatch.sp rename to addons/sourcemod/scripting/archive/modules/ReqMatch.sp diff --git a/addons/sourcemod/scripting/modules/ScoreMod.sp b/addons/sourcemod/scripting/archive/modules/ScoreMod.sp similarity index 100% rename from addons/sourcemod/scripting/modules/ScoreMod.sp rename to addons/sourcemod/scripting/archive/modules/ScoreMod.sp diff --git a/addons/sourcemod/scripting/modules/SpectatorHud.sp b/addons/sourcemod/scripting/archive/modules/SpectatorHud.sp similarity index 100% rename from addons/sourcemod/scripting/modules/SpectatorHud.sp rename to addons/sourcemod/scripting/archive/modules/SpectatorHud.sp diff --git a/addons/sourcemod/scripting/modules/UnprohibitBosses.sp b/addons/sourcemod/scripting/archive/modules/UnprohibitBosses.sp similarity index 100% rename from addons/sourcemod/scripting/modules/UnprohibitBosses.sp rename to addons/sourcemod/scripting/archive/modules/UnprohibitBosses.sp diff --git a/addons/sourcemod/scripting/modules/UnreserveLobby.sp b/addons/sourcemod/scripting/archive/modules/UnreserveLobby.sp similarity index 100% rename from addons/sourcemod/scripting/modules/UnreserveLobby.sp rename to addons/sourcemod/scripting/archive/modules/UnreserveLobby.sp diff --git a/addons/sourcemod/scripting/modules/WaterSlowdown.sp b/addons/sourcemod/scripting/archive/modules/WaterSlowdown.sp similarity index 100% rename from addons/sourcemod/scripting/modules/WaterSlowdown.sp rename to addons/sourcemod/scripting/archive/modules/WaterSlowdown.sp diff --git a/addons/sourcemod/scripting/modules/WeaponCustomization.sp b/addons/sourcemod/scripting/archive/modules/WeaponCustomization.sp similarity index 100% rename from addons/sourcemod/scripting/modules/WeaponCustomization.sp rename to addons/sourcemod/scripting/archive/modules/WeaponCustomization.sp diff --git a/addons/sourcemod/scripting/modules/WeaponInformation.sp b/addons/sourcemod/scripting/archive/modules/WeaponInformation.sp similarity index 100% rename from addons/sourcemod/scripting/modules/WeaponInformation.sp rename to addons/sourcemod/scripting/archive/modules/WeaponInformation.sp diff --git a/addons/sourcemod/scripting/modules/l4dt_forwards.sp b/addons/sourcemod/scripting/archive/modules/l4dt_forwards.sp similarity index 100% rename from addons/sourcemod/scripting/modules/l4dt_forwards.sp rename to addons/sourcemod/scripting/archive/modules/l4dt_forwards.sp diff --git a/addons/sourcemod/scripting/confoglcompmod.sp b/addons/sourcemod/scripting/confoglcompmod.sp index f02d13bd8..dea9926ea 100644 --- a/addons/sourcemod/scripting/confoglcompmod.sp +++ b/addons/sourcemod/scripting/confoglcompmod.sp @@ -1,157 +1,494 @@ #pragma semicolon 1 +#pragma newdecls required -#if defined(AUTOVERSION) -#include "version.inc" -#else -#define PLUGIN_VERSION "2.2.4" -#endif +#define DEBUG_ALL 0 -#if !defined(DEBUG_ALL) -#define DEBUG_ALL 0 -#endif +#define PLUGIN_VERSION "2.3.0" + +// Using these macros, you can disable unnecessary modules, +// and they will not be included in the plugin at compile time, +// to disable, specify 0 for the required module. +#define MODULE_MAPINFO 1 //MapInfo +#define MODULE_WEAPONINFORMATION 1 //WeaponInformation +#define MODULE_REQMATCH 1 //ReqMatch +#define MODULE_CVARSETTINGS 1 //CvarSettings +#define MODULE_GHOSTTANK 1 //GhostTank +#define MODULE_UNRESERVELOBBY 1 //UnreserveLobby +#define MODULE_GHOSTWARP 0 //GhostWarp (plugin l4d2_ghost_warp replaces this functionality) +#define MODULE_PASSWORDSYSTEM 1 //PasswordSystem +#define MODULE_BOTKICK 1 //BotKick +#define MODULE_SCOREMOD 1 //ScoreMod +#define MODULE_FINALESPAWN 1 //FinaleSpawn +#define MODULE_BOSSSPAWNING 1 //BossSpawning +#define MODULE_CLIENTSETTINGS 1 //ClientSettings +#define MODULE_ITEMTRACKING 1 //ItemTracking +#define MODULE_WATERSLOWDOWN 1 //WaterSlowdown (config 'pmelite' uses it) +#define MODULE_UNPROHIBITBOSSES 0 //UnprohibitBosses (duplicate code, plugin 'bossspawningfix' does the same). +#define MODULE_ENTITYREMOVER 0 //EntityRemover (the same can be done with the extension 'stripper'). +#define MODULE_WEAPONCUSTOMIZATION 0 //WeaponCustomization (this is deprecated and disabled, plugin 'l4d_weapon_limits' does the same). #include #include #include #include #include -#include "includes/constants.sp" -#include "includes/functions.sp" -#include "includes/debug.sp" -#include "includes/survivorindex.sp" -#include "includes/configs.sp" -#include "includes/customtags.inc" - -#include "modules/MapInfo.sp" -#include "modules/WeaponInformation.sp" -#include "modules/ReqMatch.sp" -#include "modules/CvarSettings.sp" -#include "modules/GhostTank.sp" -#include "modules/WaterSlowdown.sp" -#include "modules/UnreserveLobby.sp" -//#include "modules/GhostWarp.sp" -#include "modules/UnprohibitBosses.sp" -#include "modules/PasswordSystem.sp" -#include "modules/BotKick.sp" -//#include "modules/EntityRemover.sp" -#include "modules/ScoreMod.sp" -#include "modules/FinaleSpawn.sp" -#include "modules/BossSpawning.sp" -//#include "modules/WeaponCustomization.sp" -#include "modules/l4dt_forwards.sp" -#include "modules/ClientSettings.sp" -#include "modules/ItemTracking.sp" -//#include "modules/SpectatorHud.sp" - -public Plugin:myinfo = +//#undef REQUIRE_PLUGIN +//#include //ItemTracking (commented out) + +#include "confoglcompmod/includes/constants.sp" +#include "confoglcompmod/includes/functions.sp" +#include "confoglcompmod/includes/debug.sp" +#include "confoglcompmod/includes/survivorindex.sp" +#include "confoglcompmod/includes/configs.sp" +#include "confoglcompmod/includes/customtags.sp" + +#if MODULE_MAPINFO + #include "confoglcompmod/MapInfo.sp" +#endif + +#if MODULE_WEAPONINFORMATION + #include "confoglcompmod/WeaponInformation.sp" +#endif + +#if MODULE_REQMATCH + #include "confoglcompmod/ReqMatch.sp" +#endif + +#if MODULE_CVARSETTINGS + #include "confoglcompmod/CvarSettings.sp" +#endif + +#if MODULE_GHOSTTANK + #include "confoglcompmod/GhostTank.sp" +#endif + +#if MODULE_UNRESERVELOBBY + #include "confoglcompmod/UnreserveLobby.sp" +#endif + +#if MODULE_GHOSTWARP + #include "confoglcompmod/GhostWarp.sp" +#endif + +#if MODULE_PASSWORDSYSTEM + #include "confoglcompmod/PasswordSystem.sp" +#endif + +#if MODULE_BOTKICK + #include "confoglcompmod/BotKick.sp" +#endif + +#if MODULE_SCOREMOD + #include "confoglcompmod/ScoreMod.sp" +#endif + +#if MODULE_FINALESPAWN + #include "confoglcompmod/FinaleSpawn.sp" +#endif + +#if MODULE_BOSSSPAWNING + #include "confoglcompmod/BossSpawning.sp" +#endif + +#if MODULE_CLIENTSETTINGS + #include "confoglcompmod/ClientSettings.sp" +#endif + +#if MODULE_ITEMTRACKING + #include "confoglcompmod/ItemTracking.sp" +#endif + +#if MODULE_WATERSLOWDOWN + #include "confoglcompmod/WaterSlowdown.sp" +#endif + +#if MODULE_UNPROHIBITBOSSES + #include "confoglcompmod/UnprohibitBosses.sp" +#endif + +#if MODULE_ENTITYREMOVER + #include "confoglcompmod/EntityRemover.sp" +#endif + +#if MODULE_WEAPONCUSTOMIZATION + #include "confoglcompmod/WeaponCustomization.sp" +#endif + +public Plugin myinfo = { name = "Confogl's Competitive Mod", - author = "Confogl Team", + author = "Confogl Team, A1m`", description = "A competitive mod for L4D2", version = PLUGIN_VERSION, - url = "http://confogl.googlecode.com/" -} - -public OnPluginStart() -{ - Debug_OnModuleStart(); - Configs_OnModuleStart(); - MI_OnModuleStart(); - SI_OnModuleStart(); - WI_OnModuleStart(); - - RM_OnModuleStart(); - - CVS_OnModuleStart(); - PS_OnModuleStart(); - UL_OnModuleStart(); - - //ER_OnModuleStart(); - //GW_OnModuleStart(); - WS_OnModuleStart(); - GT_OnModuleStart(); - UB_OnModuleStart(); - - BK_OnModuleStart(); - - SM_OnModuleStart(); - FS_OnModuleStart(); - BS_OnModuleStart(); - //WC_OnModuleStart(); - CLS_OnModuleStart(); - IT_OnModuleStart(); - //SH_OnModuleStart(); - - AddCustomServerTag("confogl", true); -} - -public APLRes:AskPluginLoad2(Handle:myself, bool:late, String:error[], err_max) -{ - RM_APL(); - Configs_APL(); - MI_APL(); + url = "https://github.com/L4D-Community/L4D2-Competitive-Framework" +}; + +public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) +{ + //Plugin functions + Configs_APL(); //configs + + //Modules +#if MODULE_REQMATCH + RM_APL(); //ReqMatch +#endif + +#if MODULE_MAPINFO + MI_APL(); //MapInfo +#endif + +#if MODULE_SCOREMOD + SM_APL(); +#endif + + //Other RegPluginLibrary("confogl"); + return APLRes_Success; +} + +public void OnPluginStart() +{ + //Plugin functions + Fns_OnModuleStart(); //functions + Debug_OnModuleStart(); //debug + Configs_OnModuleStart(); //configs + SI_OnModuleStart(); //survivorindex + CT_OnModuleStart(); //customtags + + //Modules +#if MODULE_MAPINFO + MI_OnModuleStart(); //MapInfo +#endif + +#if MODULE_WEAPONINFORMATION + WI_OnModuleStart(); //WeaponInformation +#endif + +#if MODULE_REQMATCH + RM_OnModuleStart(); //ReqMatch +#endif + +#if MODULE_CVARSETTINGS + CVS_OnModuleStart(); //CvarSettings +#endif + +#if MODULE_PASSWORDSYSTEM + PS_OnModuleStart(); //PasswordSystem +#endif + +#if MODULE_UNRESERVELOBBY + UL_OnModuleStart(); //UnreserveLobby +#endif + +#if MODULE_ENTITYREMOVER + ER_OnModuleStart(); //EntityRemover +#endif + +#if MODULE_GHOSTWARP + GW_OnModuleStart(); //GhostWarp +#endif + +#if MODULE_WATERSLOWDOWN + WS_OnModuleStart(); //WaterSlowdown +#endif + +#if MODULE_GHOSTTANK + GT_OnModuleStart(); //GhostTank +#endif + +#if MODULE_UNPROHIBITBOSSES + UB_OnModuleStart(); //UnprohibitBosses +#endif + +#if MODULE_BOTKICK + BK_OnModuleStart(); //BotKick +#endif + +#if MODULE_SCOREMOD + SM_OnModuleStart(); //ScoreMod +#endif + +#if MODULE_FINALESPAWN + FS_OnModuleStart(); //FinaleSpawn +#endif + +#if MODULE_BOSSSPAWNING + BS_OnModuleStart(); //BossSpawning +#endif + +#if MODULE_WEAPONCUSTOMIZATION + WC_OnModuleStart(); //WeaponCustomization +#endif + +#if MODULE_CLIENTSETTINGS + CLS_OnModuleStart(); //ClientSettings +#endif + +#if MODULE_ITEMTRACKING + IT_OnModuleStart(); //ItemTracking +#endif + + //Other + AddCustomServerTag("confogl"); } -public OnPluginEnd() +public void OnPluginEnd() { - CVS_OnModuleEnd(); - PS_OnModuleEnd(); - //ER_OnModuleEnd(); - SM_OnModuleEnd(); - - WS_OnModuleEnd(); + //Modules +#if MODULE_CVARSETTINGS + CVS_OnModuleEnd(); //CvarSettings +#endif + +#if MODULE_PASSWORDSYSTEM + PS_OnModuleEnd(); //PasswordSystem +#endif + +#if MODULE_ENTITYREMOVER + ER_OnModuleEnd(); //EntityRemover +#endif + +#if MODULE_SCOREMOD + SM_OnModuleEnd(); //ScoreMod +#endif + +#if MODULE_WATERSLOWDOWN + WS_OnModuleEnd(); //WaterSlowdown +#endif + +#if MODULE_MAPINFO + MI_OnModuleEnd(); //MapInfo +#endif + + //Other RemoveCustomServerTag("confogl"); } -public OnGameFrame() +#if MODULE_MAPINFO || MODULE_REQMATCH || MODULE_SCOREMOD || MODULE_BOSSSPAWNING || MODULE_ITEMTRACKING +public void OnMapStart() { - WS_OnGameFrame(); + //Modules +#if MODULE_MAPINFO + MI_OnMapStart(); //MapInfo +#endif + +#if MODULE_REQMATCH + RM_OnMapStart(); //ReqMatch +#endif + +#if MODULE_SCOREMOD + SM_OnMapStart(); //ScoreMod +#endif + +#if MODULE_BOSSSPAWNING + BS_OnMapStart(); //BossSpawning +#endif + +#if MODULE_ITEMTRACKING + IT_OnMapStart(); //ItemTracking +#endif +} +#endif + +#if MODULE_MAPINFO || MODULE_WEAPONINFORMATION || MODULE_PASSWORDSYSTEM || MODULE_WATERSLOWDOWN +public void OnMapEnd() +{ + //Modules +#if MODULE_MAPINFO + MI_OnMapEnd(); //MapInfo +#endif + +#if MODULE_WEAPONINFORMATION + WI_OnMapEnd(); //WeaponInformation +#endif + +#if MODULE_PASSWORDSYSTEM + PS_OnMapEnd(); //PasswordSystem +#endif + +#if MODULE_WATERSLOWDOWN + WS_OnMapEnd(); //WaterSlowdown +#endif +} +#endif + +#if MODULE_CVARSETTINGS +public void OnConfigsExecuted() +{ + //Modules + CVS_OnConfigsExecuted(); //CvarSettings +} +#endif + +#if MODULE_REQMATCH +public void OnClientDisconnect(int client) +{ + //Modules + RM_OnClientDisconnect(client); //ReqMatch } +#endif -public OnMapStart() +#if MODULE_BOTKICK +public bool OnClientConnect(int client, char[] rejectmsg, int maxlen) { - MI_OnMapStart(); - RM_OnMapStart(); - - SM_OnMapStart(); - BS_OnMapStart(); - IT_OnMapStart(); + //Modules + if (!BK_OnClientConnect(client)) { //BotKick + return false; + } + + return true; } +#endif -public OnMapEnd() +#if MODULE_REQMATCH || MODULE_UNRESERVELOBBY || MODULE_PASSWORDSYSTEM || MODULE_FINALESPAWN +public void OnClientPutInServer(int client) { - MI_OnMapEnd(); - WI_OnMapEnd(); - PS_OnMapEnd(); - WS_OnMapEnd(); + //Modules +#if MODULE_REQMATCH + RM_OnClientPutInServer(); //ReqMatch +#endif + +#if MODULE_UNRESERVELOBBY + UL_OnClientPutInServer(); //UnreserveLobby +#endif + +#if MODULE_PASSWORDSYSTEM + PS_OnClientPutInServer(client); //PasswordSystem +#endif + +#if MODULE_FINALESPAWN + FS_OnClientPutInServer(client); // FinaleSpawn +#endif } +#endif + +//Hot functions =) -public OnConfigsExecuted() +#if MODULE_WATERSLOWDOWN +public void OnGameFrame() { - CVS_OnConfigsExecuted(); + //Modules + WS_OnGameFrame(); //WaterSlowdown } +#endif -public OnClientDisconnect(client) +#if MODULE_GHOSTWARP +public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3], float angles[3], int &weapon, \ + int &subtype, int &cmdnum, int &tickcount, int &seed, int mouse[2]) { - RM_OnClientDisconnect(client); - //GT_OnClientDisconnect(client); - //SH_OnClientDisconnect(client); + //Modules + if (GW_OnPlayerRunCmd(client, buttons)) { //GhostWarp + return Plugin_Handled; + } + + return Plugin_Continue; } +#endif + +//Left4Dhooks or Left4Downtown functions -public OnClientPutInServer(client) +#if MODULE_GHOSTTANK +public Action L4D_OnCThrowActivate(int ability) { - RM_OnClientPutInServer(); - UL_OnClientPutInServer(); - PS_OnClientPutInServer(client); + //Modules + if (GT_OnCThrowActivate() == Plugin_Handled) { //GhostTank + return Plugin_Handled; + } + + return Plugin_Continue; } +#endif -/*public Action:OnPlayerRunCmd(client, &buttons, &impulse, Float:vel[3], Float:angles[3], &weapon) +#if MODULE_GHOSTTANK +public Action L4D_OnSpawnTank(const float vector[3], const float qangle[3]) { - if(GW_OnPlayerRunCmd(client, buttons)) - { + //Modules + if (GT_OnTankSpawn_Forward() == Plugin_Handled) { //GhostTank return Plugin_Handled; } - + return Plugin_Continue; -}*/ +} +#endif + +#if MODULE_BOSSSPAWNING +public void L4D_OnSpawnTank_Post(int client, const float vecPos[3], const float vecAng[3]) +{ + //Modules + BS_OnTankSpawnPost_Forward(); //BossSpawning +} +#endif + +#if MODULE_GHOSTTANK +public Action L4D_OnSpawnMob(int &amount) +{ + //Modules + if (GT_OnSpawnMob_Forward(amount) == Plugin_Handled) { //GhostTank + return Plugin_Handled; + } + + return Plugin_Continue; +} +#endif + +#if MODULE_GHOSTTANK +public Action L4D_OnTryOfferingTankBot(int tank_index, bool &enterStasis) +{ + //Modules + if (GT_OnTryOfferingTankBot(enterStasis) == Plugin_Handled) { //GhostTank + return Plugin_Handled; + } + + return Plugin_Continue; +} +#endif + +#if MODULE_UNPROHIBITBOSSES +public Action L4D_OnGetMissionVSBossSpawning(float &spawn_pos_min, float &spawn_pos_max, float &tank_chance, float &witch_chance) +{ + //Modules + if (UB_OnGetMissionVSBossSpawning() == Plugin_Handled) { //UnprohibitBosses + return Plugin_Handled; + } + + return Plugin_Continue; +} +#endif + +#if MODULE_UNPROHIBITBOSSES +public Action L4D_OnGetScriptValueInt(const char[] key, int &retVal) +{ + //Modules + if (UB_OnGetScriptValueInt(key, retVal) == Plugin_Handled) { //UnprohibitBosses + return Plugin_Handled; + } + + return Plugin_Continue; +} +#endif + +public Action L4D_OnFirstSurvivorLeftSafeArea(int client) +{ + if (IsPluginEnabled()) { + CreateTimer(0.1, OFSLA_ForceMobSpawnTimer); + } + + return Plugin_Continue; +} + +public Action OFSLA_ForceMobSpawnTimer(Handle hTimer) +{ + //Workaround to make tank horde blocking always work + //Makes the first horde always start 100s after survivors leave saferoom + static ConVar hCvarMobSpawnTimeMin = null; + static ConVar hCvarMobSpawnTimeMax = null; + + if (hCvarMobSpawnTimeMin == null) { + hCvarMobSpawnTimeMin = FindConVar("z_mob_spawn_min_interval_normal"); + hCvarMobSpawnTimeMax = FindConVar("z_mob_spawn_max_interval_normal"); + } + + float fRand = GetRandomFloat(hCvarMobSpawnTimeMin.FloatValue, hCvarMobSpawnTimeMax.FloatValue); + L4D2_CTimerStart(L4D2CT_MobSpawnTimer, fRand); + + return Plugin_Stop; +} diff --git a/addons/sourcemod/scripting/confoglcompmod/BossSpawning.sp b/addons/sourcemod/scripting/confoglcompmod/BossSpawning.sp new file mode 100644 index 000000000..5a225f1d6 --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/BossSpawning.sp @@ -0,0 +1,232 @@ +#if defined __boss_spawning_included + #endinput +#endif +#define __boss_spawning_included + +#define DEBUG_BS 0 +#define BS_MODULE_NAME "BossSpawning" + +#define MAX_TANKS 5 +#define MAX_WITCHES 5 +#define ROUND_MAX_COUNT 2 + +static char + BS_sMap[64] = "\0"; + +static bool + BS_bEnabled = true, + BS_bIsFirstRound = true, + BS_bDeleteWitches = false, + BS_bFinaleStarted = false, + BS_bExpectTankSpawn = false; + +static int + BS_iTankCount[ROUND_MAX_COUNT] = {0, ...}, + BS_iWitchCount[ROUND_MAX_COUNT] = {0, ...}; + +static float + BS_fTankSpawn[MAX_TANKS][3], + BS_fWitchSpawn[MAX_WITCHES][2][3]; + +static ConVar + BS_hEnabled = null; + +void BS_OnModuleStart() +{ + BS_hEnabled = CreateConVarEx("lock_boss_spawns", "1", "Enables forcing same coordinates for tank and witch spawns", _, true, 0.0, true, 1.0); + + BS_bEnabled = BS_hEnabled.BoolValue; + BS_hEnabled.AddChangeHook(BS_ConVarChange); + + HookEvent("tank_spawn", BS_TankSpawn); + HookEvent("witch_spawn", BS_WitchSpawn); + HookEvent("round_end", BS_RoundEnd, EventHookMode_PostNoCopy); + HookEvent("finale_start", BS_FinaleStart, EventHookMode_PostNoCopy); + + GetCurrentMap(BS_sMap, sizeof(BS_sMap)); +} + +void BS_OnMapStart() +{ + BS_bIsFirstRound = true; + BS_bFinaleStarted = false; + BS_bExpectTankSpawn = false; + + for (int i = 0; i < ROUND_MAX_COUNT; i++) { + BS_iTankCount[i] = 0; + BS_iWitchCount[i] = 0; + } + + GetCurrentMap(BS_sMap, sizeof(BS_sMap)); +} + +public void BS_ConVarChange(ConVar convar, const char[] oldValue, const char[] newValue) +{ + BS_bEnabled = BS_hEnabled.BoolValue; +} + +public void BS_WitchSpawn(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + if (!BS_bEnabled || !IsPluginEnabled()) { + return; + } + + int iWitch = hEvent.GetInt("witchid"); + + if (BS_bDeleteWitches) { + // Used to delete round2 extra witches, which spawn on round start instead of by flow + KillEntity(iWitch); + + return; + } + + // Can't track more witches if our witch array is full + if (BS_iWitchCount[view_as(!BS_bIsFirstRound)] >= MAX_WITCHES) { + Debug_LogError(BS_MODULE_NAME, "Failed to save a large number of witches to the array. Count: %d, Max: %d", \ + BS_iWitchCount[view_as(!BS_bIsFirstRound)], MAX_WITCHES); + return; + } + + if (BS_bIsFirstRound) { + // If it's the first round, track our witch. + GetEntPropVector(iWitch, Prop_Send, "m_vecOrigin", BS_fWitchSpawn[BS_iWitchCount[0]][0]); + GetEntPropVector(iWitch, Prop_Send, "m_angRotation", BS_fWitchSpawn[BS_iWitchCount[0]][1]); + BS_iWitchCount[0]++; + } else if (BS_iWitchCount[0] > BS_iWitchCount[1]) { + // Until we have found the same number of witches as from round1, teleport them to round1 locations + TeleportEntity(iWitch, BS_fWitchSpawn[BS_iWitchCount[1]][0], BS_fWitchSpawn[BS_iWitchCount[1]][1], NULL_VECTOR); + BS_iWitchCount[1]++; + } +} + +void BS_OnTankSpawnPost_Forward() +{ + if (BS_bEnabled && IsPluginEnabled()) { + BS_bExpectTankSpawn = true; + } +} + +public void BS_TankSpawn(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + if (!BS_bEnabled || !IsPluginEnabled()) { + return; + } + + // Don't touch tanks on finale events + if (BS_bFinaleStarted) { + return; + } + + // Stop if this isn't the first tank_spawn for this tank + if (!BS_bExpectTankSpawn) { + return; + } + + BS_bExpectTankSpawn = false; + + // Don't track tank spawns on c5m5 or tank can spawn behind other team. + if (strcmp(BS_sMap, "c5m5_bridge") == 0) { + return; + } + + int iTankClient = GetClientOfUserId(hEvent.GetInt("userid")); + + if (GetMapValueInt("tank_z_fix")) { + FixZDistance(iTankClient); // fix stuck tank spawns, ex c1m1 + } + + // If we reach MAX_TANKS, we don't have any room to store their locations + if (BS_iTankCount[view_as(!BS_bIsFirstRound)] >= MAX_TANKS) { + Debug_LogError(BS_MODULE_NAME, "Failed to save a large number of tanks to the array. Count: %d, Max: %d", \ + BS_iTankCount[view_as(!BS_bIsFirstRound)], MAX_TANKS); + return; + } + + if (DEBUG_BS || IsDebugEnabled()) { + LogMessage("[%s] Tracking this tank spawn. Currently, %d tanks", BS_MODULE_NAME, BS_iTankCount[view_as(!BS_bIsFirstRound)]); + } + + if (BS_bIsFirstRound) { + GetClientAbsOrigin(iTankClient, BS_fTankSpawn[BS_iTankCount[0]]); + if (DEBUG_BS || IsDebugEnabled()) { + LogMessage("[%s] Saving tank at %f %f %f", \ + BS_MODULE_NAME, BS_fTankSpawn[BS_iTankCount[0]][0], BS_fTankSpawn[BS_iTankCount[0]][1], BS_fTankSpawn[BS_iTankCount[0]][2]); + } + + BS_iTankCount[0]++; + } else if (BS_iTankCount[0] > BS_iTankCount[1]) { + TeleportEntity(iTankClient, BS_fTankSpawn[BS_iTankCount[1]], NULL_VECTOR, NULL_VECTOR); + + if (DEBUG_BS || IsDebugEnabled()) { + LogMessage("[%s] Teleporting tank to tank at %f %f %f", \ + BS_MODULE_NAME, BS_fTankSpawn[BS_iTankCount[1]][0], BS_fTankSpawn[BS_iTankCount[1]][1], BS_fTankSpawn[BS_iTankCount[1]][2]); + } + + BS_iTankCount[1]++; + } else if (DEBUG_BS || IsDebugEnabled()) { + LogMessage("[%s] Not first round and not acceptable tank", BS_MODULE_NAME); + LogMessage("[%s] IsFirstRound: %d R1Count: %d R2Count: %d", BS_MODULE_NAME, BS_bIsFirstRound, BS_iTankCount[0], BS_iTankCount[1]); + } +} + +public void BS_RoundEnd(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + BS_bIsFirstRound = false; + BS_bFinaleStarted = false; + + if (strcmp(BS_sMap, "c6m1_riverbank") == 0) { + BS_bDeleteWitches = false; + } else { + BS_bDeleteWitches = true; + + CreateTimer(5.0, BS_WitchTimerReset); + } +} + +public void BS_FinaleStart(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + BS_bFinaleStarted = true; +} + +public Action BS_WitchTimerReset(Handle hTimer) +{ + BS_bDeleteWitches = false; + + return Plugin_Stop; +} + +static void FixZDistance(int iTankClient) +{ + int index = 0; + float distance = 99999999999999.9; + float WarpToLocation[3], TankLocation[3], TempSurvivorLocation[3]; + GetClientAbsOrigin(iTankClient, TankLocation); + + if (DEBUG_BS || IsDebugEnabled()) { + LogMessage("[%s] tank z spawn check... Map: %s, Tank Location: %f, %f, %f", BS_MODULE_NAME, BS_sMap, TankLocation[0], TankLocation[1], TankLocation[2]); + } + + for (int i = 0; i < NUM_OF_SURVIVORS; i++) { + distance = GetMapValueFloat("max_tank_z", 99999999999999.9); + index = GetSurvivorIndex(i); + + if (index != 0 && IsValidEntity(index)) { + GetClientAbsOrigin(index, TempSurvivorLocation); + + if (DEBUG_BS || IsDebugEnabled()) { + LogMessage("[%s] Survivor %d Location: %f, %f, %f", BS_MODULE_NAME, i, TempSurvivorLocation[0], TempSurvivorLocation[1], TempSurvivorLocation[2]); + } + + if (FloatAbs(TempSurvivorLocation[2] - TankLocation[2]) > distance) { + GetMapValueVector("tank_warpto", WarpToLocation); + + if (!GetVectorLength(WarpToLocation, true)) { + LogMessage("[%s] tank_warpto missing from mapinfo.txt", BS_MODULE_NAME); + return; + } + + TeleportEntity(iTankClient, WarpToLocation, NULL_VECTOR, NULL_VECTOR); + } + } + } +} diff --git a/addons/sourcemod/scripting/confoglcompmod/BotKick.sp b/addons/sourcemod/scripting/confoglcompmod/BotKick.sp new file mode 100644 index 000000000..a8dd0ff92 --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/BotKick.sp @@ -0,0 +1,115 @@ +#if defined __bot_kick_included + #endinput +#endif +#define __bot_kick_included + +#define BK_MODULE_NAME "BotKick" + +#define CHECKALLOWEDTIME 0.1 +#define BOTREPLACEVALIDTIME 0.2 + +static const char InfectedNames[][] = +{ + "smoker", + "boomer", + "hunter", + "spitter", + "jockey", + "charger" +}; + +static int + BK_iEnable = 0, + BK_lastvalidbot = -1; + +static ConVar + BK_hEnable = null; + +void BK_OnModuleStart() +{ + BK_hEnable = CreateConVarEx( \ + "blockinfectedbots", \ + "1", \ + "Blocks infected bots from joining the game, minus when a tank spawns (1 allows bots from tank spawns, 2 removes all infected bots)", \ + _, true, 0.0, true, 2.0 \ + ); + + BK_iEnable = BK_hEnable.IntValue; + BK_hEnable.AddChangeHook(BK_ConVarChange); + + HookEvent("player_bot_replace", BK_PlayerBotReplace); +} + +public void BK_ConVarChange(ConVar hConVar, const char[] sOldValue, const char[] sNewValue) +{ + BK_iEnable = BK_hEnable.IntValue; +} + +bool BK_OnClientConnect(int iClient) +{ + if (BK_iEnable == 0 || !IsPluginEnabled() || !IsFakeClient(iClient)) { // If the BK_iEnable is 0, we don't do anything + return true; + } + + // If the client doesn't have a bot infected's name, let it in + if (IsInvalidInfected(iClient)) { + return true; + } + + if (BK_iEnable == 1 && GT_IsTankInPlay()) { // Bots only allowed to try to connect when there's a tank in play. + // Check this bot in CHECKALLOWEDTIME seconds to see if he's supposed to be allowed. + CreateTimer(CHECKALLOWEDTIME, BK_CheckInfBotReplace_Timer, iClient, TIMER_FLAG_NO_MAPCHANGE); + //BK_bAllowBot = false; + return true; + } + + KickClient(iClient, "[Confogl] Kicking infected bot..."); // If all else fails, bots arent allowed and must be kicked + + return false; +} + +public Action BK_CheckInfBotReplace_Timer(Handle hTimer, any iClient) +{ + if (iClient != BK_lastvalidbot && IsClientInGame(iClient) && IsFakeClient(iClient)) { + KickClient(iClient, "[Confogl] Kicking late infected bot..."); + } else { + BK_lastvalidbot = -1; + } + + return Plugin_Stop; +} + +public void BK_PlayerBotReplace(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + if (!GT_IsTankInPlay()) { + return; + } + + int iClient = GetClientOfUserId(hEvent.GetInt("player")); + + if (iClient > 0 && IsClientInGame(iClient) && GetClientTeam(iClient) == L4D2Team_Infected) { + BK_lastvalidbot = GetClientOfUserId(hEvent.GetInt("bot")); + CreateTimer(BOTREPLACEVALIDTIME, BK_CancelValidBot_Timer, _, TIMER_FLAG_NO_MAPCHANGE); + } +} + +public Action BK_CancelValidBot_Timer(Handle hTimer) +{ + BK_lastvalidbot = -1; + + return Plugin_Stop; +} + +static bool IsInvalidInfected(int iClient) +{ + char sBotName[11]; + GetClientName(iClient, sBotName, sizeof(sBotName)); + + for (int i = 0; i < sizeof(InfectedNames); i++) { + if (StrContains(sBotName, InfectedNames[i], false) != -1) { + return false; + } + } + + return true; +} diff --git a/addons/sourcemod/scripting/confoglcompmod/ClientSettings.sp b/addons/sourcemod/scripting/confoglcompmod/ClientSettings.sp new file mode 100644 index 000000000..a1685aebb --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/ClientSettings.sp @@ -0,0 +1,457 @@ +#if defined __client_settings_include + #endinput +#endif +#define __client_settings_include + +#define CLS_MODULE_NAME "ClientSettings" + +#define CLS_CVAR_MAXLEN 64 +#define CLIENT_CHECK_INTERVAL 5.0 + +enum /*CLSAction*/ +{ + CLSA_Kick = 0, + CLSA_Log +}; + +#if SOURCEMOD_V_MINOR > 9 +enum struct CLSEntry +{ + bool CLSE_hasMin; + float CLSE_min; + bool CLSE_hasMax; + float CLSE_max; + int CLSE_action; + char CLSE_cvar[CLS_CVAR_MAXLEN]; +} +#else +enum CLSEntry +{ + bool:CLSE_hasMin, + Float:CLSE_min, + bool:CLSE_hasMax, + Float:CLSE_max, + CLSE_action, + String:CLSE_cvar[CLS_CVAR_MAXLEN] +}; +#endif + +static ArrayList + ClientSettingsArray = null; + +static Handle + ClientSettingsCheckTimer = null; + +void CLS_OnModuleStart() +{ +#if SOURCEMOD_V_MINOR > 9 + CLSEntry clsetting; +#else + CLSEntry clsetting[CLSEntry]; +#endif + + ClientSettingsArray = new ArrayList(sizeof(clsetting)); + + RegConsoleCmd("confogl_clientsettings", _ClientSettings_Cmd, "List Client settings enforced by confogl"); + + /* Using Server Cmd instead of admin because these shouldn't really be changed on the fly */ + RegServerCmd("confogl_trackclientcvar", _TrackClientCvar_Cmd, "Add a Client CVar to be tracked and enforced by confogl"); + RegServerCmd("confogl_resetclientcvars", _ResetTracking_Cmd, "Remove all tracked client cvars. Cannot be called during matchmode"); + RegServerCmd("confogl_startclientchecking", _StartClientChecking_Cmd, "Start checking and enforcing client cvars tracked by this plugin"); +} + +static void ClearAllSettings() +{ + ClientSettingsArray.Clear(); +} + +/*#if SOURCEMOD_V_MINOR > 9 +static void ClearCLSEntry(CLSEntry entry) +{ + entry.CLSE_hasMin = false; + entry.CLSE_min = 0.0; + entry.CLSE_hasMax = false; + entry.CLSE_max = 0.0; + entry.CLSE_cvar[0] = 0; +} +#else +static void ClearCLSEntry(CLSEntry entry[CLSEntry]) +{ + entry[CLSE_hasMin] = false; + entry[CLSE_min] = 0.0; + entry[CLSE_hasMax] = false; + entry[CLSE_max] = 0.0; + entry[CLSE_cvar][0] = 0; +} +#endif*/ + +public Action _CheckClientSettings_Timer(Handle hTimer) +{ + if (!IsPluginEnabled()) { + if (IsDebugEnabled()) { + LogMessage("[%s] Stopping client settings tracking", CLS_MODULE_NAME); + } + + ClientSettingsCheckTimer = null; + return Plugin_Stop; + } + + EnforceAllCliSettings(); + return Plugin_Continue; +} + +static void EnforceAllCliSettings() +{ + for (int i = 1; i <= MaxClients; i++) { + if (IsClientInGame(i) && !IsFakeClient(i)) { + EnforceCliSettings(i); + } + } +} + +static void EnforceCliSettings(int client) +{ + int iSize = ClientSettingsArray.Length; +#if SOURCEMOD_V_MINOR > 9 + CLSEntry clsetting; + for (int i = 0; i < iSize; i++) { + ClientSettingsArray.GetArray(i, clsetting, sizeof(clsetting)); + + QueryClientConVar(client, clsetting.CLSE_cvar, _EnforceCliSettings_QueryReply, i); + } +#else + CLSEntry clsetting[CLSEntry]; + for (int i = 0; i < iSize; i++) { + ClientSettingsArray.GetArray(i, clsetting[0], sizeof(clsetting)); + + QueryClientConVar(client, clsetting[CLSE_cvar], _EnforceCliSettings_QueryReply, i); + } +#endif +} + +public void _EnforceCliSettings_QueryReply(QueryCookie cookie, int client, ConVarQueryResult result, \ + const char[] cvarName, const char[] cvarValue, any value) +{ + if (!IsClientConnected(client) || !IsClientInGame(client) || IsClientInKickQueue(client)) { + // Client disconnected or got kicked already + return; + } + + if (result) { + LogMessage("[%s] Couldn't retrieve cvar %s from %L, kicked from server", CLS_MODULE_NAME, cvarName, client); + KickClient(client, "CVar '%s' protected or missing! Hax?", cvarName); + return; + } + + float fCvarVal = StringToFloat(cvarValue); + int clsetting_index = value; + +#if SOURCEMOD_V_MINOR > 9 + CLSEntry clsetting; + ClientSettingsArray.GetArray(clsetting_index, clsetting, sizeof(clsetting)); + + if ((clsetting.CLSE_hasMin && fCvarVal < clsetting.CLSE_min) + || (clsetting.CLSE_hasMax && fCvarVal > clsetting.CLSE_max) + ) { + switch (clsetting.CLSE_action) { + case CLSA_Kick: { + LogMessage("[%s] Kicking %L for bad %s value (%f). Min: %d %f Max: %d %f", \ + CLS_MODULE_NAME, client, cvarName, fCvarVal, clsetting.CLSE_hasMin, \ + clsetting.CLSE_min, clsetting.CLSE_hasMax, clsetting.CLSE_max); + + /*PrintToChatAll("\x01[\x05Confogl\x01] Kicking \x04%L\x01 for having an illegal value for '\x04%s\x01' (\x04%f\x01) !!!", \ + client, cvarName, fCvarVal);*/ + CPrintToChatAll("{blue}[{default}Confogl{blue}] {olive}%L{default} was kicked for having an illegal value for '{green}%s{default}' {blue}({default}%f{blue})", \ + client, cvarName, fCvarVal); + + char kickMessage[256] = "Illegal Client Value for "; + Format(kickMessage, sizeof(kickMessage), "%s%s (%.2f)", kickMessage, cvarName, fCvarVal); + + if (clsetting.CLSE_hasMin) { + Format(kickMessage, sizeof(kickMessage), "%s, Min %.2f", kickMessage, clsetting.CLSE_min); + } + + if (clsetting.CLSE_hasMax) { + Format(kickMessage, sizeof(kickMessage), "%s, Max %.2f", kickMessage, clsetting.CLSE_max); + } + + KickClient(client, "%s", kickMessage); + } + case CLSA_Log: { + LogMessage("[%s] Client %L has a bad %s value (%f). Min: %d %f Max: %d %f", \ + CLS_MODULE_NAME, client, cvarName, fCvarVal, clsetting.CLSE_hasMin, \ + clsetting.CLSE_min, clsetting.CLSE_hasMax, clsetting.CLSE_max); + } + } + } +#else + CLSEntry clsetting[CLSEntry]; + ClientSettingsArray.GetArray(clsetting_index, clsetting[0], sizeof(clsetting)); + + if ((clsetting[CLSE_hasMin] && fCvarVal < clsetting[CLSE_min]) + || (clsetting[CLSE_hasMax] && fCvarVal > clsetting[CLSE_max]) + ) { + switch (clsetting[CLSE_action]) { + case CLSA_Kick: { + LogMessage("[%s] Kicking %L for bad %s value (%f). Min: %d %f Max: %d %f", \ + CLS_MODULE_NAME, client, cvarName, fCvarVal, clsetting[CLSE_hasMin], \ + clsetting[CLSE_min], clsetting[CLSE_hasMax], clsetting[CLSE_max]); + + /*PrintToChatAll("\x01[\x05Confogl\x01] Kicking \x04%L\x01 for having an illegal value for '\x04%s\x01' (\x04%f\x01) !!!", \ + client, cvarName, fCvarVal);*/ + CPrintToChatAll("{blue}[{default}Confogl{blue}] {olive}%L{default} was kicked for having an illegal value for '{green}%s{default}' {blue}({default}%f{blue})", \ + client, cvarName, fCvarVal); + + char kickMessage[256] = "Illegal Client Value for "; + Format(kickMessage, sizeof(kickMessage), "%s%s (%.2f)", kickMessage, cvarName, fCvarVal); + + if (clsetting[CLSE_hasMin]) { + Format(kickMessage, sizeof(kickMessage), "%s, Min %.2f", kickMessage, clsetting[CLSE_min]); + } + + if (clsetting[CLSE_hasMax]) { + Format(kickMessage, sizeof(kickMessage), "%s, Max %.2f", kickMessage, clsetting[CLSE_max]); + } + + KickClient(client, "%s", kickMessage); + } + case CLSA_Log: { + LogMessage("[%s] Client %L has a bad %s value (%f). Min: %d %f Max: %d %f", \ + CLS_MODULE_NAME, client, cvarName, fCvarVal, clsetting[CLSE_hasMin], \ + clsetting[CLSE_min], clsetting[CLSE_hasMax], clsetting[CLSE_max]); + } + } + } +#endif +} + +public Action _ClientSettings_Cmd(int client, int args) +{ + int iSize = ClientSettingsArray.Length; + ReplyToCommand(client, "[Confogl] Tracked Client CVars (Total %d)", iSize); + +#if SOURCEMOD_V_MINOR > 9 + CLSEntry clsetting; +#else + CLSEntry clsetting[CLSEntry]; +#endif + + char message[256], shortbuf[64]; + for (int i = 0; i < iSize; i++) { + #if SOURCEMOD_V_MINOR > 9 + ClientSettingsArray.GetArray(i, clsetting, sizeof(clsetting)); + Format(message, sizeof(message), "[Confogl] Client CVar: %s ", clsetting.CLSE_cvar); + + if (clsetting.CLSE_hasMin) { + Format(shortbuf, sizeof(shortbuf), "Min: %f ", clsetting.CLSE_min); + StrCat(message, sizeof(message), shortbuf); + } + + if (clsetting.CLSE_hasMax) { + Format(shortbuf, sizeof(shortbuf), "Max: %f ", clsetting.CLSE_max); + StrCat(message, sizeof(message), shortbuf); + } + + switch (clsetting.CLSE_action) { + case CLSA_Kick: { + StrCat(message, sizeof(message), "Action: Kick"); + } + case CLSA_Log: { + StrCat(message, sizeof(message), "Action: Log"); + } + } + #else + ClientSettingsArray.GetArray(i, clsetting[0], sizeof(clsetting)); + Format(message, sizeof(message), "[Confogl] Client CVar: %s ", clsetting[CLSE_cvar]); + + if (clsetting[CLSE_hasMin]) { + Format(shortbuf, sizeof(shortbuf), "Min: %f ", clsetting[CLSE_min]); + StrCat(message, sizeof(message), shortbuf); + } + + if (clsetting[CLSE_hasMax]) { + Format(shortbuf, sizeof(shortbuf), "Max: %f ", clsetting[CLSE_max]); + StrCat(message, sizeof(message), shortbuf); + } + + switch (clsetting[CLSE_action]) { + case CLSA_Kick: { + StrCat(message, sizeof(message), "Action: Kick"); + } + case CLSA_Log: { + StrCat(message, sizeof(message), "Action: Log"); + } + } + #endif + + ReplyToCommand(client, message); + } + + return Plugin_Handled; +} + +public Action _TrackClientCvar_Cmd(int args) +{ + if (args < 3 || args == 4) { + PrintToServer("Usage: confogl_trackclientcvar [ []]"); + + if (IsDebugEnabled()) { + char cmdbuf[128]; + GetCmdArgString(cmdbuf, sizeof(cmdbuf)); + Debug_LogError(CLS_MODULE_NAME, "Invalid track client cvar: %s", cmdbuf); + } + + return Plugin_Handled; + } + + char sBuffer[CLS_CVAR_MAXLEN], cvar[CLS_CVAR_MAXLEN]; + bool hasMax; + float max; + int action = CLSA_Kick; + + GetCmdArg(1, cvar, sizeof(cvar)); + + if (!strlen(cvar)) { + PrintToServer("Unreadable cvar"); + + if (IsDebugEnabled()) { + char cmdbuf[128]; + GetCmdArgString(cmdbuf, sizeof(cmdbuf)); + Debug_LogError(CLS_MODULE_NAME, "Invalid track client cvar: %s", cmdbuf); + } + + return Plugin_Handled; + } + + GetCmdArg(2, sBuffer, sizeof(sBuffer)); + bool hasMin = view_as(StringToInt(sBuffer)); + + GetCmdArg(3, sBuffer, sizeof(sBuffer)); + float min = StringToFloat(sBuffer); + + if (args >= 5) { + GetCmdArg(4, sBuffer, sizeof(sBuffer)); + hasMax = view_as(StringToInt(sBuffer)); + + GetCmdArg(5, sBuffer, sizeof(sBuffer)); + max = StringToFloat(sBuffer); + } + + if (args >= 6) { + GetCmdArg(6, sBuffer, sizeof(sBuffer)); + action = StringToInt(sBuffer); + } + + _AddClientCvar(cvar, hasMin, min, hasMax, max, action); + + return Plugin_Handled; +} + +public Action _ResetTracking_Cmd(int args) +{ + if (ClientSettingsCheckTimer != null) { + PrintToServer("Can't reset tracking in the middle of a match"); + return Plugin_Handled; + } + + ClearAllSettings(); + PrintToServer("Client CVar Tracking Information Reset!"); + + return Plugin_Handled; +} + +public Action _StartClientChecking_Cmd(int args) +{ + _StartTracking(); + + return Plugin_Handled; +} + +static void _StartTracking() +{ + if (IsPluginEnabled() && ClientSettingsCheckTimer == null) { + if (IsDebugEnabled()) { + LogMessage("[%s] Starting repeating check timer", CLS_MODULE_NAME); + } + + ClientSettingsCheckTimer = CreateTimer(CLIENT_CHECK_INTERVAL, _CheckClientSettings_Timer, _, TIMER_REPEAT); + } else { + PrintToServer("Can't start plugin tracking or tracking already started"); + } +} + +static void _AddClientCvar(const char[] cvar, bool hasMin, float min, bool hasMax, float max, int action) +{ + if (ClientSettingsCheckTimer != null) { + PrintToServer("Can't track new cvars in the middle of a match"); + + if (IsDebugEnabled()) { + LogMessage("[%s] Attempt to track new cvar %s during a match!", CLS_MODULE_NAME, cvar); + } + + return; + } + + if (!(hasMin || hasMax)) { + Debug_LogError(CLS_MODULE_NAME, "Client CVar %s specified without max or min", cvar); + return; + } + + if (hasMin && hasMax && max < min) { + Debug_LogError(CLS_MODULE_NAME, "Client CVar %s specified max < min (%f < %f)", cvar, max, min); + return; + } + + if (strlen(cvar) >= CLS_CVAR_MAXLEN) { + Debug_LogError(CLS_MODULE_NAME, "CVar Specified (%s) is longer than max cvar length (%d)", cvar, CLS_CVAR_MAXLEN); + return; + } + + int iSize = ClientSettingsArray.Length; + +#if SOURCEMOD_V_MINOR > 9 + CLSEntry newEntry; + for (int i = 0; i < iSize; i++) { + ClientSettingsArray.GetArray(i, newEntry, sizeof(newEntry)); + if (strcmp(newEntry.CLSE_cvar, cvar, false) == 0) { + Debug_LogError(CLS_MODULE_NAME, "Attempt to track CVar %s, which is already being tracked.", cvar); + return; + } + } + + newEntry.CLSE_hasMin = hasMin; + newEntry.CLSE_min = min; + newEntry.CLSE_hasMax = hasMax; + newEntry.CLSE_max = max; + newEntry.CLSE_action = action; + strcopy(newEntry.CLSE_cvar, CLS_CVAR_MAXLEN, cvar); + + if (IsDebugEnabled()) { + LogMessage("[%s] Tracking Cvar %s Min %d %f Max %d %f Action %d", CLS_MODULE_NAME, cvar, hasMin, min, hasMax, max, action); + } + + ClientSettingsArray.PushArray(newEntry, sizeof(newEntry)); +#else + CLSEntry newEntry[CLSEntry]; + for (int i = 0; i < iSize; i++) { + ClientSettingsArray.GetArray(i, newEntry[0], sizeof(newEntry)); + if (strcmp(newEntry[CLSE_cvar], cvar, false) == 0) { + Debug_LogError(CLS_MODULE_NAME, "Attempt to track CVar %s, which is already being tracked.", cvar); + return; + } + } + + newEntry[CLSE_hasMin] = hasMin; + newEntry[CLSE_min] = min; + newEntry[CLSE_hasMax] = hasMax; + newEntry[CLSE_max] = max; + newEntry[CLSE_action] = action; + strcopy(newEntry[CLSE_cvar], CLS_CVAR_MAXLEN, cvar); + + if (IsDebugEnabled()) { + LogMessage("[%s] Tracking Cvar %s Min %d %f Max %d %f Action %d", CLS_MODULE_NAME, cvar, hasMin, min, hasMax, max, action); + } + + ClientSettingsArray.PushArray(newEntry[0], sizeof(newEntry)); +#endif +} diff --git a/addons/sourcemod/scripting/confoglcompmod/CvarSettings.sp b/addons/sourcemod/scripting/confoglcompmod/CvarSettings.sp new file mode 100644 index 000000000..55395df47 --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/CvarSettings.sp @@ -0,0 +1,402 @@ +#if defined __cvar_settings_included + #endinput +#endif +#define __cvar_settings_included + +#define CVS_MODULE_NAME "CvarSettings" + +#define CVARS_DEBUG 0 +#define CVS_CVAR_MAXLEN 64 + +#if SOURCEMOD_V_MINOR > 9 +enum struct CVSEntry +{ + ConVar CVSE_cvar; + char CVSE_oldval[CVS_CVAR_MAXLEN]; + char CVSE_newval[CVS_CVAR_MAXLEN]; +} +#else +enum CVSEntry +{ + ConVar:CVSE_cvar, + String:CVSE_oldval[CVS_CVAR_MAXLEN], + String:CVSE_newval[CVS_CVAR_MAXLEN] +}; +#endif + +static bool + bTrackingStarted = false; + +static ArrayList + CvarSettingsArray = null; + +void CVS_OnModuleStart() +{ +#if SOURCEMOD_V_MINOR > 9 + CVSEntry cvsetting; +#else + CVSEntry cvsetting[CVSEntry]; +#endif + + CvarSettingsArray = new ArrayList(sizeof(cvsetting)); + + RegConsoleCmd("confogl_cvarsettings", CVS_CvarSettings_Cmd, "List all ConVars being enforced by Confogl"); + RegConsoleCmd("confogl_cvardiff", CVS_CvarDiff_Cmd, "List any ConVars that have been changed from their initialized values"); + + RegServerCmd("confogl_addcvar", CVS_AddCvar_Cmd, "Add a ConVar to be set by Confogl"); + RegServerCmd("confogl_setcvars", CVS_SetCvars_Cmd, "Starts enforcing ConVars that have been added."); + RegServerCmd("confogl_resetcvars", CVS_ResetCvars_Cmd, "Resets enforced ConVars. Cannot be used during a match!"); +} + +void CVS_OnModuleEnd() +{ + ClearAllSettings(); +} + +void CVS_OnConfigsExecuted() +{ + if (bTrackingStarted) { + SetEnforcedCvars(); + } +} + +public Action CVS_SetCvars_Cmd(int args) +{ + if (!IsPluginEnabled()) { + return Plugin_Handled; + } + + if (bTrackingStarted) { + PrintToServer("Tracking has already been started"); + return Plugin_Handled; + } + +#if CVARS_DEBUG + LogMessage("[%s] No longer accepting new ConVars", CVS_MODULE_NAME); +#endif + + SetEnforcedCvars(); + bTrackingStarted = true; + + return Plugin_Handled; +} + +public Action CVS_AddCvar_Cmd(int args) +{ + if (args != 2) { + PrintToServer("Usage: confogl_addcvar "); + + if (IsDebugEnabled()) { + char cmdbuf[MAX_NAME_LENGTH]; + GetCmdArgString(cmdbuf, sizeof(cmdbuf)); + Debug_LogError(CVS_MODULE_NAME, "Invalid Cvar Add: %s", cmdbuf); + } + + return Plugin_Handled; + } + + char cvar[CVS_CVAR_MAXLEN], newval[CVS_CVAR_MAXLEN]; + GetCmdArg(1, cvar, sizeof(cvar)); + GetCmdArg(2, newval, sizeof(newval)); + + AddCvar(cvar, newval); + + return Plugin_Handled; +} + +public Action CVS_ResetCvars_Cmd(int args) +{ + if (IsPluginEnabled()) { + PrintToServer("Can't reset tracking in the middle of a match"); + return Plugin_Handled; + } + + ClearAllSettings(); + PrintToServer("Server CVar Tracking Information Reset!"); + + return Plugin_Handled; +} + +public Action CVS_CvarSettings_Cmd(int client, int args) +{ + if (!IsPluginEnabled()) { + return Plugin_Handled; + } + + if (!bTrackingStarted) { + ReplyToCommand(client, "[Confogl] CVar tracking has not been started!! THIS SHOULD NOT OCCUR DURING A MATCH!"); + return Plugin_Handled; + } + + char buffer[CVS_CVAR_MAXLEN], name[CVS_CVAR_MAXLEN]; + int cvscount = CvarSettingsArray.Length; + + ReplyToCommand(client, "[Confogl] Enforced Server CVars (Total %d)", cvscount); + + GetCmdArg(1, buffer, sizeof(buffer)); + int offset = StringToInt(buffer); + + if (offset < 0 || offset > cvscount) { + return Plugin_Handled; + } + + int temp = cvscount; + if ((offset + 20) < cvscount) { + temp = offset + 20; + } + +#if SOURCEMOD_V_MINOR > 9 + CVSEntry cvsetting; + + for (int i = offset; i < temp && i < cvscount; i++) { + CvarSettingsArray.GetArray(i, cvsetting, sizeof(cvsetting)); + + (cvsetting.CVSE_cvar).GetString(buffer, sizeof(buffer)); + (cvsetting.CVSE_cvar).GetName(name, sizeof(name)); + + ReplyToCommand(client, "[Confogl] Server CVar: %s, Desired Value: %s, Current Value: %s", name, cvsetting.CVSE_newval, buffer); + } +#else + CVSEntry cvsetting[CVSEntry]; + + for (int i = offset; i < temp && i < cvscount; i++) { + CvarSettingsArray.GetArray(i, cvsetting[0], sizeof(cvsetting)); + + cvsetting[CVSE_cvar].GetString(buffer, sizeof(buffer)); + cvsetting[CVSE_cvar].GetName(name, sizeof(name)); + + ReplyToCommand(client, "[Confogl] Server CVar: %s, Desired Value: %s, Current Value: %s", name, cvsetting[CVSE_newval], buffer); + } +#endif + + if ((offset + 20) < cvscount) { + ReplyToCommand(client, "[Confogl] To see more CVars, use confogl_cvarsettings %d", offset + 20); + } + + return Plugin_Handled; +} + +public Action CVS_CvarDiff_Cmd(int client, int args) +{ + if (!IsPluginEnabled()) { + return Plugin_Handled; + } + + if (!bTrackingStarted) { + ReplyToCommand(client, "[Confogl] CVar tracking has not been started!! THIS SHOULD NOT OCCUR DURING A MATCH!"); + return Plugin_Handled; + } + + char buffer[CVS_CVAR_MAXLEN], name[CVS_CVAR_MAXLEN]; + int cvscount = CvarSettingsArray.Length; + + GetCmdArg(1, buffer, sizeof(buffer)); + int offset = StringToInt(buffer); + + if (offset > cvscount) { + return Plugin_Handled; + } + + int foundCvars = 0; + +#if SOURCEMOD_V_MINOR > 9 + CVSEntry cvsetting; + + while (offset < cvscount && foundCvars < 20) { + CvarSettingsArray.GetArray(offset, cvsetting, sizeof(cvsetting)); + + (cvsetting.CVSE_cvar).GetString(buffer, sizeof(buffer)); + (cvsetting.CVSE_cvar).GetName(name, sizeof(name)); + + if (strcmp(cvsetting.CVSE_newval, buffer) != 0) { + ReplyToCommand(client, "[Confogl] Server CVar: %s, Desired Value: %s, Current Value: %s", name, cvsetting.CVSE_newval, buffer); + foundCvars++; + } + + offset++; + } +#else + CVSEntry cvsetting[CVSEntry]; + + while (offset < cvscount && foundCvars < 20) { + CvarSettingsArray.GetArray(offset, cvsetting[0], sizeof(cvsetting)); + + cvsetting[CVSE_cvar].GetString(buffer, sizeof(buffer)); + cvsetting[CVSE_cvar].GetName(name, sizeof(name)); + + if (strcmp(cvsetting[CVSE_newval], buffer) != 0) { + ReplyToCommand(client, "[Confogl] Server CVar: %s, Desired Value: %s, Current Value: %s", name, cvsetting[CVSE_newval], buffer); + foundCvars++; + } + + offset++; + } +#endif + + if (offset < cvscount) { + ReplyToCommand(client, "[Confogl] To see more CVars, use confogl_cvarsettings %d", offset); + } + + return Plugin_Handled; +} + +static void ClearAllSettings() +{ + bTrackingStarted = false; + int iSize = CvarSettingsArray.Length; + +#if SOURCEMOD_V_MINOR > 9 + CVSEntry cvsetting; + + for (int i = 0; i < iSize; i++) { + CvarSettingsArray.GetArray(i, cvsetting, sizeof(cvsetting)); + + (cvsetting.CVSE_cvar).RemoveChangeHook(CVS_ConVarChange); + (cvsetting.CVSE_cvar).SetString(cvsetting.CVSE_oldval); + } +#else + CVSEntry cvsetting[CVSEntry]; + + for (int i = 0; i < iSize; i++) { + CvarSettingsArray.GetArray(i, cvsetting[0], sizeof(cvsetting)); + + cvsetting[CVSE_cvar].RemoveChangeHook(CVS_ConVarChange); + cvsetting[CVSE_cvar].SetString(cvsetting[CVSE_oldval]); + } +#endif + + CvarSettingsArray.Clear(); +} + +static void SetEnforcedCvars() +{ + int iSize = CvarSettingsArray.Length; + +#if SOURCEMOD_V_MINOR > 9 + CVSEntry cvsetting; + + for (int i = 0; i < iSize; i++) { + CvarSettingsArray.GetArray(i, cvsetting, sizeof(cvsetting)); + + #if CVARS_DEBUG + char debug_buffer[CVS_CVAR_MAXLEN]; + (cvsetting.CVSE_cvar).GetName(debug_buffer, sizeof(debug_buffer)); + LogMessage("[%s] cvar = %s, newval = %s", CVS_MODULE_NAME, debug_buffer, cvsetting.CVSE_newval); + #endif + + (cvsetting.CVSE_cvar).SetString(cvsetting.CVSE_newval); + } +#else + CVSEntry cvsetting[CVSEntry]; + + for (int i = 0; i < iSize; i++) { + CvarSettingsArray.GetArray(i, cvsetting[0], sizeof(cvsetting)); + + #if CVARS_DEBUG + char debug_buffer[CVS_CVAR_MAXLEN]; + cvsetting[CVSE_cvar].GetName(debug_buffer, sizeof(debug_buffer)); + LogMessage("[%s] cvar = %s, newval = %s", CVS_MODULE_NAME, debug_buffer, cvsetting[CVSE_newval]); + #endif + + cvsetting[CVSE_cvar].SetString(cvsetting[CVSE_newval]); + } +#endif +} + +static void AddCvar(const char[] cvar, const char[] newval) +{ + if (bTrackingStarted) { + #if CVARS_DEBUG + LogMessage("[%s] Attempt to track new cvar %s during a match!", CVS_MODULE_NAME, cvar); + #endif + return; + } + + if (strlen(cvar) >= CVS_CVAR_MAXLEN) { + Debug_LogError(CVS_MODULE_NAME, "CVar Specified (%s) is longer than max cvar/value length (%d)", cvar, CVS_CVAR_MAXLEN); + return; + } + + if (strlen(newval) >= CVS_CVAR_MAXLEN) { + Debug_LogError(CVS_MODULE_NAME, "New Value Specified (%s) is longer than max cvar/value length (%d)", newval, CVS_CVAR_MAXLEN); + return; + } + + ConVar newCvar = FindConVar(cvar); + + if (newCvar == null) { + Debug_LogError(CVS_MODULE_NAME, "Could not find CVar specified (%s)", cvar); + return; + } + + char cvarBuffer[CVS_CVAR_MAXLEN]; + int iSize = CvarSettingsArray.Length; + +#if SOURCEMOD_V_MINOR > 9 + CVSEntry newEntry; + + for (int i = 0; i < iSize; i++) { + CvarSettingsArray.GetArray(i, newEntry, sizeof(newEntry)); + + (newEntry.CVSE_cvar).GetName(cvarBuffer, CVS_CVAR_MAXLEN); + + if (strcmp(cvar, cvarBuffer, false) == 0) { + Debug_LogError(CVS_MODULE_NAME, "Attempt to track ConVar %s, which is already being tracked.", cvar); + return; + } + } + + newCvar.GetString(cvarBuffer, CVS_CVAR_MAXLEN); + + newEntry.CVSE_cvar = newCvar; + strcopy(newEntry.CVSE_oldval, CVS_CVAR_MAXLEN, cvarBuffer); + strcopy(newEntry.CVSE_newval, CVS_CVAR_MAXLEN, newval); + + newCvar.AddChangeHook(CVS_ConVarChange); + +#if CVARS_DEBUG + LogMessage("[%s] cvar = %s, newval = %s, oldval = %s", CVS_MODULE_NAME, cvar, newval, cvarBuffer); +#endif + + CvarSettingsArray.PushArray(newEntry, sizeof(newEntry)); +#else + CVSEntry newEntry[CVSEntry]; + + for (int i = 0; i < iSize; i++) { + CvarSettingsArray.GetArray(i, newEntry[0], sizeof(newEntry)); + + newEntry[CVSE_cvar].GetName(cvarBuffer, CVS_CVAR_MAXLEN); + + if (strcmp(cvar, cvarBuffer, false) == 0) { + Debug_LogError(CVS_MODULE_NAME, "Attempt to track ConVar %s, which is already being tracked.", cvar); + return; + } + } + + newCvar.GetString(cvarBuffer, CVS_CVAR_MAXLEN); + + newEntry[CVSE_cvar] = newCvar; + strcopy(newEntry[CVSE_oldval], CVS_CVAR_MAXLEN, cvarBuffer); + strcopy(newEntry[CVSE_newval], CVS_CVAR_MAXLEN, newval); + + newCvar.AddChangeHook(CVS_ConVarChange); + +#if CVARS_DEBUG + LogMessage("[%s] cvar = %s, newval = %s, oldval = %s", CVS_MODULE_NAME, cvar, newval, cvarBuffer); +#endif + + CvarSettingsArray.PushArray(newEntry[0], sizeof(newEntry)); +#endif +} + +public void CVS_ConVarChange(ConVar hConVar, const char[] sOldValue, const char[] sNewValue) +{ + if (bTrackingStarted) { + char sName[CVS_CVAR_MAXLEN]; + hConVar.GetName(sName, sizeof(sName)); + + PrintToServer("[Confogl] Tracked Server CVar '%s' changed from '%s' to '%s' !!!", sName, sOldValue, sNewValue); + //PrintToChatAll("[Confogl] Tracked Server CVar '%s' changed from '%s' to '%s' !!!", sName, sOldValue, sNewValue); + CPrintToChatAll("{blue}[{default}Confogl{blue}]{default} Tracked Server CVar '{green}%s{default}' changed from '{blue}%s{default}' to '{blue}%s{default}' !!!", sName, sOldValue, sNewValue); + } +} diff --git a/addons/sourcemod/scripting/confoglcompmod/EntityRemover.sp b/addons/sourcemod/scripting/confoglcompmod/EntityRemover.sp new file mode 100644 index 000000000..4f73d4d04 --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/EntityRemover.sp @@ -0,0 +1,403 @@ +#if defined __entity_remover_included + #endinput +#endif +#define __entity_remover_included + +#define ER_MODULE_NAME "EntityRemover" + +#define DEBUG_ER 0 + +#define ER_KV_ACTION_KILL 1 + +#define ER_KV_PROPTYPE_INT 1 +#define ER_KV_PROPTYPE_FLOAT 2 +#define ER_KV_PROPTYPE_BOOL 3 +#define ER_KV_PROPTYPE_STRING 4 + +#define ER_KV_CONDITION_EQUAL 1 +#define ER_KV_CONDITION_NEQUAL 2 +#define ER_KV_CONDITION_LESS 3 +#define ER_KV_CONDITION_GREAT 4 +#define ER_KV_CONDITION_CONTAINS 5 + +static bool + ER_bKillParachutist = true, + ER_bReplaceGhostHurt = false; + +static ConVar + ER_hKillParachutist = null, + ER_hReplaceGhostHurt = null; + +static KeyValues + kERData = null; + +void ER_OnModuleStart() +{ + ER_hKillParachutist = CreateConVarEx("remove_parachutist", "1", "Removes the parachutist from c3m2", _, true, 0.0, true, 1.0); + ER_hReplaceGhostHurt = CreateConVarEx( \ + "disable_ghost_hurt", \ + "0", \ + "Replaces all trigger_ghost_hurt with trigger_hurt, blocking ghost spawns from dying.", \ + _, true, 0.0, true, 1.0 \ + ); + + ER_bKillParachutist = ER_hKillParachutist.BoolValue; + ER_bReplaceGhostHurt = ER_hReplaceGhostHurt.BoolValue; + + ER_hKillParachutist.AddChangeHook(ER_ConVarChange); + ER_hReplaceGhostHurt.AddChangeHook(ER_ConVarChange); + + ER_KV_Load(); + + RegAdminCmd("confogl_erdata_reload", ER_KV_CmdReload, ADMFLAG_CONFIG); + + HookEvent("round_start", ER_RoundStart_Event, EventHookMode_PostNoCopy); +} + +public void ER_ConVarChange(ConVar hConvar, const char[] sOldValue, const char[] sNewValue) +{ + ER_bKillParachutist = ER_hKillParachutist.BoolValue; + ER_bReplaceGhostHurt = ER_hReplaceGhostHurt.BoolValue; +} + +void ER_OnModuleEnd() +{ + ER_KV_Close(); +} + +static void ER_KV_Close() +{ + if (kERData != null) { + delete kERData; + kERData = null; + } +} + +static void ER_KV_Load() +{ + char sNameBuff[PLATFORM_MAX_PATH], sDescBuff[256], sValBuff[32]; + + if (DEBUG_ER || IsDebugEnabled()) { + LogMessage("[%s] Loading EntityRemover KeyValues", ER_MODULE_NAME); + } + + kERData = new KeyValues("EntityRemover"); + + BuildConfigPath(sNameBuff, sizeof(sNameBuff), "entityremove.txt"); //Build our filepath + + if (!kERData.ImportFromFile(sNameBuff)) { + Debug_LogError(ER_MODULE_NAME, "Couldn't load EntityRemover data!"); + ER_KV_Close(); + return; + } + + // Create cvars for all entity removes + if (DEBUG_ER || IsDebugEnabled()) { + LogMessage("[%s] Creating entry CVARs", ER_MODULE_NAME); + } + + kERData.GotoFirstSubKey(); + + do { + kERData.GotoFirstSubKey(); + + do { + kERData.GetString("cvar", sNameBuff, sizeof(sNameBuff)); + kERData.GetString("cvar_desc", sDescBuff, sizeof(sDescBuff)); + kERData.GetString("cvar_val", sValBuff, sizeof(sValBuff)); + + CreateConVarEx(sNameBuff, sValBuff, sDescBuff); + + if (DEBUG_ER || IsDebugEnabled()) { + LogMessage("[%s] Creating CVAR %s", ER_MODULE_NAME, sNameBuff); + } + + } while(kERData.GotoNextKey()); + + kERData.GoBack(); + } while(kERData.GotoNextKey()); + + kERData.Rewind(); +} + +public Action ER_KV_CmdReload(int client, int args) +{ + if (!IsPluginEnabled()) { + return Plugin_Continue; + } + + ReplyToCommand(client, "[ER] Reloading EntityRemoveData"); + ER_KV_Reload(); + + return Plugin_Handled; +} + +static void ER_KV_Reload() +{ + ER_KV_Close(); + ER_KV_Load(); +} + +static bool ER_KV_TestCondition(int lhsval, int rhsval, int condition) +{ + switch (condition) { + case ER_KV_CONDITION_EQUAL: { + return (lhsval == rhsval); + } + case ER_KV_CONDITION_NEQUAL: { + return (lhsval != rhsval); + } + case ER_KV_CONDITION_LESS: { + return (lhsval < rhsval); + } + case ER_KV_CONDITION_GREAT: { + return (lhsval > rhsval); + } + } + + return false; +} + +static bool ER_KV_TestConditionFloat(float lhsval, float rhsval, int condition) +{ + switch (condition) { + case ER_KV_CONDITION_EQUAL: { + return (lhsval == rhsval); + } + case ER_KV_CONDITION_NEQUAL: { + return (lhsval != rhsval); + } + case ER_KV_CONDITION_LESS: { + return (lhsval < rhsval); + } + case ER_KV_CONDITION_GREAT: { + return (lhsval > rhsval); + } + } + + return false; +} + +static bool ER_KV_TestConditionString(const char[] lhsval, const char[] rhsval, int condition) +{ + switch (condition) { + case ER_KV_CONDITION_EQUAL: { + return (strcmp(lhsval, rhsval) == 0); + } + case ER_KV_CONDITION_NEQUAL: { + return (strcmp(lhsval, rhsval) != 0); + } + case ER_KV_CONDITION_CONTAINS: { + return (StrContains(lhsval, rhsval) != -1); + } + } + + return false; +} + +// Returns true if the entity is still alive (not killed) +static bool ER_KV_ParseEntity(KeyValues kEntry, int iEntity) +{ + char sBuffer[64], mapname[64]; + + // Check CVAR for this entry + kEntry.GetString("cvar", sBuffer, sizeof(sBuffer)); + + if (strlen(sBuffer) && !(FindConVarEx(sBuffer).BoolValue)) { + return true; + } + + // Check MapName for this entry + GetCurrentMap(mapname, sizeof(mapname)); + + kEntry.GetString("map", sBuffer, sizeof(sBuffer)); + if (strlen(sBuffer) && StrContains(sBuffer, mapname) == -1) { + return true; + } + + kEntry.GetString("excludemap", sBuffer, sizeof(sBuffer)); + if (strlen(sBuffer) && StrContains(sBuffer, mapname) != -1) { + return true; + } + + // Do property check for this entry + kEntry.GetString("property", sBuffer, sizeof(sBuffer)); + if (strlen(sBuffer)) { + int proptype = kEntry.GetNum("proptype"); + + switch (proptype) { + case ER_KV_PROPTYPE_INT, ER_KV_PROPTYPE_BOOL: { + int rhsval = kEntry.GetNum("propval"); + PropType prop_type = view_as(kEntry.GetNum("propdata")); + int lhsval = GetEntProp(iEntity, prop_type, sBuffer); + + if (!ER_KV_TestCondition(lhsval, rhsval, kEntry.GetNum("condition"))) { + return true; + } + } + case ER_KV_PROPTYPE_FLOAT: { + float rhsval = kEntry.GetFloat("propval"); + PropType prop_type = view_as(kEntry.GetNum("propdata")); + float lhsval = GetEntPropFloat(iEntity, prop_type, sBuffer); + + if (!ER_KV_TestConditionFloat(lhsval, rhsval, kEntry.GetNum("condition"))) { + return true; + } + } + case ER_KV_PROPTYPE_STRING: { + char rhsval[64], lhsval[64]; + kEntry.GetString("propval", rhsval, sizeof(rhsval)); + PropType prop_type = view_as(kEntry.GetNum("propdata")); + GetEntPropString(iEntity, prop_type, sBuffer, lhsval, sizeof(lhsval)); + + if (!ER_KV_TestConditionString(lhsval, rhsval, kEntry.GetNum("condition"))) { + return true; + } + } + } + } + + int iAction = kEntry.GetNum("action"); + return (ER_KV_TakeAction(iAction, iEntity)); +} + +// Returns true if the entity is still alive (not killed) +static bool ER_KV_TakeAction(int action, int iEntity) +{ + switch (action) { + case ER_KV_ACTION_KILL: { + if (DEBUG_ER || IsDebugEnabled()) { + LogMessage("[%s] Killing!", ER_MODULE_NAME); + } + + KillEntity(iEntity); + + return false; + } + default: { + Debug_LogError(ER_MODULE_NAME, "ParseEntity Encountered bad action!"); + } + } + + return true; +} + +static bool ER_KillParachutist(int ent) +{ + char buf[32]; + GetCurrentMap(buf, sizeof(buf)); + + if (strcmp(buf, "c3m2_swamp") == 0) { + GetEntPropString(ent, Prop_Data, "m_iName", buf, sizeof(buf)); + + if (!strncmp(buf, "parachute_", 10)) { + KillEntity(ent); + + return true; + } + } + + return false; +} + +static bool ER_ReplaceTriggerHurtGhost(int ent) +{ + char buf[MAX_ENTITY_NAME_LENGTH]; + GetEdictClassname(ent, buf, sizeof(buf)); + + if (strcmp(buf, "trigger_hurt_ghost") == 0) { + // Replace trigger_hurt_ghost with trigger_hurt + int replace = CreateEntityByName("trigger_hurt"); + if (replace == -1) { + Debug_LogError(ER_MODULE_NAME, "Could not create trigger_hurt entity!"); + return false; + } + + // Get modelname + char model[PLATFORM_MAX_PATH]; + GetEntPropString(ent, Prop_Data, "m_ModelName", model, sizeof(model)); + + // Get position and rotation + float pos[3], ang[3]; + GetEntPropVector(ent, Prop_Send, "m_vecOrigin", pos); + GetEntPropVector(ent, Prop_Send, "m_angRotation", ang); + + // Kill the old one + KillEntity(ent); + + // Set the values for the new one + DispatchKeyValue(replace, "StartDisabled", "0"); + DispatchKeyValue(replace, "spawnflags", "67"); + DispatchKeyValue(replace, "damagetype", "32"); + DispatchKeyValue(replace, "damagemodel", "0"); + DispatchKeyValue(replace, "damagecap", "10000"); + DispatchKeyValue(replace, "damage", "10000"); + DispatchKeyValue(replace, "model", model); + + DispatchKeyValue(replace, "filtername", "filter_infected"); + + // Spawn the new one + TeleportEntity(replace, pos, ang, NULL_VECTOR); + DispatchSpawn(replace); + ActivateEntity(replace); + + return true; + } + + return false; +} + +public void ER_RoundStart_Event(Event hEvent, const char[] sEventName, bool bdontBroadcast) +{ + if (!IsPluginEnabled()) { + return; + } + + CreateTimer(0.3, ER_RoundStart_Timer, _, TIMER_FLAG_NO_MAPCHANGE); +} + +public Action ER_RoundStart_Timer(Handle hTimer) +{ + char sBuffer[MAX_ENTITY_NAME_LENGTH]; + if (DEBUG_ER || IsDebugEnabled()) { + LogMessage("[%s] Starting RoundStart Event", ER_MODULE_NAME); + } + + if (kERData != null) { + kERData.Rewind(); + } + + int iEntCount = GetEntityCount(); + + for (int ent = (MaxClients + 1); ent <= iEntCount; ent++) { + if (!IsValidEdict(ent)) { + continue; + } + + GetEdictClassname(ent, sBuffer, sizeof(sBuffer)); + + if (ER_bKillParachutist && ER_KillParachutist(ent)) { + //empty + } else if (ER_bReplaceGhostHurt && ER_ReplaceTriggerHurtGhost(ent)) { + //empty + } else if (kERData != null && kERData.JumpToKey(sBuffer)) { + if (DEBUG_ER || IsDebugEnabled()) { + LogMessage("[%s] Dealing with an instance of %s", ER_MODULE_NAME, sBuffer); + } + + kERData.GotoFirstSubKey(); + + do { + // Parse each entry for this entity's classname + // Stop if we run out of entries or we have killed the entity + if (!ER_KV_ParseEntity(kERData, ent)) { + break; + } + } while (kERData.GotoNextKey()); + + kERData.Rewind(); + } + } + + return Plugin_Stop; +} diff --git a/addons/sourcemod/scripting/confoglcompmod/FinaleSpawn.sp b/addons/sourcemod/scripting/confoglcompmod/FinaleSpawn.sp new file mode 100644 index 000000000..2bd6cd56a --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/FinaleSpawn.sp @@ -0,0 +1,100 @@ +#if defined __finale_spawn_included + #endinput +#endif +#define __finale_spawn_included + +#define FS_MODULE_NAME "FinaleSpawn" + +#define SPAWN_RANGE 150 + +static ConVar + FS_hEnabled = null; + +static bool + FS_bIsFinale = false, + FS_bEnabled = true; + +void FS_OnModuleStart() +{ + FS_hEnabled = CreateConVarEx("reduce_finalespawnrange", "1", "Adjust the spawn range on finales for infected, to normal spawning range", _, true, 0.0, true, 1.0); + + FS_bEnabled = FS_hEnabled.BoolValue; + FS_hEnabled.AddChangeHook(FS_ConVarChange); + + HookEvent("round_end", FS_Round_Event, EventHookMode_PostNoCopy); + HookEvent("round_start", FS_Round_Event, EventHookMode_PostNoCopy); + HookEvent("finale_start", FS_FinaleStart_Event, EventHookMode_PostNoCopy); +} + +public void FS_Round_Event(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + FS_bIsFinale = false; +} + +public void FS_FinaleStart_Event(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + FS_bIsFinale = true; +} + +public void FS_ConVarChange(ConVar hConVar, const char[] sOldValue, const char[] sNewValue) +{ + FS_bEnabled = FS_hEnabled.BoolValue; +} + +void FS_OnClientPutInServer(int client) +{ + SDKHook(client, SDKHook_PreThinkPost, HookCallback); +} + +public void HookCallback(int client) +{ + if (!FS_bIsFinale) { + return; + } + + //if (!FS_bEnabled) { // rework version + if (!FS_bEnabled || !IsPluginEnabled()) { // original + return; + } + + if (GetClientTeam(client) != L4D2Team_Infected) { + return; + } + + if (GetEntProp(client, Prop_Send, "m_isGhost", 1) != 1) { + return; + } + + if (GetEntProp(client, Prop_Send, "m_ghostSpawnState") == SPAWNFLAG_TOOCLOSE) { + if (!TooClose(client)) { + SetEntProp(client, Prop_Send, "m_ghostSpawnState", SPAWNFLAG_READY); + } + } +} + +static bool TooClose(int client) +{ + int index = 0; + float fInfLocation[3], fSurvLocation[3], fVector[3]; + GetClientAbsOrigin(client, fInfLocation); + + for (int i = 0; i < 4; i++) { + index = GetSurvivorIndex(i); + if (index == 0) { + continue; + } + + if (!IsPlayerAlive(index)) { + continue; + } + + GetClientAbsOrigin(index, fSurvLocation); + MakeVectorFromPoints(fInfLocation, fSurvLocation, fVector); + + if (GetVectorLength(fVector) <= SPAWN_RANGE) { + return true; + } + } + + return false; +} diff --git a/addons/sourcemod/scripting/confoglcompmod/GhostTank.sp b/addons/sourcemod/scripting/confoglcompmod/GhostTank.sp new file mode 100644 index 000000000..c20931b62 --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/GhostTank.sp @@ -0,0 +1,345 @@ +#if defined __ghost_tank_included + #endinput +#endif +#define __ghost_tank_included + +#define GT_MODULE_NAME "GhostTank" + +#define THROWRANGE 99999999.0 +#define FIREIMMUNITY_TIME 5.0 + +static int + g_iPasses = 0, + g_iGT_TankClient = 0; + +static bool + g_bGT_FinaleVehicleIncoming = false, + g_bGT_TankIsInPlay = false, + g_bGT_TankHasFireImmunity = false, + g_bGT_HordesDisabled = false; + +static Handle + g_hGT_TankDeathTimer = null; + +static ConVar + g_hGT_Enabled = null, + g_hCvarTankThrowAllowRange = null, + g_hCvarDirectorTankLotterySelectionTime = null, + g_hCvarZMobSpawnMinIntervalNormal = null, + g_hCvarZMobSpawnMaxIntervalNormal = null, + g_hCvarMobSpawnMinSize = null, + g_hCvarMobSpawnMaxSize = null, + g_hCvarSurvivorIncapHealth = null, + g_hGT_RemoveEscapeTank = null, + g_hGT_BlockPunchRock = null, + g_hGT_DisableTankHordes = null; // Disable Tank Hordes items + +void GT_OnModuleStart() +{ + g_hGT_Enabled = CreateConVarEx( \ + "boss_tank", \ + "1", \ + "Tank can't be prelight, frozen and ghost until player takes over, punch fix, and no rock throw for AI tank while waiting for player", \ + _, true, 0.0, true, 1.0 \ + ); + + g_hGT_RemoveEscapeTank = CreateConVarEx("remove_escape_tank", "1", "Remove tanks that spawn as the rescue vehicle is incoming on finales.", _, true, 0.0, true, 1.0); + g_hGT_DisableTankHordes = CreateConVarEx("disable_tank_hordes", "0", "Disable natural hordes while tanks are in play", _, true, 0.0, true, 1.0); + g_hGT_BlockPunchRock = CreateConVarEx("block_punch_rock", "0", "Block tanks from punching and throwing a rock at the same time", _, true, 0.0, true, 1.0); + + g_hCvarSurvivorIncapHealth = FindConVar("survivor_incap_health"); + g_hCvarTankThrowAllowRange = FindConVar("tank_throw_allow_range"); + g_hCvarDirectorTankLotterySelectionTime = FindConVar("director_tank_lottery_selection_time"); + g_hCvarZMobSpawnMinIntervalNormal = FindConVar("z_mob_spawn_min_interval_normal"); + g_hCvarZMobSpawnMaxIntervalNormal = FindConVar("z_mob_spawn_max_interval_normal"); + g_hCvarMobSpawnMinSize = FindConVar("z_mob_spawn_min_size"); + g_hCvarMobSpawnMaxSize = FindConVar("z_mob_spawn_max_size"); + + HookEvent("round_start", GT_RoundStart, EventHookMode_PostNoCopy); + HookEvent("tank_spawn", GT_TankSpawn); + HookEvent("player_death", GT_TankKilled); + HookEvent("player_hurt", GT_TankOnFire); + HookEvent("item_pickup", GT_ItemPickup); + HookEvent("player_incapacitated", GT_PlayerIncap); + HookEvent("finale_vehicle_incoming", GT_FinaleVehicleIncoming, EventHookMode_PostNoCopy); +} + +Action GT_OnTankSpawn_Forward() +{ + if (IsPluginEnabled() && g_hGT_RemoveEscapeTank.BoolValue && g_bGT_FinaleVehicleIncoming) { + return Plugin_Handled; + } + + return Plugin_Continue; +} + +Action GT_OnCThrowActivate() +{ + if (IsPluginEnabled() + && g_bGT_TankIsInPlay + && g_hGT_BlockPunchRock.BoolValue + && GetClientButtons(g_iGT_TankClient) & IN_ATTACK + ) { + if (IsDebugEnabled()) { + LogMessage("[%s] Blocking Haymaker on %L", GT_MODULE_NAME, g_iGT_TankClient); + } + + return Plugin_Handled; + } + + return Plugin_Continue; +} + +Action GT_OnSpawnMob_Forward(int &amount) +{ + // quick fix. needs normalize_hordes 1 + if (IsPluginEnabled()) { + if (IsDebugEnabled()) { + LogMessage("[%s] SpawnMob(%d), HordesDisabled: %d TimerDuration: %f Minimum: %f Remaining: %f", \ + GT_MODULE_NAME, amount, g_bGT_HordesDisabled, L4D2_CTimerGetCountdownDuration(L4D2CT_MobSpawnTimer), \ + g_hCvarZMobSpawnMinIntervalNormal.FloatValue, L4D2_CTimerGetRemainingTime(L4D2CT_MobSpawnTimer)); + } + + if (g_bGT_HordesDisabled) { + if (amount < g_hCvarMobSpawnMinSize.IntValue || amount > g_hCvarMobSpawnMaxSize.IntValue) { + return Plugin_Continue; + } + + if (!L4D2_CTimerIsElapsed(L4D2CT_MobSpawnTimer)) { + return Plugin_Continue; + } + + float duration = L4D2_CTimerGetCountdownDuration(L4D2CT_MobSpawnTimer); + if (duration < g_hCvarZMobSpawnMinIntervalNormal.FloatValue || duration > g_hCvarZMobSpawnMaxIntervalNormal.FloatValue) { + return Plugin_Continue; + } + + return Plugin_Handled; + } + } + + return Plugin_Continue; +} + +// Disable stasis when we're using GhostTank +Action GT_OnTryOfferingTankBot(bool &enterStasis) +{ + g_iPasses++; + + if (IsPluginEnabled()) { + if (g_hGT_Enabled.BoolValue) { + enterStasis = false; + } + + if (g_hGT_RemoveEscapeTank.BoolValue && g_bGT_FinaleVehicleIncoming) { + return Plugin_Handled; + } + } + + return Plugin_Continue; +} + +public void GT_FinaleVehicleIncoming(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + g_bGT_FinaleVehicleIncoming = true; + + if (g_bGT_TankIsInPlay && IsFakeClient(g_iGT_TankClient)) { + KickClient(g_iGT_TankClient); + GT_Reset(); + } +} + +public void GT_ItemPickup(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + if (!g_bGT_TankIsInPlay) { + return; + } + + char item[MAX_ENTITY_NAME_LENGTH]; + hEvent.GetString("item", item, sizeof(item)); + + if (strcmp(item, "tank_claw") != 0) { + return; + } + + g_iGT_TankClient = GetClientOfUserId(hEvent.GetInt("userid")); + + if (g_hGT_TankDeathTimer != null) { + KillTimer(g_hGT_TankDeathTimer); + g_hGT_TankDeathTimer = null; + } +} + +public void GT_RoundStart(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + g_bGT_FinaleVehicleIncoming = false; + GT_Reset(); +} + +public void GT_TankKilled(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + if (!g_bGT_TankIsInPlay) { + return; + } + + int client = GetClientOfUserId(hEvent.GetInt("userid")); + if (client != g_iGT_TankClient) { + return; + } + + g_hGT_TankDeathTimer = CreateTimer(1.0, GT_TankKilled_Timer); +} + +public void GT_TankSpawn(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + int client = GetClientOfUserId(hEvent.GetInt("userid")); + g_iGT_TankClient = client; + + if (g_bGT_TankIsInPlay) { + return; + } + + g_bGT_TankIsInPlay = true; + + if (g_hGT_DisableTankHordes.BoolValue) { + g_bGT_HordesDisabled = true; + } + + if (!IsPluginEnabled() || !g_hGT_Enabled.BoolValue) { + return; + } + + float fFireImmunityTime = FIREIMMUNITY_TIME; + float fSelectionTime = g_hCvarDirectorTankLotterySelectionTime.FloatValue; + + if (IsFakeClient(client)) { + GT_PauseTank(); + CreateTimer(fSelectionTime, GT_ResumeTankTimer); + fFireImmunityTime += fSelectionTime; + } + + CreateTimer(fFireImmunityTime, GT_FireImmunityTimer); +} + +public void GT_TankOnFire(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + int dmgtype = hEvent.GetInt("type"); + + if (!(dmgtype & DMG_BURN)) { //more performance + return; + } + + if (!g_bGT_TankIsInPlay || !g_bGT_TankHasFireImmunity || !IsPluginEnabled() || !g_hGT_Enabled.BoolValue) { + return; + } + + int client = GetClientOfUserId(hEvent.GetInt("userid")); + if (client < 1 || g_iGT_TankClient != client || !IsClientInGame(client) || GetClientTeam(client) != L4D2Team_Infected) { + return; + } + + ExtinguishEntity(client); + + int iSetHealth = GetClientHealth(client) + hEvent.GetInt("dmg_health"); + SetEntityHealth(client, iSetHealth); +} + +public void GT_PlayerIncap(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + if (!g_bGT_TankIsInPlay || !IsPluginEnabled() || !g_hGT_Enabled.BoolValue) { + return; + } + + char weapon[MAX_ENTITY_NAME_LENGTH]; + hEvent.GetString("weapon", weapon, sizeof(weapon)); + + if (strcmp(weapon, "tank_claw") != 0) { + return; + } + + int userid = hEvent.GetInt("userid"); + int client = GetClientOfUserId(userid); + if (client < 1 || !IsClientInGame(client) || GetClientTeam(client) != L4D2Team_Survivor) { + return; + } + + SetEntProp(client, Prop_Send, "m_isIncapacitated", 0, 1); + SetEntityHealth(client, 1); + + CreateTimer(0.4, GT_IncapTimer, userid, TIMER_FLAG_NO_MAPCHANGE); +} + +public Action GT_IncapTimer(Handle hTimer, int userid) +{ + int client = GetClientOfUserId(userid); + if (client > 0) { + SetEntProp(client, Prop_Send, "m_isIncapacitated", 1, 1); + SetEntityHealth(client, g_hCvarSurvivorIncapHealth.IntValue); + } + + return Plugin_Stop; +} + +public Action GT_ResumeTankTimer(Handle hTimer) +{ + GT_ResumeTank(); + + return Plugin_Stop; +} + +public Action GT_FireImmunityTimer(Handle hTimer) +{ + g_bGT_TankHasFireImmunity = false; + + return Plugin_Stop; +} + +static void GT_PauseTank() +{ + g_hCvarTankThrowAllowRange.SetFloat(THROWRANGE); + + if (!IsValidEntity(g_iGT_TankClient)) { + return; + } + + SetEntityMoveType(g_iGT_TankClient, MOVETYPE_NONE); + SetEntProp(g_iGT_TankClient, Prop_Send, "m_isGhost", 1, 1); +} + +static void GT_ResumeTank() +{ + g_hCvarTankThrowAllowRange.RestoreDefault(); + + if (!IsValidEntity(g_iGT_TankClient)) { + return; + } + + SetEntityMoveType(g_iGT_TankClient, MOVETYPE_CUSTOM); + SetEntProp(g_iGT_TankClient, Prop_Send, "m_isGhost", 0, 1); +} + +static void GT_Reset() +{ + g_iPasses = 0; + g_hGT_TankDeathTimer = null; + + if (g_bGT_HordesDisabled) { + g_bGT_HordesDisabled = false; + } + + g_bGT_TankIsInPlay = false; + g_bGT_TankHasFireImmunity = true; +} + +public Action GT_TankKilled_Timer(Handle hTimer) +{ + GT_Reset(); + + return Plugin_Stop; +} + +// For other modules to use +stock bool GT_IsTankInPlay() +{ + return (g_bGT_TankIsInPlay); +} diff --git a/addons/sourcemod/scripting/confoglcompmod/GhostWarp.sp b/addons/sourcemod/scripting/confoglcompmod/GhostWarp.sp new file mode 100644 index 000000000..076e7a23f --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/GhostWarp.sp @@ -0,0 +1,176 @@ +#if defined __ghost_warp_included + #endinput +#endif +#define __ghost_warp_included + +#define GW_MODULE_NAME "GhostWarp" + +static int + GW_iLastTarget[MAXPLAYERS + 1] = {-1, ...}; + +static bool + GW_bEnabled = true, + GW_bReload = false, + GW_bDelay[MAXPLAYERS + 1] = {false, ...}; + +static ConVar + GW_hGhostWarp = null, + GW_hGhostWarpReload = null; + +void GW_OnModuleStart() +{ + // GhostWarp + GW_hGhostWarp = CreateConVarEx("ghost_warp", "1", "Sets whether infected ghosts can right click for warp to next survivor", _, true, 0.0, true, 1.0); + GW_hGhostWarpReload = CreateConVarEx("ghost_warp_reload", "0", "Sets whether to use mouse2 or reload for ghost warp.", _, true, 0.0, true, 1.0); + + // Ghost Warp + GW_bEnabled = GW_hGhostWarp.BoolValue; + GW_bReload = GW_hGhostWarpReload.BoolValue; + + GW_hGhostWarp.AddChangeHook(GW_ConVarsChanged); + GW_hGhostWarpReload.AddChangeHook(GW_ConVarsChanged); + + RegConsoleCmd("sm_warptosurvivor", GW_Cmd_WarpToSurvivor); + + HookEvent("player_death", GW_PlayerDeath_Event); + HookEvent("round_start", GW_RoundStart); +} + +public void GW_ConVarsChanged(ConVar hConVar, const char[] sOldValue, const char[] sNewValue) +{ + GW_bEnabled = GW_hGhostWarp.BoolValue; + GW_bReload = GW_hGhostWarpReload.BoolValue; +} + +bool GW_OnPlayerRunCmd(int iClient, int iButtons) +{ + if (!IsPluginEnabled() || !GW_bEnabled || GW_bDelay[iClient]) { + return false; + } + + if (/*!IsClientInGame(iClient) || */GetClientTeam(iClient) != L4D2Team_Infected || GetEntProp(iClient, Prop_Send, "m_isGhost", 1) != 1) { + return false; + } + + if (GW_bReload && !(iButtons & IN_RELOAD)) { + return false; + } + + if (!GW_bReload && !(iButtons & IN_ATTACK2)) { + return false; + } + + GW_bDelay[iClient] = true; + CreateTimer(0.25, GW_ResetDelay, iClient, TIMER_FLAG_NO_MAPCHANGE); + GW_WarpToSurvivor(iClient, 0); + + return true; +} + +public void GW_RoundStart(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + for (int i = 1; i <= MaxClients; i++) { + GW_bDelay[i] = false; + GW_iLastTarget[i] = -1; + } +} + +public void GW_PlayerDeath_Event(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + int iClient = GetClientOfUserId(hEvent.GetInt("userid")); + + GW_iLastTarget[iClient] = -1; +} + +public Action GW_ResetDelay(Handle hTimer, any iClient) +{ + GW_bDelay[iClient] = false; + + return Plugin_Stop; +} + +public Action GW_Cmd_WarpToSurvivor(int iClient, int iArgs) +{ + if (iClient < 1 || iArgs != 1) { + return Plugin_Handled; + } + + if (!IsPluginEnabled() || !GW_bEnabled) { + return Plugin_Handled; + } + + if (GetClientTeam(iClient) != L4D2Team_Infected || GetEntProp(iClient, Prop_Send, "m_isGhost", 1) != 1) { + return Plugin_Handled; + } + + char sBuffer[2]; + GetCmdArg(1, sBuffer, sizeof(sBuffer)); + if (strlen(sBuffer) == 0) { + return Plugin_Handled; + } + + int iCharacter = StringToInt(sBuffer); + GW_WarpToSurvivor(iClient, iCharacter); + + return Plugin_Handled; +} + +static void GW_WarpToSurvivor(int iClient, int iCharacter) +{ + int iTarget = 0; + + if (iCharacter <= 0) { + iTarget = GW_FindNextSurvivor(iClient, GW_iLastTarget[iClient]); + } else if (iCharacter <= 4) { + iTarget = GetSurvivorIndex(iCharacter - 1); + } else { + return; + } + + if (iTarget == 0) { + return; + } + + // Prevent people from spawning and then warp to survivor + SetEntProp(iClient, Prop_Send, "m_ghostSpawnState", SPAWNFLAG_TOOCLOSE); + + float fPosition[3], fAnglestarget[3]; + GetClientAbsOrigin(iTarget, fPosition); + GetClientAbsAngles(iTarget, fAnglestarget); + + TeleportEntity(iClient, fPosition, fAnglestarget, NULL_VECTOR); +} + +static int GW_FindNextSurvivor(int iClient, int iCharacter) +{ + if (!IsAnySurvivorsAlive()) { + return 0; + } + + bool bHavelooped = false; + iCharacter++; + + if (iCharacter >= NUM_OF_SURVIVORS) { + iCharacter = 0; + } + + for (int i = iCharacter; i <= MaxClients; i++) { + if (i >= NUM_OF_SURVIVORS) { + if (bHavelooped) { + break; + } + + bHavelooped = true; + i = 0; + } + + if (GetSurvivorIndex(i) == 0) { + continue; + } + + GW_iLastTarget[iClient] = i; + return GetSurvivorIndex(i); + } + + return 0; +} diff --git a/addons/sourcemod/scripting/confoglcompmod/ItemTracking.sp b/addons/sourcemod/scripting/confoglcompmod/ItemTracking.sp new file mode 100644 index 000000000..c784b2c50 --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/ItemTracking.sp @@ -0,0 +1,612 @@ +#if defined __item_tracking_included + #endinput +#endif +#define __item_tracking_included + +#define IT_MODULE_NAME "ItemTracking" + +// Item lists for tracking/decoding/etc +enum /*ItemList*/ +{ + IL_PainPills, + IL_Adrenaline, + // Not sure we need these. + //IL_FirstAid, + //IL_Defib, + IL_PipeBomb, + IL_Molotov, + IL_VomitJar, + + ItemList_Size +}; + +// Names for cvars, kv, descriptions +// [ItemIndex][shortname = 0, fullname = 1, spawnname = 2] +enum /*ItemNames*/ +{ + IN_shortname, + IN_longname, + IN_officialname, + IN_modelname, + + ItemNames_Size +}; + +// Settings for item limiting. +/*enum ItemLimitSettings +{ + Handle:cvar, + limitnum +};*/ + +// For spawn entires adt_array +#if SOURCEMOD_V_MINOR > 9 +enum struct ItemTracking +{ + int IT_entity; + float IT_origins; + float IT_origins1; + float IT_origins2; + float IT_angles; + float IT_angles1; + float IT_angles2; +} +#else +enum ItemTracking +{ + IT_entity, + Float:IT_origins, + Float:IT_origins1, + Float:IT_origins2, + Float:IT_angles, + Float:IT_angles1, + Float:IT_angles2 +}; +#endif + +static const char g_sItemNames[ItemList_Size][ItemNames_Size][] = +{ + { + "pills", + "pain pills", + "pain_pills", + "painpills" + }, + { + "adrenaline", + "adrenaline shots", + "adrenaline", + "pipebomb" + }, + /*{ + "kits", + "first aid kits", + "first_aid_kit", + "medkit" + }, + { + "defib", + "defibrillators", + "defibrillator", + "defibrillator" + },*/ + { + "pipebomb", + "pipe bombs", + "pipe_bomb", + "pipebomb" + }, + { + "molotov", + "molotovs", + "molotov", + "molotov" + }, + { + "vomitjar", + "bile bombs", + "vomitjar", + "bile_flask" + } +}; + +static int + g_iItemLimits[ItemList_Size] = {0, ...}, // Current item limits array + g_iSaferoomCount[2] = {0, ...}; + +static bool + g_bIsRound1Over = false; // Is round 1 over? + +static ConVar + g_hCvarEnabled = null, + g_hSurvivorLimit = null, + g_hCvarConsistentSpawns = null, + g_hCvarMapSpecificSpawns = null, + g_hCvarLimits[ItemList_Size] = {null, ...}; // CVAR Handle Array for item limits + +static ArrayList + g_hItemSpawns[ItemList_Size] = {null, ...}; // ADT Array Handle for actual item spawns + +static StringMap + g_hItemListTrie = null; + +void IT_OnModuleStart() +{ + g_hCvarEnabled = CreateConVarEx("enable_itemtracking", "0", "Enable the itemtracking module", _, true, 0.0, true, 1.0); + g_hCvarConsistentSpawns = CreateConVarEx("itemtracking_savespawns", "0", "Keep item spawns the same on both rounds", _, true, 0.0, true, 1.0); + g_hCvarMapSpecificSpawns = CreateConVarEx("itemtracking_mapspecific", "0", "Change how mapinfo.txt overrides work. 0 = ignore mapinfo.txt, 1 = allow limit reduction, 2 = allow limit increases.", _, true, 0.0, true, 3.0); + + char sNameBuf[64], sCvarDescBuf[256]; + // Create itemlimit cvars + for (int i = 0; i < ItemList_Size; i++) { + Format(sNameBuf, sizeof(sNameBuf), "%s_limit", g_sItemNames[i][IN_shortname]); + Format(sCvarDescBuf, sizeof(sCvarDescBuf), "Limits the number of %s on each map. -1: no limit; >=0: limit to cvar value", g_sItemNames[i][IN_longname]); + + g_hCvarLimits[i] = CreateConVarEx(sNameBuf, "-1", sCvarDescBuf); + } + + // Create name translation trie + CreateItemListTrie(); + + // Create item spawns array; +#if SOURCEMOD_V_MINOR > 9 + ItemTracking curitem; +#else + ItemTracking curitem[ItemTracking]; +#endif + + for (int i = 0; i < ItemList_Size; i++) { + g_hItemSpawns[i] = new ArrayList(sizeof(curitem)); + } + + HookEvent("round_start", _IT_RoundStartEvent, EventHookMode_PostNoCopy); + HookEvent("round_end", _IT_RoundEndEvent, EventHookMode_PostNoCopy); + + g_hSurvivorLimit = FindConVar("survivor_limit"); +} + +void IT_OnMapStart() +{ + for (int i = 0; i < ItemList_Size; i++) { + g_iItemLimits[i] = g_hCvarLimits[i].IntValue; + } + + int iCvarValue = g_hCvarMapSpecificSpawns.IntValue; + if (iCvarValue) { + int itemlimit = 0, temp = 0; + KeyValues kOverrideLimits = new KeyValues("ItemLimits"); + CopyMapSubsection(kOverrideLimits, "ItemLimits"); + + for (int i = 0; i < ItemList_Size; i++) { + itemlimit = g_hCvarLimits[i].IntValue; + + temp = kOverrideLimits.GetNum(g_sItemNames[i][IN_officialname], itemlimit); + + if (((g_iItemLimits[i] > temp) && (iCvarValue & 1)) || ((g_iItemLimits[i] < temp) && (iCvarValue & 2))) { + g_iItemLimits[i] = temp; + } + + g_hItemSpawns[i].Clear(); + } + + delete kOverrideLimits; + } + + g_bIsRound1Over = false; +} + +public void _IT_RoundEndEvent(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + g_bIsRound1Over = true; +} + +public void _IT_RoundStartEvent(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + g_iSaferoomCount[START_SAFEROOM - 1] = 0; + g_iSaferoomCount[END_SAFEROOM - 1] = 0; + + // Mapstart happens after round_start most of the time, so we need to wait for g_bIsRound1Over. + // Plus, we don't want to have conflicts with EntityRemover. + CreateTimer(1.0, IT_RoundStartTimer, _, TIMER_FLAG_NO_MAPCHANGE); +} + +public Action IT_RoundStartTimer(Handle hTimer) +{ + if (!g_bIsRound1Over) { + // Round1 + if (IsModuleEnabled()) { + EnumAndElimSpawns(); + } + } else { + // Round2 + if (IsModuleEnabled()) { + if (g_hCvarConsistentSpawns.BoolValue) { + GenerateStoredSpawns(); + } else { + EnumAndElimSpawns(); + } + } + } + + return Plugin_Stop; +} + +static void EnumAndElimSpawns() +{ + if (IsDebugEnabled()) { + LogMessage("[%s] Resetting g_iSaferoomCount and Enumerating and eliminating spawns...", IT_MODULE_NAME); + } + + EnumerateSpawns(); + RemoveToLimits(); +} + +static void GenerateStoredSpawns() +{ + KillRegisteredItems(); + SpawnItems(); +} + +// l4d2lib plugin +// For 3.0 rounds library +/*public void L4D2_OnRealRoundStart(int roundNum) +{ + if (roundNum == 1) { + EnumerateSpawns(); + RemoveToLimits(); + } else { + // We kill off all items we recognize. + // Unlimited items will be replaced, limited items will be spawned, + // and killed items will stay killed + KillRegisteredItems(); + // Spawn up the same items that existed in round 1 + SpawnItems(); + } +}*/ + +// Produces the lookup trie for weapon spawn entities +// to translate to our ADT array of spawns +static void CreateItemListTrie() +{ + g_hItemListTrie = new StringMap(); + g_hItemListTrie.SetValue("weapon_pain_pills_spawn", IL_PainPills); + g_hItemListTrie.SetValue("weapon_pain_pills", IL_PainPills); + g_hItemListTrie.SetValue("weapon_adrenaline_spawn", IL_Adrenaline); + g_hItemListTrie.SetValue("weapon_adrenaline", IL_Adrenaline); + g_hItemListTrie.SetValue("weapon_pipe_bomb_spawn", IL_PipeBomb); + g_hItemListTrie.SetValue("weapon_pipe_bomb", IL_PipeBomb); + g_hItemListTrie.SetValue("weapon_molotov_spawn", IL_Molotov); + g_hItemListTrie.SetValue("weapon_molotov", IL_Molotov); + g_hItemListTrie.SetValue("weapon_vomitjar_spawn", IL_VomitJar); + g_hItemListTrie.SetValue("weapon_vomitjar", IL_VomitJar); +} + +static void KillRegisteredItems() +{ + int itemindex = 0, psychonic = GetEntityCount(); + int iSurvivorLimit = g_hSurvivorLimit.IntValue; + + for (int i = (MaxClients + 1); i <= psychonic; i++) { + if (!IsValidEdict(i)) { + continue; + } + + itemindex = GetItemIndexFromEntity(i); + if (itemindex >= 0/* && !IsEntityInSaferoom(i)*/) { + if (IsEntityInSaferoom(i, START_SAFEROOM) && g_iSaferoomCount[START_SAFEROOM - 1] < iSurvivorLimit) { + g_iSaferoomCount[START_SAFEROOM - 1]++; + } else if (IsEntityInSaferoom(i, END_SAFEROOM) && g_iSaferoomCount[END_SAFEROOM - 1] < iSurvivorLimit) { + g_iSaferoomCount[END_SAFEROOM - 1]++; + } else { + // Kill items we're tracking; + KillEntity(i); + /*if (!AcceptEntityInput(i, "kill")) { + Debug_LogError(IT_MODULE_NAME, "Error killing instance of item %s", g_sItemNames[itemindex][IN_longname]); + }*/ + } + } + } +} + +static void SpawnItems() +{ +#if SOURCEMOD_V_MINOR > 9 + ItemTracking curitem; +#else + ItemTracking curitem[ItemTracking]; +#endif + + float origins[3], angles[3]; + int arrsize = 0, itement = 0, wepid = 0; + char sModelname[PLATFORM_MAX_PATH]; + + for (int itemidx = 0; itemidx < ItemList_Size; itemidx++) { + Format(sModelname, sizeof(sModelname), "models/w_models/weapons/w_eq_%s.mdl", g_sItemNames[itemidx][IN_modelname]); + + arrsize = g_hItemSpawns[itemidx].Length; + + for (int idx = 0; idx < arrsize; idx++) { + #if SOURCEMOD_V_MINOR > 9 + g_hItemSpawns[itemidx].GetArray(idx, curitem, sizeof(curitem)); + #else + g_hItemSpawns[itemidx].GetArray(idx, curitem[0], sizeof(curitem)); + #endif + + GetSpawnOrigins(origins, curitem); + GetSpawnAngles(angles, curitem); + wepid = GetWeaponIDFromItemList(itemidx); + + if (IsDebugEnabled()) { + LogMessage("[%s] Spawning an instance of item %s (%d, wepid %d), number %d, at %.02f %.02f %.02f", \ + IT_MODULE_NAME, g_sItemNames[itemidx][IN_officialname], itemidx, wepid, idx, origins[0], origins[1], origins[2]); + } + + itement = CreateEntityByName("weapon_spawn"); + if (itement == -1) { + continue; + } + + SetEntProp(itement, Prop_Send, "m_weaponID", wepid); + SetEntityModel(itement, sModelname); + DispatchKeyValue(itement, "count", "1"); + TeleportEntity(itement, origins, angles, NULL_VECTOR); + DispatchSpawn(itement); + SetEntityMoveType(itement, MOVETYPE_NONE); + } + } +} + +static void EnumerateSpawns() +{ +#if SOURCEMOD_V_MINOR > 9 + ItemTracking curitem; +#else + ItemTracking curitem[ItemTracking]; +#endif + + float origins[3], angles[3]; + int itemindex = 0, psychonic = GetEntityCount(); + int iSurvivorLimit = g_hSurvivorLimit.IntValue; + + for (int i = (MaxClients + 1); i <= psychonic; i++) { + if (!IsValidEdict(i)) { + continue; + } + + itemindex = GetItemIndexFromEntity(i); + if (itemindex >= 0/* && !IsEntityInSaferoom(i)*/) { + if (IsEntityInSaferoom(i, START_SAFEROOM)) { + if (g_iSaferoomCount[START_SAFEROOM - 1] < iSurvivorLimit) { + g_iSaferoomCount[START_SAFEROOM - 1]++; + } else { + KillEntity(i); + /*if (!AcceptEntityInput(i, "kill")) { + Debug_LogError(IT_MODULE_NAME, "Error killing instance of item %s", g_sItemNames[itemindex][IN_longname]); + }*/ + } + } else if (IsEntityInSaferoom(i, END_SAFEROOM)) { + if (g_iSaferoomCount[END_SAFEROOM - 1] < iSurvivorLimit) { + g_iSaferoomCount[END_SAFEROOM - 1]++; + } else { + KillEntity(i); + /*if (!AcceptEntityInput(i, "kill")) { + Debug_LogError(IT_MODULE_NAME, "Error killing instance of item %s", g_sItemNames[itemindex][IN_longname]); + }*/ + } + } else { + int mylimit = g_iItemLimits[itemindex]; + if (IsDebugEnabled()) { + LogMessage("[%s] Found an instance of item %s (%d), with limit %d", IT_MODULE_NAME, g_sItemNames[itemindex][IN_longname], itemindex, mylimit); + } + + // Item limit is zero, justkill it as we find it + if (!mylimit) { + if (IsDebugEnabled()) { + LogMessage("[%s] Killing spawn", IT_MODULE_NAME); + } + + KillEntity(i); + /*if (!AcceptEntityInput(i, "kill")) { + Debug_LogError(IT_MODULE_NAME, "Error killing instance of item %s", g_sItemNames[itemindex][IN_longname]); + }*/ + } else { + // Store entity, angles, origin + #if SOURCEMOD_V_MINOR > 9 + curitem.IT_entity = i; + #else + curitem[IT_entity] = i; + #endif + + GetEntPropVector(i, Prop_Send, "m_vecOrigin", origins); + GetEntPropVector(i, Prop_Send, "m_angRotation", angles); + + if (IsDebugEnabled()) { + LogMessage("[%s] Saving spawn #%d at %.02f %.02f %.02f", IT_MODULE_NAME, g_hItemSpawns[itemindex].Length, origins[0], origins[1], origins[2]); + } + + SetSpawnOrigins(origins, curitem); + SetSpawnAngles(angles, curitem); + + // Push this instance onto our array for that item + #if SOURCEMOD_V_MINOR > 9 + g_hItemSpawns[itemindex].PushArray(curitem, sizeof(curitem)); + #else + g_hItemSpawns[itemindex].PushArray(curitem[0], sizeof(curitem)); + #endif + } + } + } + } +} + +static void RemoveToLimits() +{ +#if SOURCEMOD_V_MINOR > 9 + ItemTracking curitem; +#else + ItemTracking curitem[ItemTracking]; +#endif + + int curlimit = 0, killidx = 0; + + for (int itemidx = 0; itemidx < ItemList_Size; itemidx++) { + curlimit = g_iItemLimits[itemidx]; + + if (curlimit > 0) { + // Kill off item spawns until we've reduced the item to the limit + while (g_hItemSpawns[itemidx].Length > curlimit) { + // Pick a random + killidx = GetURandomIntRange(0, (g_hItemSpawns[itemidx].Length - 1)); + + if (IsDebugEnabled()) { + LogMessage("[%s] Killing randomly chosen %s (%d) #%d", IT_MODULE_NAME, g_sItemNames[itemidx][IN_longname], itemidx, killidx); + } + + #if SOURCEMOD_V_MINOR > 9 + g_hItemSpawns[itemidx].GetArray(killidx, curitem, sizeof(curitem)); + + if (IsValidEdict(curitem.IT_entity)) { + KillEntity(curitem.IT_entity); + + /*if (!AcceptEntityInput(curitem.IT_entity, "kill")) { + Debug_LogError(IT_MODULE_NAME, "Error killing instance of item %s", g_sItemNames[itemidx][IN_longname]); + }*/ + } + #else + g_hItemSpawns[itemidx].GetArray(killidx, curitem[0], sizeof(curitem)); + + if (IsValidEdict(curitem[IT_entity])) { + KillEntity(curitem[IT_entity]); + + /*if (!AcceptEntityInput(curitem[IT_entity], "kill")) { + Debug_LogError(IT_MODULE_NAME, "Error killing instance of item %s", g_sItemNames[itemidx][IN_longname]); + }*/ + } + #endif + + g_hItemSpawns[itemidx].Erase(killidx); + } + } + // If limit is 0, they're already dead. If it's negative, we kill nothing. + } +} + +#if SOURCEMOD_V_MINOR > 9 +static void SetSpawnOrigins(const float buf[3], ItemTracking spawn) +{ + spawn.IT_origins = buf[0]; + spawn.IT_origins1 = buf[1]; + spawn.IT_origins2 = buf[2]; +} + +static void SetSpawnAngles(const float buf[3], ItemTracking spawn) +{ + spawn.IT_angles = buf[0]; + spawn.IT_angles1 = buf[1]; + spawn.IT_angles2 = buf[2]; +} + +static void GetSpawnOrigins(float buf[3], const ItemTracking spawn) +{ + buf[0] = spawn.IT_origins; + buf[1] = spawn.IT_origins1; + buf[2] = spawn.IT_origins2; +} + +static void GetSpawnAngles(float buf[3], const ItemTracking spawn) +{ + buf[0] = spawn.IT_angles; + buf[1] = spawn.IT_angles1; + buf[2] = spawn.IT_angles2; +} +#else +static void SetSpawnOrigins(const float buf[3], ItemTracking spawn[ItemTracking]) +{ + spawn[IT_origins] = buf[0]; + spawn[IT_origins1] = buf[1]; + spawn[IT_origins2] = buf[2]; +} + +static void SetSpawnAngles(const float buf[3], ItemTracking spawn[ItemTracking]) +{ + spawn[IT_angles] = buf[0]; + spawn[IT_angles1] = buf[1]; + spawn[IT_angles2] = buf[2]; +} + +static void GetSpawnOrigins(float buf[3], const ItemTracking spawn[ItemTracking]) +{ + buf[0] = spawn[IT_origins]; + buf[1] = spawn[IT_origins1]; + buf[2] = spawn[IT_origins2]; +} + +static void GetSpawnAngles(float buf[3], const ItemTracking spawn[ItemTracking]) +{ + buf[0] = spawn[IT_angles]; + buf[1] = spawn[IT_angles1]; + buf[2] = spawn[IT_angles2]; +} +#endif + +static int GetWeaponIDFromItemList(int id) +{ + switch (id) { + case IL_PainPills: { + return WEPID_PAIN_PILLS; + } + case IL_Adrenaline: { + return WEPID_ADRENALINE; + } + case IL_PipeBomb: { + return WEPID_PIPE_BOMB; + } + case IL_Molotov: { + return WEPID_MOLOTOV; + } + case IL_VomitJar: { + return WEPID_VOMITJAR; + } + } + + return -1; +} + +static int GetItemIndexFromEntity(int entity) +{ + char classname[MAX_ENTITY_NAME_LENGTH]; + int index; + + GetEdictClassname(entity, classname, sizeof(classname)); + if (g_hItemListTrie.GetValue(classname, index)) { + return index; + } + + if (strcmp(classname, "weapon_spawn") == 0 || strcmp(classname, "weapon_item_spawn") == 0) { + int id = GetEntProp(entity, Prop_Send, "m_weaponID"); + switch (id) { + case WEPID_VOMITJAR: { + return IL_VomitJar; + } + case WEPID_PIPE_BOMB: { + return IL_PipeBomb; + } + case WEPID_MOLOTOV: { + return IL_Molotov; + } + case WEPID_PAIN_PILLS: { + return IL_PainPills; + } + case WEPID_ADRENALINE: { + return IL_Adrenaline; + } + } + } + + return -1; +} + +static bool IsModuleEnabled() +{ + return (IsPluginEnabled() && g_hCvarEnabled.BoolValue); +} diff --git a/addons/sourcemod/scripting/confoglcompmod/MapInfo.sp b/addons/sourcemod/scripting/confoglcompmod/MapInfo.sp new file mode 100644 index 000000000..b96f828c3 --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/MapInfo.sp @@ -0,0 +1,511 @@ +#if defined __map_info_included + #endinput +#endif +#define __map_info_included + +#define DEBUG_MI 0 +#define MI_MODULE_NAME "MapInfo" + +static int + iMapMaxDistance = 0, + iIsInEditMode[MAXPLAYERS + 1] = {0, ...}; + +static bool + MapDataAvailable = false; + +static float + Start_Point[3] = {0.0, ...}, + End_Point[3] = {0.0, ...}, + Start_Dist = 0.0, + Start_Extra_Dist = 0.0, + End_Dist = 0.0, + fLocTemp[MAXPLAYERS + 1][3]; + +static KeyValues + kMIData = null; + +void MI_APL() +{ + CreateNative("LGO_IsMapDataAvailable", _native_IsMapDataAvailable); + CreateNative("LGO_GetMapValueInt", _native_GetMapValueInt); + CreateNative("LGO_GetMapValueFloat", _native_GetMapValueFloat); + CreateNative("LGO_GetMapValueVector", _native_GetMapValueVector); + CreateNative("LGO_GetMapValueString", _native_GetMapValueString); + CreateNative("LGO_CopyMapSubsection", _native_CopyMapSubsection); +} + +void MI_OnModuleStart() +{ + MI_KV_Load(); + + //RegAdminCmd("confogl_midata_reload", MI_KV_CmdReload, ADMFLAG_CONFIG); + RegAdminCmd("confogl_midata_save", MI_KV_CmdSave, ADMFLAG_CONFIG); + RegAdminCmd("confogl_save_location", MI_KV_CmdSaveLoc, ADMFLAG_CONFIG); + + HookEvent("player_disconnect", PlayerDisconnect_Event); +} + +void MI_OnMapStart() +{ + MI_KV_UpdateMapInfo(); +} + +void MI_OnMapEnd() +{ + kMIData.Rewind(); + + MapDataAvailable = false; + + // 0 - server index? + for (int i = 0; i <= MaxClients; i++) { + iIsInEditMode[i] = 0; + } +} + +void MI_OnModuleEnd() +{ + MI_KV_Close(); +} + +public void PlayerDisconnect_Event(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + int client = GetClientOfUserId(hEvent.GetInt("userid")); + if (client > 0 && client <= MaxClients) { + iIsInEditMode[client] = 0; + } +} + +public Action MI_KV_CmdSave(int client, int args) +{ + char sCurMap[128]; + GetCurrentMap(sCurMap, sizeof(sCurMap)); + + if (kMIData.JumpToKey(sCurMap, true)) { + kMIData.SetVector("start_point", Start_Point); + kMIData.SetFloat("start_dist", Start_Dist); + kMIData.SetFloat("start_extra_dist", Start_Extra_Dist); + + char sNameBuff[PLATFORM_MAX_PATH]; + BuildConfigPath(sNameBuff, sizeof(sNameBuff), "mapinfo.txt"); + + kMIData.Rewind(); + kMIData.ExportToFile(sNameBuff); + + ReplyToCommand(client, "%s has been added to %s.", sCurMap, sNameBuff); + } + + return Plugin_Handled; +} + +public Action MI_KV_CmdSaveLoc(int client, int args) +{ + bool updateinfo = false; + char sCurMap[128]; + GetCurrentMap(sCurMap, sizeof(sCurMap)); + + if (!iIsInEditMode[client]) { + if (!args) { + ReplyToCommand(client, "Move to the location of the medkits, then enter the point type (start_point or end_point)"); + return Plugin_Handled; + } + + char sBuffer[16]; + GetCmdArg(1, sBuffer, sizeof(sBuffer)); + + if (strcmp(sBuffer, "start_point", true) == 0) { + iIsInEditMode[client] = 1; + ReplyToCommand(client, "Move a few feet from the medkits and enter this command again to set the start_dist for this point"); + } else if (strcmp(sBuffer, "end_point", true) == 0) { + iIsInEditMode[client] = 2; + ReplyToCommand(client, "Move to the farthest point in the saferoom and enter this command again to set the end_dist for this point"); + } else { + ReplyToCommand(client, "Please enter the location type: start_point, end_point"); + return Plugin_Handled; + } + + if (kMIData.JumpToKey(sCurMap, true)) { + GetClientAbsOrigin(client, fLocTemp[client]); + kMIData.SetVector(sBuffer, fLocTemp[client]); + } + + updateinfo = true; + } else if (iIsInEditMode[client] == 1) { + iIsInEditMode[client] = 3; + + float fDistLoc[3], fDistance; + GetClientAbsOrigin(client, fDistLoc); + + fDistance = GetVectorDistance(fDistLoc, fLocTemp[client]); + if (kMIData.JumpToKey(sCurMap, true)) { + kMIData.SetFloat("start_dist", fDistance); + } + + ReplyToCommand(client, "Move to the farthest point in the saferoom and enter this command again to set start_extra_dist for this point"); + + updateinfo = true; + } else if (iIsInEditMode[client] == 2) { + iIsInEditMode[client] = 0; + + float fDistLoc[3], fDistance; + GetClientAbsOrigin(client, fDistLoc); + + fDistance = GetVectorDistance(fDistLoc, fLocTemp[client]); + if (kMIData.JumpToKey(sCurMap, true)) { + kMIData.SetFloat("end_dist", fDistance); + } + + updateinfo = true; + } else if (iIsInEditMode[client] == 3) { + iIsInEditMode[client] = 0; + + float fDistLoc[3], fDistance; + GetClientAbsOrigin(client, fDistLoc); + + fDistance = GetVectorDistance(fDistLoc, fLocTemp[client]); + if (kMIData.JumpToKey(sCurMap, true)) { + kMIData.SetFloat("start_extra_dist", fDistance); + } + + updateinfo = true; + } + + if (updateinfo) { + char sNameBuff[PLATFORM_MAX_PATH]; + BuildConfigPath(sNameBuff, sizeof(sNameBuff), "mapinfo.txt"); + + kMIData.Rewind(); + kMIData.ExportToFile(sNameBuff); + + ReplyToCommand(client, "mapinfo.txt has been updated!"); + } + + return Plugin_Handled; +} + +static void MI_KV_Close() +{ + if (kMIData != null) { + delete kMIData; + kMIData = null; + } +} + +static void MI_KV_Load() +{ + char sNameBuff[PLATFORM_MAX_PATH]; + + if (DEBUG_MI || IsDebugEnabled()) { + LogMessage("[%s] Loading MapInfo KeyValues", MI_MODULE_NAME); + } + + kMIData = new KeyValues("MapInfo"); + BuildConfigPath(sNameBuff, sizeof(sNameBuff), "mapinfo.txt"); //Build our filepath + if (!kMIData.ImportFromFile(sNameBuff)) { + Debug_LogError(MI_MODULE_NAME, "Couldn't load MapInfo data!"); + MI_KV_Close(); + return; + } +} + +static void MI_KV_UpdateMapInfo() +{ + char sCurMap[128]; + GetCurrentMap(sCurMap, sizeof(sCurMap)); + + if (kMIData.JumpToKey(sCurMap)) { + kMIData.GetVector("start_point", Start_Point); + kMIData.GetVector("end_point", End_Point); + + Start_Dist = kMIData.GetFloat("start_dist"); + Start_Extra_Dist = kMIData.GetFloat("start_extra_dist"); + End_Dist = kMIData.GetFloat("end_dist"); + + iMapMaxDistance = kMIData.GetNum("max_distance", -1); + + // kMIData.Rewind(); + MapDataAvailable = true; + } else { + MapDataAvailable = false; + Start_Dist = FindStartPointHeuristic(Start_Point); + if (Start_Dist > 0.0) { + // This is the largest Start Extra Dist we've encountered; + // May be too much + Start_Extra_Dist = 500.0; + } else { + ZeroVector(Start_Point); + Start_Dist = -1.0; + Start_Extra_Dist = -1.0; + } + + ZeroVector(End_Point); + End_Dist = -1.0; + iMapMaxDistance = -1; + LogMessage("[%s] MapInfo for %s is missing.", MI_MODULE_NAME, sCurMap); + } + + // Let's leave MIData on the current map + // kMIData.Rewind(); +} + +static float FindStartPointHeuristic(float result[3]) +{ + char entclass[MAX_ENTITY_NAME_LENGTH]; + float kitOrigin[4][3], averageOrigin[3]; + int kits = 0, entcount = GetEntityCount(); + + for (int iEntity = (MaxClients + 1); iEntity <= entcount && kits < 4; iEntity++) { + if (!IsValidEdict(iEntity)) { + continue; + } + + GetEdictClassname(iEntity, entclass, sizeof(entclass)); + if (strcmp(entclass, "weapon_first_aid_kit_spawn") == 0) { + GetEntPropVector(iEntity, Prop_Send, "m_vecOrigin", kitOrigin[kits]); + AddToVector(averageOrigin, kitOrigin[kits]); + kits++; + } + } + + if (kits < 4) { + return -1.0; + } + + ScaleVector(averageOrigin, 0.25); + + float greatestDist, tempDist; + for (int i = 0; i < 4; i++) { + tempDist = GetVectorDistance(averageOrigin, kitOrigin[i]); + + if (tempDist > greatestDist) { + greatestDist = tempDist; + } + } + + CopyVector(result, averageOrigin); + return (greatestDist + 1.0); +} + +// Old Functions (Avoid using these, use the ones below) +stock float GetMapStartOriginX() +{ + return Start_Point[0]; +} + +stock float GetMapStartOriginY() +{ + return Start_Point[1]; +} + +stock float GetMapStartOriginZ() +{ + return Start_Point[2]; +} + +stock float GetMapEndOriginX() +{ + return End_Point[0]; +} + +stock float GetMapEndOriginY() +{ + return End_Point[1]; +} + +stock float GetMapEndOriginZ() +{ + return End_Point[2]; +} + +// New Super Awesome Functions!!! +stock int GetCustomMapMaxScore() +{ + return iMapMaxDistance; +} + +stock bool IsMapDataAvailable() +{ + return MapDataAvailable; +} + +/** + * Determines if an entity is in a start or end saferoom (based on mapinfo.txt or automatically generated info) + * + * @param ent The entity to be checked + * @param saferoom START_SAFEROOM (1) = Start saferoom, END_SAFEROOM (2) = End saferoom (including finale area), 3 = both + * @return True if it is one of the specified saferoom(s) + * False if it is not in the specified saferoom(s) + * False if no saferoom specified + */ +stock bool IsEntityInSaferoom(int ent, int saferoom = 3) //ItemTracking (commented out) +{ + float origins[3]; + GetEntPropVector(ent, Prop_Send, "m_vecOrigin", origins); + + if ((saferoom & START_SAFEROOM) + && (GetVectorDistance(origins, Start_Point) <= ((Start_Extra_Dist > Start_Dist) ? Start_Extra_Dist : Start_Dist)) + ) { + return true; + } else if ((saferoom & END_SAFEROOM) && (GetVectorDistance(origins, End_Point) <= End_Dist)) { + return true; + } else { + return false; + } + +// return ((GetVectorDistance(origins, Start_Point) <= ((Start_Extra_Dist > Start_Dist) ? Start_Extra_Dist : Start_Dist)) +// || (GetVectorDistance(origins, End_Point) <= End_Dist)); +} + +stock int GetMapValueInt(const char[] key, int defvalue = 0) //BossSpawning +{ + return kMIData.GetNum(key, defvalue); +} + +stock float GetMapValueFloat(const char[] key, float defvalue = 0.0) //BossSpawning +{ + return kMIData.GetFloat(key, defvalue); +} + +stock void GetMapValueVector(const char[] key, float vector[3], float defvalue[3] = NULL_VECTOR) //BossSpawning +{ + kMIData.GetVector(key, vector, defvalue); +} + +stock void GetMapValueString(const char[] key, char[] value, const int maxlength, const char[] defvalue) +{ + kMIData.GetString(key, value, maxlength, defvalue); +} + +stock void CopyMapSubsection(KeyValues kv, const char[] section) //ItemTracking +{ + if (kMIData.JumpToKey(section, false)) { + kMIData.Import(kv); // KvCopySubkeys(kMIData, kv); + kMIData.GoBack(); + } +} + +stock void GetMapStartOrigin(float origin[3]) //not used +{ + origin[0] = Start_Point[0]; + origin[1] = Start_Point[1]; + origin[2] = Start_Point[2]; +} + +stock void GetMapEndOrigin(float origin[3]) //not used +{ + origin[0] = End_Point[0]; + origin[1] = End_Point[1]; + origin[2] = End_Point[2]; +} + +stock float GetMapEndDist() //WeaponInformation use it +{ + return End_Dist; +} + +stock float GetMapStartDist() //WeaponInformation use it +{ + return Start_Dist; +} + +stock float GetMapStartExtraDist() //WeaponInformation use it +{ + return Start_Extra_Dist; +} + +// Natives +public int _native_IsMapDataAvailable(Handle plugin, int numParams) +{ + return IsMapDataAvailable(); +} + +public int _native_GetMapValueInt(Handle plugin, int numParams) +{ + int iLen = 0; + GetNativeStringLength(1, iLen); + + int iNewLen = iLen + 1; + char[] sKey = new char[iNewLen]; + GetNativeString(1, sKey, iNewLen); + + int iDefVal = GetNativeCell(2); + return GetMapValueInt(sKey, iDefVal); +} + +#if SOURCEMOD_V_MINOR > 9 +public any _native_GetMapValueFloat(Handle plugin, int numParams) +#else +public int _native_GetMapValueFloat(Handle plugin, int numParams) +#endif +{ + int iLen = 0; + GetNativeStringLength(1, iLen); + + int iNewLen = iLen + 1; + char[] sKey = new char[iNewLen]; + GetNativeString(1, sKey, iNewLen); + + float iDefVal = GetNativeCell(2); + +#if SOURCEMOD_V_MINOR > 9 + return GetMapValueFloat(sKey, iDefVal); +#else + return view_as(GetMapValueFloat(sKey, iDefVal)); +#endif +} + +public int _native_GetMapValueVector(Handle plugin, int numParams) +{ + int iLen = 0; + GetNativeStringLength(1, iLen); + + int iNewLen = iLen + 1; + char[] sKey = new char[iNewLen]; + GetNativeString(1, sKey, iNewLen); + + float fDefVal[3], fValue[3]; + GetNativeArray(3, fDefVal, sizeof(fDefVal)); + GetMapValueVector(sKey, fValue, fDefVal); + + SetNativeArray(2, fValue, sizeof(fValue)); + return 1; +} + +public int _native_GetMapValueString(Handle plugin, int numParams) +{ + int iLen = 0; + GetNativeStringLength(1, iLen); + + int iNewLen = iLen + 1; + char[] sKey = new char[iNewLen]; + GetNativeString(1, sKey, iNewLen); + + GetNativeStringLength(4, iLen); + + iNewLen = iLen + 1; + char[] sDefVal = new char[iNewLen]; + GetNativeString(4, sDefVal, iNewLen); + + iLen = GetNativeCell(3); + + iNewLen = iLen + 1; + char[] sBuf = new char[iNewLen]; + GetMapValueString(sKey, sBuf, iNewLen, sDefVal); + + SetNativeString(2, sBuf, iNewLen); + return 1; +} + +public int _native_CopyMapSubsection(Handle plugin, int numParams) +{ + int iLen = 0; + GetNativeStringLength(2, iLen); + + int iNewLen = iLen + 1; + char[] sKey = new char[iNewLen]; + GetNativeString(2, sKey, iNewLen); + + KeyValues hKv = GetNativeCell(1); + CopyMapSubsection(hKv, sKey); + + return 1; +} diff --git a/addons/sourcemod/scripting/confoglcompmod/PasswordSystem.sp b/addons/sourcemod/scripting/confoglcompmod/PasswordSystem.sp new file mode 100644 index 000000000..74df8450e --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/PasswordSystem.sp @@ -0,0 +1,161 @@ +#if defined __password_system_included + #endinput +#endif +#define __password_system_included + +#define PS_MODULE_NAME "PasswordSystem" + +static char + PS_sPassword[128] = "\0"; + +static bool + PS_bIsPassworded = false, + PS_bSuppress = false; + +static ConVar + PS_hReloaded = null, + PS_hPassword = null; + +void PS_OnModuleStart() +{ + PS_hPassword = CreateConVarEx( \ + "password", \ + "", \ + "Set a password on the server, if empty password disabled. See Confogl's wiki for more information", \ + FCVAR_DONTRECORD|FCVAR_PROTECTED \ + ); + + PS_hReloaded = FindConVarEx("password_reloaded"); + + if (PS_hReloaded == null) { + PS_hReloaded = CreateConVarEx( \ + "password_reloaded", \ + "", \ + "DONT TOUCH THIS CVAR! This will is to make sure that the password gets set upon the plugin is reloaded", \ + FCVAR_DONTRECORD|FCVAR_UNLOGGED \ + ); + } else { + char sBuffer[128]; + PS_hReloaded.GetString(sBuffer, sizeof(sBuffer)); + + PS_hPassword.SetString(sBuffer); + PS_hReloaded.SetString(""); + + PS_hPassword.GetString(PS_sPassword, sizeof(PS_sPassword)); + + PS_bIsPassworded = true; + PS_SetPasswordOnClients(); + } + + PS_hPassword.AddChangeHook(PS_ConVarChange); + + HookEvent("player_disconnect", PS_SuppressDisconnectMsg, EventHookMode_Pre); +} + +void PS_OnModuleEnd() +{ + if (!PS_bIsPassworded) { + return; + } + + PS_hReloaded.SetString(PS_sPassword); +} + +static void PS_CheckPassword(int client) +{ + if (!PS_bIsPassworded || !IsPluginEnabled()) { + return; + } + + CreateTimer(0.1, PS_CheckPassword_Timer, client, TIMER_REPEAT); +} + +public Action PS_CheckPassword_Timer(Handle hTimer, any client) +{ + if (!IsClientConnected(client) || IsFakeClient(client)) { + return Plugin_Stop; + } + + if (!IsClientInGame(client)) { + return Plugin_Continue; + } + + QueryClientConVar(client, "sv_password", PS_ConVarDone); + + return Plugin_Stop; +} + +public void PS_ConVarDone(QueryCookie cookie, int client, ConVarQueryResult result, const char[] cvarName, const char[] cvarValue, any value) +{ + if (result == ConVarQuery_Okay) { + char buffer[128]; + PS_hPassword.GetString(buffer, sizeof(buffer)); + + if (strcmp(buffer, cvarValue) == 0) { + return; + } + } + + PS_bSuppress = true; + KickClient(client, "Bad password"); +} + +public void PS_ConVarChange(ConVar convar, const char[] oldValue, const char[] newValue) +{ + PS_hPassword.GetString(PS_sPassword, sizeof(PS_sPassword)); + + if (strlen(PS_sPassword) > 0) { + PS_bIsPassworded = true; + PS_SetPasswordOnClients(); + } else { + PS_bIsPassworded = false; + } +} + +public Action PS_SuppressDisconnectMsg(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + if (bDontBroadcast || !PS_bSuppress) { + return Plugin_Continue; + } + + char clientName[33], networkID[22], reason[65]; + hEvent.GetString("name", clientName, sizeof(clientName)); + hEvent.GetString("networkid", networkID, sizeof(networkID)); + hEvent.GetString("reason", reason, sizeof(reason)); + + Handle newEvent = CreateEvent("player_disconnect", true); + SetEventInt(newEvent, "userid", hEvent.GetInt("userid")); + SetEventString(newEvent, "reason", reason); + SetEventString(newEvent, "name", clientName); + SetEventString(newEvent, "networkid", networkID); + FireEvent(newEvent, true); + + PS_bSuppress = false; + + return Plugin_Handled; +} + +void PS_OnMapEnd() +{ + PS_SetPasswordOnClients(); +} + +void PS_OnClientPutInServer(int client) +{ + PS_CheckPassword(client); +} + +static void PS_SetPasswordOnClients() +{ + char pwbuffer[128]; + PS_hPassword.GetString(pwbuffer, sizeof(pwbuffer)); + + for (int client = 1; client <= MaxClients; client++) { + if (!IsClientInGame(client) || IsFakeClient(client)){ + continue; + } + + LogMessage("[%s] Set password on %N, password %s", PS_MODULE_NAME, client, pwbuffer); + ClientCommand(client, "sv_password \"%s\"", pwbuffer); + } +} diff --git a/addons/sourcemod/scripting/confoglcompmod/ReqMatch.sp b/addons/sourcemod/scripting/confoglcompmod/ReqMatch.sp new file mode 100644 index 000000000..923fbfb03 --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/ReqMatch.sp @@ -0,0 +1,391 @@ +#if defined __reg_match_included + #endinput +#endif +#define __reg_match_included + +#define RM_DEBUG 0 +#define RM_MODULE_NAME "ReqMatch" + +#define MAPRESTARTTIME 3.0 +#define RESETMINTIME 60.0 + +static bool + //RM_bMatchRequest[2] = {false, ...}, + RM_bIsMatchModeLoaded = false, + RM_bIsAMatchActive = false, + RM_bIsPluginsLoaded = false, + RM_bIsMapRestarted = false; + +static Handle + RM_hFwdMatchLoad = null, + RM_hFwdMatchUnload = null; + +static ConVar + RM_hSbAllBotGame = null, + RM_hDoRestart = null, + //RM_hAllowVoting = null, + RM_hReloaded = null, + RM_hAutoLoad = null, + RM_hAutoCfg = null, + RM_hConfigFile_On = null, + RM_hConfigFile_Plugins = null, + RM_hConfigFile_Off = null; + +void RM_APL() +{ + RM_hFwdMatchLoad = CreateGlobalForward("LGO_OnMatchModeLoaded", ET_Ignore); + RM_hFwdMatchUnload = CreateGlobalForward("LGO_OnMatchModeUnloaded", ET_Ignore); + + CreateNative("LGO_IsMatchModeLoaded", native_IsMatchModeLoaded); +} + +void RM_OnModuleStart() +{ + RM_hDoRestart = CreateConVarEx("match_restart", "1", "Sets whether the plugin will restart the map upon match mode being forced or requested", _, true, 0.0, true, 1.0); + //RM_hAllowVoting = CreateConVarEx("match_allowvoting", "1", "Sets whether players can vote/request for match mode", _, true, 0.0, true, 1.0); + RM_hAutoLoad = CreateConVarEx("match_autoload", "0", "Has match mode start up automatically when a player connects and the server is not in match mode", _, true, 0.0, true, 1.0); + RM_hAutoCfg = CreateConVarEx("match_autoconfig", "", "Specify which config to load if the autoloader is enabled"); + RM_hConfigFile_On = CreateConVarEx("match_execcfg_on", "confogl.cfg", "Execute this config file upon match mode starts and every map after that."); + //RM_hConfigFile_Plugins = CreateConVarEx("match_execcfg_plugins", "confogl_plugins.cfg", "Execute this config file upon match mode starts. This will only get executed once and meant for plugins that needs to be loaded."); //original + RM_hConfigFile_Plugins = CreateConVarEx("match_execcfg_plugins", "generalfixes.cfg;confogl_plugins.cfg;sharedplugins.cfg", "Execute this config file upon match mode starts. This will only get executed once and meant for plugins that needs to be loaded."); //rework + RM_hConfigFile_Off = CreateConVarEx("match_execcfg_off", "confogl_off.cfg", "Execute this config file upon match mode ends."); + + //RegConsoleCmd("sm_match", RM_Cmd_Match); + RegAdminCmd("sm_forcematch", RM_Cmd_ForceMatch, ADMFLAG_CONFIG, "Forces the game to use match mode"); + RegAdminCmd("sm_fm", RM_Cmd_ForceMatch, ADMFLAG_CONFIG, "Forces the game to use match mode"); + RegAdminCmd("sm_resetmatch", RM_Cmd_ResetMatch, ADMFLAG_CONFIG, "Forces match mode to turn off REGRADLESS for always on or forced match"); + + RM_hSbAllBotGame = FindConVar("sb_all_bot_game"); + + RM_hReloaded = FindConVarEx("match_reloaded"); + if (RM_hReloaded == null) { + RM_hReloaded = CreateConVarEx("match_reloaded", "0", "DONT TOUCH THIS CVAR! This is to prevent match feature keep looping, however the plugin takes care of it. Don't change it!", FCVAR_DONTRECORD|FCVAR_UNLOGGED); + } + + if (RM_hReloaded.BoolValue) { + if (RM_DEBUG || IsDebugEnabled()) { + LogMessage("[%s] Plugin was reloaded from match mode, executing match load", RM_MODULE_NAME); + } + + RM_bIsPluginsLoaded = true; + RM_hReloaded.SetInt(0); + RM_Match_Load(); + } +} + +void RM_OnMapStart() +{ + if (!RM_bIsMatchModeLoaded) { + return; + } + + if (RM_DEBUG || IsDebugEnabled()) { + LogMessage("[%s] New map, executing match config...", RM_MODULE_NAME); + } + + RM_Match_Load(); +} + +void RM_OnClientPutInServer() +{ + if (!RM_hAutoLoad.BoolValue || RM_bIsAMatchActive) { + return; + } + + char buffer[128]; + RM_hAutoCfg.GetString(buffer, sizeof(buffer)); + + RM_UpdateCfgOn(buffer); + RM_Match_Load(); +} + +static void RM_Match_Load() +{ + if (RM_DEBUG || IsDebugEnabled()) { + LogMessage("[%s] Match Load", RM_MODULE_NAME); + } + + if (!RM_bIsAMatchActive) { + RM_bIsAMatchActive = true; + } + + RM_hSbAllBotGame.SetInt(1); + char sBuffer[128]; + + if (!RM_bIsPluginsLoaded) { + if (RM_DEBUG || IsDebugEnabled()) { + LogMessage("[%s] Loading plugins and reload self", RM_MODULE_NAME); + } + + RM_hReloaded.SetInt(1); + RM_hConfigFile_Plugins.GetString(sBuffer, sizeof(sBuffer)); + + //ExecuteCfg(sBuffer); //original + //rework + char sPieces[32][256]; + int iNumPieces = ExplodeString(sBuffer, ";", sPieces, sizeof(sPieces), sizeof(sPieces[])); + + // Unlocking and Unloading Plugins. + ServerCommand("sm plugins load_unlock"); + ServerCommand("sm plugins unload_all"); + + // Loading Plugins. + for (int i = 0; i < iNumPieces; i++) { + ExecuteCfg(sPieces[i]); + } + //rework end + + return; + } + + RM_hConfigFile_On.GetString(sBuffer, sizeof(sBuffer)); + ExecuteCfg(sBuffer); + + if (RM_DEBUG || IsDebugEnabled()) { + LogMessage("[%s] Match config executed", RM_MODULE_NAME); + } + + if (RM_bIsMatchModeLoaded) { + return; + } + + if (RM_DEBUG || IsDebugEnabled()) { + LogMessage("[%s] Setting match mode active", RM_MODULE_NAME); + } + + RM_bIsMatchModeLoaded = true; + IsPluginEnabled(true, true); + + //PrintToChatAll("\x01[\x05Confogl\x01] Match mode loaded!"); + CPrintToChatAll("{blue}[{default}Confogl{blue}]{default} Match mode loaded!"); + + if (!RM_bIsMapRestarted && RM_hDoRestart.BoolValue) { + //PrintToChatAll("\x01[\x05Confogl\x01] Restarting map!"); + CPrintToChatAll("{blue}[{default}Confogl{blue}]{default} Restarting map!"); + + CreateTimer(MAPRESTARTTIME, RM_Match_MapRestart_Timer); + } + + if (RM_DEBUG || IsDebugEnabled()) { + LogMessage("[%s] Match mode loaded!", RM_MODULE_NAME); + } + + Call_StartForward(RM_hFwdMatchLoad); + Call_Finish(); +} + +static void RM_Match_Unload(bool bForced = false) +{ + bool bIsHumansOnServer = IsHumansOnServer(); + + if (!bIsHumansOnServer || bForced) { + if (RM_DEBUG || IsDebugEnabled()) { + LogMessage("[%s] Match is no longer active, sb_all_bot_game reset to 0, IsHumansOnServer %b, bForced %b", RM_MODULE_NAME, bIsHumansOnServer, bForced); + } + + RM_bIsAMatchActive = false; + RM_hSbAllBotGame.SetInt(0); + } + + if (bIsHumansOnServer && !bForced) { + return; + } + + if (RM_DEBUG || IsDebugEnabled()) { + LogMessage("[%s] Unloading match mode...", RM_MODULE_NAME); + } + + char sBuffer[128]; + RM_bIsMatchModeLoaded = false; + IsPluginEnabled(true, false); + RM_bIsMapRestarted = false; + RM_bIsPluginsLoaded = false; + + Call_StartForward(RM_hFwdMatchUnload); + Call_Finish(); + + //PrintToChatAll("\x01[\x05Confogl\x01] Match mode unloaded!"); + CPrintToChatAll("{blue}[{default}Confogl{blue}]{default} Match mode unloaded!"); + + RM_hConfigFile_Off.GetString(sBuffer, sizeof(sBuffer)); + ExecuteCfg(sBuffer); + + if (RM_DEBUG || IsDebugEnabled()) { + LogMessage("[%s] Match mode unloaded!", RM_MODULE_NAME); + } +} + +public Action RM_Match_MapRestart_Timer(Handle hTimer) +{ + ServerCommand("sm plugins load_lock"); //rework + + if (RM_DEBUG || IsDebugEnabled()) { + LogMessage("[%s] Restarting map...", RM_MODULE_NAME); + } + + char sBuffer[128]; + GetCurrentMap(sBuffer, sizeof(sBuffer)); + ServerCommand("changelevel %s", sBuffer); + RM_bIsMapRestarted = true; + + return Plugin_Stop; +} + +static bool RM_UpdateCfgOn(const char[] cfgfile, bool bIsPrint = true) +{ + if (SetCustomCfg(cfgfile)) { + //PrintToChatAll("\x01[\x05Confogl\x01] Using \"\x04%s\x01\" config.", cfgfile); + CPrintToChatAll("{blue}[{default}Confogl{blue}]{default} Loading '{olive}%s{default}'.", cfgfile); + + if (RM_DEBUG || IsDebugEnabled()) { + LogMessage("[%s] Starting match on config %s", RM_MODULE_NAME, cfgfile); + } + + return true; + } + + if (bIsPrint) { + //PrintToChatAll("\x01[\x05Confogl\x01] Config \"\x04%s\x01\" not found, using default config!", cfgfile); + CPrintToChatAll("{blue}[{default}Confogl{blue}]{default} Config '{olive}%s{default}' not found, using default config!", cfgfile); + } + + return false; +} + +public Action RM_Cmd_ForceMatch(int client, int args) +{ + if (RM_bIsMatchModeLoaded) { + return Plugin_Handled; + } + + if (RM_DEBUG || IsDebugEnabled()) { + LogMessage("[%s] Match mode forced to load!", RM_MODULE_NAME); + } + + if (args < 1) { + //SetCustomCfg(""); //old code + //RM_Match_Load(); //old code + + if (client == 0) { + PrintToServer("[Confogl] Please specify a config to load."); + } else { + //PrintToChat(client, "\x01[\x05Confogl\x01] Please specify a \x04config\x01 to load."); + CPrintToChat(client, "{blue}[{default}Confogl{blue}]{default} Please specify a {olive}config{default} to load."); + } + return Plugin_Handled; + } + + char sBuffer[128]; + GetCmdArg(1, sBuffer, sizeof(sBuffer)); + + //RM_UpdateCfgOn(sBuffer); //old code + + if (!RM_UpdateCfgOn(sBuffer, false)) { + if (client == 0) { + PrintToServer("[Confogl] Config %s not found!", sBuffer); + } else { + //PrintToChat(client, "\x01[\x05Confogl\x01] Please specify a \"\x04%s\x01\" to load.", sBuffer); + CPrintToChat(client, "{blue}[{default}Confogl{blue}]{default} Config '{olive}%s{default}' not found!", sBuffer); + } + + return Plugin_Handled; + } + + RM_Match_Load(); + + return Plugin_Handled; +} + +public Action RM_Cmd_ResetMatch(int client, int args) +{ + if (!RM_bIsMatchModeLoaded) { + return Plugin_Handled; + } + + if (RM_DEBUG || IsDebugEnabled()) { + LogMessage("[%s] Match mode forced to unload!", RM_MODULE_NAME); + } + + RM_Match_Unload(true); + + return Plugin_Handled; +} + +/*public Action RM_Cmd_Match(int client, int args) +{ + if (RM_bIsMatchModeLoaded || (!IsVersus() && !IsScavenge()) || !RM_hAllowVoting.BoolValue) { + return Plugin_Handled; + } + + int iTeam = GetClientTeam(client); + if ((iTeam == L4D2Team_Survivor || iTeam == L4D2Team_Infected) && !RM_bMatchRequest[iTeam - 2]) { + RM_bMatchRequest[iTeam - 2] = true; + } else { + return Plugin_Handled; + } + + if (RM_bMatchRequest[0] && RM_bMatchRequest[1]) { + //PrintToChatAll("\x01[\x05Confogl\x01] Both teams have agreed to start a competitive match!"); + CPrintToChatAll("{blue}[{default}Confogl{blue}]{default} Both teams have agreed to start a competitive match!"); + + RM_Match_Load(); + } else if (RM_bMatchRequest[0] || RM_bMatchRequest[1]) { + //PrintToChatAll("\x01[\x05Confogl\x01] The \x04%s\x01 have requested to start a competitive match. The \x04%s\x01 must accept with match command!", + //g_sTeamName[iTeam + 4], g_sTeamName[iTeam + 3]); + CPrintToChatAll("{blue}[{default}Confogl{blue}]{default} The {olive}%s{default} have requested to start a competitive match. The {olive}%s{default} must accept with match command!", \ + g_sTeamName[iTeam + 4], g_sTeamName[iTeam + 3]); + + if (args > 0) { // cfgfile specified + char sBuffer[128]; + GetCmdArg(1, sBuffer, sizeof(sBuffer)); + RM_UpdateCfgOn(sBuffer); + } else { + SetCustomCfg(""); + } + + CreateTimer(30.0, RM_MatchRequestTimeout); + } + + return Plugin_Handled; +} + +public Action RM_MatchRequestTimeout(Handle hTimer) +{ + RM_ResetMatchRequest(); + + return Plugin_Stop; +}*/ + +void RM_OnClientDisconnect(int client) +{ + if (!RM_bIsMatchModeLoaded || IsFakeClient(client)) { + return; + } + + CreateTimer(RESETMINTIME, RM_MatchResetTimer); +} + +public Action RM_MatchResetTimer(Handle hTimer) +{ + RM_Match_Unload(); + + return Plugin_Stop; +} + +/*static void RM_ResetMatchRequest() +{ + RM_hConfigFile_On.RestoreDefault(); + + RM_bMatchRequest[0] = false; + RM_bMatchRequest[1] = false; +}*/ + +stock bool IsAMatchActive() +{ + return RM_bIsAMatchActive; +} + +public int native_IsMatchModeLoaded(Handle plugin, int numParams) +{ + return RM_bIsMatchModeLoaded; +} diff --git a/addons/sourcemod/scripting/confoglcompmod/ScoreMod.sp b/addons/sourcemod/scripting/confoglcompmod/ScoreMod.sp new file mode 100644 index 000000000..87dcdea33 --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/ScoreMod.sp @@ -0,0 +1,515 @@ +#if defined __scoremod_included + #endinput +#endif +#define __scoremod_included + +#define DEBUG_SM 0 +#define SM_MODULE_NAME "ScoreMod" + +static int + SM_iDefaultSurvivalBonus = 0, + SM_iDefaultTieBreaker = 0, + SM_iPillPercent = 0, + SM_iAdrenPercent = 0, + SM_iFirstScore = 0; + +static float + SM_fHealPercent = 0.0, + SM_fMapMulti = 0.0, + SM_fHBRatio = 0.0, + SM_fSurvivalBonusRatio = 0.0, + SM_fTempMulti[3] = {0.0, ...}; + +static bool + SM_bEventsHooked = false, + SM_bModuleIsEnabled = false, + SM_bHooked = false, + SM_bIsFirstRoundOver = false, + SM_bIsSecondRoundStarted = false, + SM_bIsSecondRoundOver = false; + +// Cvars +static ConVar + SM_hEnable = null, + SM_hHBRatio = null, + SM_hSurvivalBonusRatio = null, + SM_hMapMulti = null, + SM_hCustomMaxDistance = null; + +// Default Cvar Values +static ConVar + SM_hSurvivalBonus = null, + SM_hTieBreaker = null, + SM_hHealPercent = null, + SM_hPillPercent = null, + SM_hAdrenPercent = null, + SM_hTempMulti0 = null, + SM_hTempMulti1 = null, + SM_hTempMulti2 = null; + +void SM_APL() +{ + CreateNative("LGO_IsScoremodEnabled", Native_IsScoremodEnabled); + CreateNative("LGO_GetScoremodBonus", Native_GetScoremodBonus); +} + +void SM_OnModuleStart() +{ + SM_hEnable = CreateConVarEx("SM_enable", "1", "L4D2 Custom Scoring - Enable/Disable", _, true, 0.0, true, 1.0); + SM_hHBRatio = CreateConVarEx("SM_healthbonusratio", "2.0", "L4D2 Custom Scoring - Healthbonus Multiplier", _, true, 0.25, true, 5.0); + SM_hSurvivalBonusRatio = CreateConVarEx("SM_survivalbonusratio", "0.0", "Ratio to be used for a static survival bonus against Map distance. 25% == 100 points maximum health bonus on a 400 distance map", _); + SM_hTempMulti0 = CreateConVarEx("SM_tempmulti_incap_0", "0.30625", "L4D2 Custom Scoring - How important temp health is on survivors who have had no incaps", _, true, 0.0, true, 1.0); + SM_hTempMulti1 = CreateConVarEx("SM_tempmulti_incap_1", "0.17500", "L4D2 Custom Scoring - How important temp health is on survivors who have had one incap", _, true, 0.0, true, 1.0); + SM_hTempMulti2 = CreateConVarEx("SM_tempmulti_incap_2", "0.10000", "L4D2 Custom Scoring - How important temp health is on survivors who have had two incaps (black and white)", _, true, 0.0, true, 1.0); + SM_hMapMulti = CreateConVarEx("SM_mapmulti", "1", "L4D2 Custom Scoring - Increases Healthbonus Max to Distance Max", _, true, 0.0, true, 1.0); + SM_hCustomMaxDistance = CreateConVarEx("SM_custommaxdistance", "0", "L4D2 Custom Scoring - Custom max distance from config", _, true, 0.0, true, 1.0); + + SM_fTempMulti[0] = SM_hTempMulti0.FloatValue; + SM_fTempMulti[1] = SM_hTempMulti1.FloatValue; + SM_fTempMulti[2] = SM_hTempMulti2.FloatValue; + + SM_hEnable.AddChangeHook(SM_ConVarChanged_Enable); + SM_hHBRatio.AddChangeHook(SM_CVChanged_HealthBonusRatio); + SM_hSurvivalBonusRatio.AddChangeHook(SM_CVChanged_SurvivalBonusRatio); + SM_hTempMulti0.AddChangeHook(SM_ConVarChanged_TempMulti0); + SM_hTempMulti1.AddChangeHook(SM_ConVarChanged_TempMulti1); + SM_hTempMulti2.AddChangeHook(SM_ConVarChanged_TempMulti2); + + SM_hSurvivalBonus = FindConVar("vs_survival_bonus"); + SM_hTieBreaker = FindConVar("vs_tiebreak_bonus"); + SM_hHealPercent = FindConVar("first_aid_heal_percent"); + SM_hPillPercent = FindConVar("pain_pills_health_value"); + SM_hAdrenPercent = FindConVar("adrenaline_health_buffer"); + + SM_fHealPercent = SM_hHealPercent.FloatValue; + SM_iPillPercent = SM_hPillPercent.IntValue; + SM_iAdrenPercent = SM_hAdrenPercent.IntValue; + SM_iDefaultSurvivalBonus = SM_hSurvivalBonus.IntValue; + SM_iDefaultTieBreaker = SM_hTieBreaker.IntValue; + + SM_hHealPercent.AddChangeHook(SM_ConVarChanged_Health); + SM_hPillPercent.AddChangeHook(SM_ConVarChanged_Health); + SM_hAdrenPercent.AddChangeHook(SM_ConVarChanged_Health); + + RegConsoleCmd("sm_health", SM_Cmd_Health); + RegConsoleCmd("sm_bonus", SM_Cmd_Health); +} + +void SM_OnModuleEnd() +{ + PluginDisable(false); +} + +void SM_OnMapStart() +{ + if (!IsPluginEnabled()) { + return; + } + + SM_fMapMulti = (!SM_hMapMulti.BoolValue) ? 1.00 : float(L4D_GetVersusMaxCompletionScore()) / 400.0; + + SM_bModuleIsEnabled = SM_hEnable.BoolValue; + + if (SM_bModuleIsEnabled && !SM_bHooked) { + PluginEnable(); + } + + if (SM_bModuleIsEnabled) { + SM_hTieBreaker.SetInt(0); + } + + if (SM_bModuleIsEnabled && SM_hCustomMaxDistance.BoolValue && GetCustomMapMaxScore() > -1) { + L4D_SetVersusMaxCompletionScore(GetCustomMapMaxScore()); + // to allow a distance score of 0 and a health bonus + if (GetCustomMapMaxScore() > 0) { + SM_fMapMulti = float(GetCustomMapMaxScore()) / 400.0; + } + } + + SM_bIsFirstRoundOver = false; + SM_bIsSecondRoundStarted = false; + SM_bIsSecondRoundOver = false; + SM_iFirstScore = 0; + + SM_fTempMulti[0] = SM_hTempMulti0.FloatValue; + SM_fTempMulti[1] = SM_hTempMulti1.FloatValue; + SM_fTempMulti[2] = SM_hTempMulti2.FloatValue; +} + +public void SM_ConVarChanged_Enable(ConVar hConVar, const char[] sOldValue, const char[] sNewValue) +{ + if (StringToInt(sNewValue) == 0) { + PluginDisable(); + SM_bModuleIsEnabled = false; + } else { + PluginEnable(); + SM_bModuleIsEnabled = true; + } +} + +public void SM_ConVarChanged_TempMulti0(ConVar hConVar, const char[] sOldValue, const char[] sNewValue) +{ + SM_fTempMulti[0] = StringToFloat(sNewValue); +} + +public void SM_ConVarChanged_TempMulti1(ConVar hConVar, const char[] sOldValue, const char[] sNewValue) +{ + SM_fTempMulti[1] = StringToFloat(sNewValue); +} + +public void SM_ConVarChanged_TempMulti2(ConVar hConVar, const char[] sOldValue, const char[] sNewValue) +{ + SM_fTempMulti[2] = StringToFloat(sNewValue); +} + +public void SM_CVChanged_HealthBonusRatio(ConVar hConVar, const char[] sOldValue, const char[] sNewValue) +{ + SM_fHBRatio = StringToFloat(sNewValue); +} + +public void SM_CVChanged_SurvivalBonusRatio(ConVar hConVar, const char[] sOldValue, const char[] sNewValue) +{ + SM_fSurvivalBonusRatio = StringToFloat(sNewValue); +} + +public void SM_ConVarChanged_Health(ConVar hConVar, const char[] sOldValue, const char[] sNewValue) +{ + SM_fHealPercent = SM_hHealPercent.FloatValue; + SM_iPillPercent = SM_hPillPercent.IntValue; + SM_iAdrenPercent = SM_hAdrenPercent.IntValue; +} + +static void PluginEnable() +{ + ToggleHook(true); + + SM_fHBRatio = SM_hHBRatio.FloatValue; + SM_fSurvivalBonusRatio = SM_hSurvivalBonusRatio.FloatValue; + SM_iDefaultSurvivalBonus = SM_hSurvivalBonus.IntValue; + SM_iDefaultTieBreaker = SM_hTieBreaker.IntValue; + + SM_hTieBreaker.SetInt(0); + + SM_fHealPercent = SM_hHealPercent.FloatValue; + SM_iPillPercent = SM_hPillPercent.IntValue; + SM_iAdrenPercent = SM_hAdrenPercent.IntValue; + + SM_bHooked = true; +} + +static void ToggleHook(bool bIsHook) +{ + if (bIsHook) { + if (!SM_bEventsHooked) { + HookEvent("door_close", SM_DoorClose_Event); + HookEvent("player_death", SM_PlayerDeath_Event); + HookEvent("round_end", SM_RoundEnd_Event, EventHookMode_PostNoCopy); + HookEvent("round_start", SM_RoundStart_Event, EventHookMode_PostNoCopy); + HookEvent("finale_vehicle_leaving", SM_FinaleVehicleLeaving_Event, EventHookMode_PostNoCopy); + + /*AddCommandListener(SM_Command_Say, "say"); + AddCommandListener(SM_Command_Say, "say_team");*/ + + SM_bEventsHooked = true; + } + } else { + if (SM_bEventsHooked) { + UnhookEvent("door_close", SM_DoorClose_Event); + UnhookEvent("player_death", SM_PlayerDeath_Event); + UnhookEvent("round_end", SM_RoundEnd_Event, EventHookMode_PostNoCopy); + UnhookEvent("round_start", SM_RoundStart_Event, EventHookMode_PostNoCopy); + UnhookEvent("finale_vehicle_leaving", SM_FinaleVehicleLeaving_Event, EventHookMode_PostNoCopy); + + /*RemoveCommandListener(SM_Command_Say, "say"); + RemoveCommandListener(SM_Command_Say, "say_team");*/ + + SM_bEventsHooked = false; + } + } +} + +static void PluginDisable(bool unhook = true) +{ + if (unhook) { + ToggleHook(false); + } + + SM_hSurvivalBonus.SetInt(SM_iDefaultSurvivalBonus); + SM_hTieBreaker.SetInt(SM_iDefaultTieBreaker); + + SM_bHooked = false; +} + +public void SM_DoorClose_Event(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + if (!SM_bModuleIsEnabled || !IsPluginEnabled() || !hEvent.GetBool("checkpoint")) { + return; + } + + SM_hSurvivalBonus.SetInt(SM_CalculateSurvivalBonus()); +} + +public void SM_PlayerDeath_Event(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + if (!SM_bModuleIsEnabled || !IsPluginEnabled()) { + return; + } + + int client = GetClientOfUserId(hEvent.GetInt("userid")); + + // Can't just check for fakeclient + if (client > 0 && GetClientTeam(client) == L4D2Team_Survivor) { + SM_hSurvivalBonus.SetInt(SM_CalculateSurvivalBonus()); + } +} + +public void SM_RoundEnd_Event(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + if (!SM_bModuleIsEnabled || !IsPluginEnabled()) { + return; + } + + if (!SM_bIsFirstRoundOver) { + // First round just ended, save the current score. + SM_bIsFirstRoundOver = true; + int iAliveCount; + SM_iFirstScore = RoundToFloor(SM_CalculateAvgHealth(iAliveCount) * SM_fMapMulti * SM_fHBRatio + 400 * SM_fMapMulti * SM_fSurvivalBonusRatio * iAliveCount / 4.0); + + // If the score is nonzero, trust the SurvivalBonus var. + SM_iFirstScore = (SM_iFirstScore) ? (SM_hSurvivalBonus.IntValue * iAliveCount) : 0; + + //PrintToChatAll("\x01[\x05Confogl\x01] Round 1 Bonus: \x04%d", SM_iFirstScore); + CPrintToChatAll("{blue}[{default}Confogl{blue}]{default} Round 1 Bonus: {olive}%d", SM_iFirstScore); + + if (SM_hCustomMaxDistance.BoolValue && GetCustomMapMaxScore() > -1) { + //PrintToChatAll("\x01[\x05Confogl\x01] Custom Max Distance: \x04%d", GetCustomMapMaxScore()); + CPrintToChatAll("{blue}[{default}Confogl{blue}]{default} Custom Max Distance: {olive}%d", GetCustomMapMaxScore()); + } + } else if (SM_bIsSecondRoundStarted && !SM_bIsSecondRoundOver) { + SM_bIsSecondRoundOver = true; + // Second round has ended, print scores + + int iAliveCount; + int iScore = RoundToFloor(SM_CalculateAvgHealth(iAliveCount) * SM_fMapMulti * SM_fHBRatio + 400 * SM_fMapMulti * SM_fSurvivalBonusRatio * iAliveCount / 4.0); + // If the score is nonzero, trust the SurvivalBonus var. + iScore = (iScore) ? (SM_hSurvivalBonus.IntValue * iAliveCount) : 0; + + //PrintToChatAll("\x01[\x05Confogl\x01] Round 1 Bonus: \x04%d", SM_iFirstScore); + //PrintToChatAll("\x01[\x05Confogl\x01] Round 2 Bonus: \x04%d", iScore); + CPrintToChatAll("{blue}[{default}Confogl{blue}]{default} Round 1 Bonus: {olive}%d", SM_iFirstScore); + CPrintToChatAll("{blue}[{default}Confogl{blue}]{default} Round 2 Bonus: {olive}%d", iScore); + + if (SM_hCustomMaxDistance.BoolValue && GetCustomMapMaxScore() > -1) { + //PrintToChatAll("\x01[\x05Confogl\x01] Custom Max Distance: \x04%d", GetCustomMapMaxScore()); + CPrintToChatAll("{blue}[{default}Confogl{blue}]{default} Custom Max Distance: {olive}%d", GetCustomMapMaxScore()); + } + } +} + +public void SM_RoundStart_Event(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + if (!SM_bModuleIsEnabled || !IsPluginEnabled() || !SM_bIsFirstRoundOver) { + return; + } + + // Mark the beginning of the second round. + SM_bIsSecondRoundStarted = true; +} + +public void SM_FinaleVehicleLeaving_Event(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + if (!SM_bModuleIsEnabled || !IsPluginEnabled()) { + return; + } + + SM_hSurvivalBonus.SetInt(SM_CalculateSurvivalBonus()); +} + +public Action SM_Cmd_Health(int client, int args) +{ + if (!SM_bModuleIsEnabled || !IsPluginEnabled()) { + return Plugin_Handled; + } + + int iAliveCount; + float fAvgHealth = SM_CalculateAvgHealth(iAliveCount); + + if (SM_bIsSecondRoundStarted) { + //PrintToChat(client, "\x01[\x05Confogl\x01] Round 1 Bonus: \x04%d", SM_iFirstScore); + CPrintToChat(client, "{blue}[{default}Confogl{blue}]{default} Round 1 Bonus: {olive}%d", SM_iFirstScore); + } + + if (client) { + //PrintToChat(client, "\x01[\x05Confogl\x01] Average Health: \x04%.02f", fAvgHealth); + CPrintToChat(client, "{blue}[{default}Confogl{blue}]{default} Average Health: {olive}%.02f", fAvgHealth); + } else { + PrintToServer("[Confogl] Average Health: %.02f", fAvgHealth); + } + + int iScore = RoundToFloor(fAvgHealth * SM_fMapMulti * SM_fHBRatio) * iAliveCount; + + if (DEBUG_SM || IsDebugEnabled()) { + LogMessage("[%s] CalcScore: %d MapMulti: %.02f Multiplier %.02f", SM_MODULE_NAME, iScore, SM_fMapMulti, SM_fHBRatio); + } + + if (client) { + //PrintToChat(client, "\x01[\x05Confogl\x01] Health Bonus: \x04%d", iScore); + CPrintToChat(client, "{blue}[{default}Confogl{blue}]{default} Health Bonus: {olive}%d", iScore); + + if (SM_fSurvivalBonusRatio != 0.0) { + //PrintToChat(client, "\x01[\x05Confogl\x01] Static Survival Bonus Per Survivor: \x04%d", RoundToFloor(400 * SM_fMapMulti * SM_fSurvivalBonusRatio)); + CPrintToChat(client, "{blue}[{default}Confogl{blue}]{default} Static Survival Bonus Per Survivor: {olive}%d", RoundToFloor(400 * SM_fMapMulti * SM_fSurvivalBonusRatio)); + } + + if (SM_hCustomMaxDistance.BoolValue && GetCustomMapMaxScore() > -1) { + //PrintToChat(client, "\x01[\x05Confogl\x01] Custom Max Distance: \x04%d", GetCustomMapMaxScore()); + CPrintToChat(client, "{blue}[{default}Confogl{blue}]{default} Custom Max Distance: {olive}%d", GetCustomMapMaxScore()); + } + } else { + PrintToServer("[Confogl] Health Bonus: %d", iScore); + + if (SM_fSurvivalBonusRatio != 0.0) { + PrintToServer("[Confogl] Static Survival Bonus Per Survivor: %d", RoundToFloor(400 * SM_fMapMulti * SM_fSurvivalBonusRatio)); + } + + if (SM_hCustomMaxDistance.BoolValue && GetCustomMapMaxScore() > -1) { + PrintToServer("[Confogl] Custom Max Distance: %d", GetCustomMapMaxScore()); + } + } + + return Plugin_Handled; +} + +static float SM_CalculateAvgHealth(int &iAliveCount = 0) +{ + // Temporary Storage Variables for inventory + char strTemp[MAX_ENTITY_NAME_LENGTH]; + + int iTotalHealth, iTotalTempHealth[3], iTemp; + int iCurrHealth, iCurrTemp, iIncapCount, iSurvCount; + + float fTotalAdjustedTempHealth; + + bool IsFinale = L4D_IsMissionFinalMap(); + + iAliveCount = 0; + + for (int index = 1; index <= MaxClients; index++) { + if (IsSurvivor(index)) { + iSurvCount++; + if (IsPlayerAlive(index)) { + if (GetEntProp(index, Prop_Send, "m_isIncapacitated", 1) < 1) { + + // Get Main health stats + iCurrHealth = GetSurvivorPermanentHealth(index); + iCurrTemp = GetSurvivorTempHealth(index); + iIncapCount = GetSurvivorIncapCount(index); + + // Adjust for kits + iTemp = GetPlayerWeaponSlot(index, L4D2WeaponSlot_HeavyHealthItem); + if (iTemp > -1) { + GetEdictClassname(iTemp, strTemp, sizeof(strTemp)); + + if (strcmp(strTemp, "weapon_first_aid_kit") == 0) { + iCurrHealth = RoundToFloor(iCurrHealth + ((100 - iCurrHealth) * SM_fHealPercent)); + iCurrTemp = 0; + iIncapCount = 0; + } + } + + // Adjust for pills/adrenaline + iTemp = GetPlayerWeaponSlot(index, L4D2WeaponSlot_LightHealthItem); + if (iTemp > -1) { + GetEdictClassname(iTemp, strTemp, sizeof(strTemp)); + + if (strcmp(strTemp, "weapon_pain_pills") == 0) { + iCurrTemp += SM_iPillPercent; + } else if (strcmp(strTemp, "weapon_adrenaline") == 0) { + iCurrTemp += SM_iAdrenPercent; + } + } + + // Enforce max 100 total health points + if ((iCurrTemp + iCurrHealth) > 100) { + iCurrTemp = 100 - iCurrHealth; + } + + iAliveCount++; + iTotalHealth += iCurrHealth; + + if (iIncapCount < 0) { + iIncapCount = 0; + } else if (iIncapCount > 2) { + iIncapCount = 2; + } + + iTotalTempHealth[iIncapCount] += iCurrTemp; + } else if (!IsFinale) { + iAliveCount++; + } + } + } + } + + for (int i = 0; i < 3; i++) { + fTotalAdjustedTempHealth += iTotalTempHealth[i] * SM_fTempMulti[i]; + } + + // Total Score = Average Health points * numAlive + + // Average Health points = Total Health Points / Survivor Count + // Total Health Points = Total Permanent Health + Total Adjusted Temp Health + + // return Average Health Points + float fAvgHealth = (iTotalHealth + fTotalAdjustedTempHealth) / iSurvCount; + +#if DEBUG_SM + LogMessage("[%s] TotalPerm: %d TotalAdjustedTemp: %.02f SurvCount: %d AliveCount: %d AvgHealth: %.02f", \ + SM_MODULE_NAME, iTotalHealth, fTotalAdjustedTempHealth, iSurvCount, iAliveCount, fAvgHealth); +#endif + + return fAvgHealth; +} + +/*public Action SM_Command_Say(int iClient, const char[] sCommand, int iArgc) +{ + if (iClient == 0 || !SM_bModuleIsEnabled || !IsPluginEnabled()) { + return Plugin_Continue; + } + + char sMessage[MAX_NAME_LENGTH]; + GetCmdArg(1, sMessage, sizeof(sMessage)); + + if (strcmp(sMessage, "!health") == 0) { + return Plugin_Handled; + } + + return Plugin_Continue; +}*/ + +static int SM_CalculateSurvivalBonus() +{ + return RoundToFloor(SM_CalculateAvgHealth() * SM_fMapMulti * SM_fHBRatio + 400 * SM_fMapMulti * SM_fSurvivalBonusRatio); +} + +static int SM_CalculateScore() +{ + int iAliveCount = 0; + float fScore = SM_CalculateAvgHealth(iAliveCount); + + return RoundToFloor(fScore * SM_fMapMulti * SM_fHBRatio + 400 * SM_fMapMulti * SM_fSurvivalBonusRatio) * iAliveCount; +} + +public int Native_IsScoremodEnabled(Handle plugin, int numParams) +{ + return (SM_bModuleIsEnabled && IsPluginEnabled()); +} + +public int Native_GetScoremodBonus(Handle plugin, int numParams) +{ + if (!SM_bModuleIsEnabled || !IsPluginEnabled()) { + return -1; + } + + return SM_CalculateScore(); +} diff --git a/addons/sourcemod/scripting/confoglcompmod/UnprohibitBosses.sp b/addons/sourcemod/scripting/confoglcompmod/UnprohibitBosses.sp new file mode 100644 index 000000000..41d334c70 --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/UnprohibitBosses.sp @@ -0,0 +1,58 @@ +#if defined __unprohibit_bosses_included + #endinput +#endif +#define __unprohibit_bosses_included + +#define UB_MODULE_NAME "UnprohibitBosses" + +static bool + UB_bEnabled = true; + +static ConVar + UB_hEnable = null; + +void UB_OnModuleStart() +{ + UB_hEnable = CreateConVarEx("boss_unprohibit", "1", "Enable bosses spawning on all maps, even through they normally aren't allowed", _, true, 0.0, true, 1.0); + + UB_bEnabled = UB_hEnable.BoolValue; //turns on when changing cvar only + UB_hEnable.AddChangeHook(UB_ConVarChange); +} + +public void UB_ConVarChange(ConVar hConVar, const char[] sOldValue, const char[] sNewValue) +{ + UB_bEnabled = UB_hEnable.BoolValue; +} + +Action UB_OnGetScriptValueInt(const char[] key, int &retVal) +{ + if (IsPluginEnabled() && UB_bEnabled) { + if (strcmp(key, "DisallowThreatType") == 0) { + retVal = 0; + return Plugin_Handled; + } + + if (strcmp(key, "ProhibitBosses") == 0) { + retVal = 0; + return Plugin_Handled; + } + } + + return Plugin_Continue; +} + +Action UB_OnGetMissionVSBossSpawning() +{ + //if (IsPluginEnabled() && UB_bEnabled) { + if (UB_bEnabled) { + char mapbuf[32]; + GetCurrentMap(mapbuf, sizeof(mapbuf)); + if (strcmp(mapbuf, "c7m1_docks") == 0 || strcmp(mapbuf, "c13m2_southpinestream") == 0) { + return Plugin_Continue; + } + + return Plugin_Handled; + } + + return Plugin_Continue; +} diff --git a/addons/sourcemod/scripting/confoglcompmod/UnreserveLobby.sp b/addons/sourcemod/scripting/confoglcompmod/UnreserveLobby.sp new file mode 100644 index 000000000..650356a3a --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/UnreserveLobby.sp @@ -0,0 +1,36 @@ +#if defined __unreserve_lobby_included + #endinput +#endif +#define __unreserve_lobby_included + +#define UL_MODULE_NAME "UnreserveLobby" + +static ConVar + UL_hEnable = null; + +void UL_OnModuleStart() +{ + UL_hEnable = CreateConVarEx("match_killlobbyres", "1", \ + "Sets whether the plugin will clear lobby reservation once a match have begun", \ + _, true, 0.0, true, 1.0 \ + ); + + RegAdminCmd("sm_killlobbyres", UL_KillLobbyRes, ADMFLAG_BAN, "Forces the plugin to kill lobby reservation"); +} + +void UL_OnClientPutInServer() +{ + if (!IsPluginEnabled() || !UL_hEnable.BoolValue) { + return; + } + + L4D_LobbyUnreserve(); +} + +public Action UL_KillLobbyRes(int client, int args) +{ + L4D_LobbyUnreserve(); + ReplyToCommand(client, "[Confogl] Removed lobby reservation."); + + return Plugin_Handled; +} diff --git a/addons/sourcemod/scripting/confoglcompmod/WaterSlowdown.sp b/addons/sourcemod/scripting/confoglcompmod/WaterSlowdown.sp new file mode 100644 index 000000000..ad5565270 --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/WaterSlowdown.sp @@ -0,0 +1,125 @@ +#if defined __water_slowdown_included + #endinput +#endif +#define __water_slowdown_included + +#define WS_MODULE_NAME "WaterSlowdown" + +static float + WS_fSlowdownFactor = 0.90; + +static bool + WS_bEnabled = true, + WS_bJockeyInWater = false, + WS_bPlayerInWater[MAXPLAYERS + 1] = {false, ...}; + +static ConVar + WS_hEnable = null, + WS_hFactor = null; + +void WS_OnModuleStart() +{ + WS_hEnable = CreateConVarEx("waterslowdown", "1", "Enables additional water slowdown", _, true, 0.0, true, 1.0); + WS_hFactor = CreateConVarEx("slowdown_factor", "0.90", "Sets how much water will slow down survivors. 1.00 = Vanilla"); + + WS_SetStatus(); + WS_fSlowdownFactor = WS_hFactor.FloatValue; + + WS_hEnable.AddChangeHook(WS_ConVarChange); + WS_hFactor.AddChangeHook(WS_FactorConVarChange); + + HookEvent("round_start", WS_RoundStart, EventHookMode_PostNoCopy); + HookEvent("jockey_ride", WS_JockeyRide); + HookEvent("jockey_ride_end", WS_JockeyRideEnd); +} + +public void WS_FactorConVarChange(ConVar hConVar, const char[] sOldValue, const char[] sNewValue) +{ + WS_fSlowdownFactor = WS_hFactor.FloatValue; +} + +public void WS_ConVarChange(ConVar hConVar, const char[] sOldValue, const char[] sNewValue) +{ + WS_SetStatus(); +} + +void WS_OnMapEnd() +{ + WS_SetStatus(false); +} + +void WS_OnModuleEnd() +{ + WS_SetStatus(false); +} + +void WS_OnGameFrame() +{ + if (!IsServerProcessing() || !IsPluginEnabled() || !WS_bEnabled) { + return; + } + + int client, flags; + + for (int i = 0; i < NUM_OF_SURVIVORS; i++) { + client = GetSurvivorIndex(i); + + if (client != 0 && IsValidEntity(client)) { + flags = GetEntityFlags(client); + + if (!(flags & IN_JUMP && WS_bPlayerInWater[client])) { + if (flags & FL_INWATER) { + if (!WS_bPlayerInWater[client]) { + WS_bPlayerInWater[client] = true; + SetEntPropFloat(client, Prop_Send, "m_flLaggedMovementValue", WS_fSlowdownFactor); + } + } else { + if (WS_bPlayerInWater[client]) { + WS_bPlayerInWater[client] = false; + SetEntPropFloat(client, Prop_Send, "m_flLaggedMovementValue", 1.0); + } + } + } + } + } +} + +public void WS_RoundStart(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + WS_SetStatus(); +} + +public void WS_JockeyRide(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + int victim = GetClientOfUserId(hEvent.GetInt("victim")); + int jockey = GetClientOfUserId(hEvent.GetInt("userid")); + + if (WS_bPlayerInWater[victim] && !WS_bJockeyInWater) { + WS_bJockeyInWater = true; + SetEntPropFloat(jockey, Prop_Send, "m_flLaggedMovementValue", WS_fSlowdownFactor); + } else if (!WS_bPlayerInWater[victim] && WS_bJockeyInWater) { + WS_bJockeyInWater = false; + SetEntPropFloat(jockey, Prop_Send, "m_flLaggedMovementValue", 1.0); + } +} + +public void WS_JockeyRideEnd(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + int jockey = GetClientOfUserId(hEvent.GetInt("userid")); + + WS_bJockeyInWater = false; + + if (jockey > 0 && IsValidEntity(jockey)) { + SetEntPropFloat(jockey, Prop_Send, "m_flLaggedMovementValue", 1.0); + } +} + +static void WS_SetStatus(bool bEnable = true) +{ + if (!bEnable) { + WS_bEnabled = false; + return; + } + + WS_bEnabled = WS_hEnable.BoolValue; +} diff --git a/addons/sourcemod/scripting/confoglcompmod/WeaponCustomization.sp b/addons/sourcemod/scripting/confoglcompmod/WeaponCustomization.sp new file mode 100644 index 000000000..769222f87 --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/WeaponCustomization.sp @@ -0,0 +1,132 @@ +#if defined __weapon_customization_included + #endinput +#endif +#define __weapon_customization_included + +#define WC_MODULE_NAME "WeaponCustomization" + +static const char sSniperNames[][] = +{ + "weapon_hunting_rifle", + "weapon_sniper_military", + "weapon_sniper_awp", + "weapon_sniper_scout", + "weapon_rifle_sg552" +}; + +static char + WC_sLastWeapon[64] = "\0"; + +static int + WC_iLimitCount = 1, + WC_iLastWeapon = -1, + WC_iLastClient = -1; + +static ConVar + WC_hLimitCount = null; + +void WC_OnModuleStart() +{ + WC_hLimitCount = CreateConVarEx("limit_sniper", "1", "Limits the maximum number of sniping rifles at one time to this number", _, true, 0.0, true, 4.0); + + WC_iLimitCount = WC_hLimitCount.IntValue; + WC_hLimitCount.AddChangeHook(WC_ConVarChange); + + HookEvent("player_use", WC_PlayerUse_Event); + HookEvent("weapon_drop", WC_WeaponDrop_Event); +} + +public void WC_ConVarChange(ConVar hConVar, const char[] sOldValue, const char[] sNewValue) +{ + WC_iLimitCount = WC_hLimitCount.IntValue; +} + +public void WC_WeaponDrop_Event(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + if (!IsPluginEnabled()) { + return; + } + + WC_iLastWeapon = hEvent.GetInt("propid"); + WC_iLastClient = GetClientOfUserId(hEvent.GetInt("userid")); + hEvent.GetString("item", WC_sLastWeapon, sizeof(WC_sLastWeapon)); +} + +public void WC_PlayerUse_Event(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + if (!IsPluginEnabled()) { + return; + } + + int client = GetClientOfUserId(hEvent.GetInt("userid")); + + int primary = GetPlayerWeaponSlot(client, L4D2WeaponSlot_Primary); + if (primary < 1 || !IsValidEdict(primary)) { + return; + } + + char primary_name[MAX_ENTITY_NAME_LENGTH]; + GetEdictClassname(primary, primary_name, sizeof(primary_name)); + + if (IsValidSniper(primary_name)) { + if (SniperCount(client) >= WC_iLimitCount) { + RemovePlayerItem(client, primary); + //PrintToChat(client, "\x01[\x05Confogl\x01] Maximum \x04%d \x01sniping rifle(s) is enforced.", WC_iLimitCount); + CPrintToChat(client, "{blue}[{default}Confogl{blue}]{default} Maximum {blue}%d {olive}sniping rifle(s) {default}is enforced.", WC_iLimitCount); + + if (WC_iLastClient == client) { + if (WC_iLastWeapon > 0 && IsValidEdict(WC_iLastWeapon)) { + KillEntity(WC_iLastWeapon); + + int flags = GetCommandFlags("give"); + SetCommandFlags("give", flags ^ FCVAR_CHEAT); + + char sTemp[64]; + Format(sTemp, sizeof(sTemp), "give %s", WC_sLastWeapon); + FakeClientCommand(client, sTemp); + + SetCommandFlags("give", flags); + } + } + } + } + + WC_iLastWeapon = -1; + WC_iLastClient = -1; + WC_sLastWeapon[0] = 0; +} + +static int SniperCount(int client) +{ + char temp[MAX_ENTITY_NAME_LENGTH]; + int count = 0, index = 0, ent = 0; + + for (int i = 0; i < 4; i++) { + index = GetSurvivorIndex(i); + + if (index != client && index != 0 && IsClientConnected(index)) { + ent = GetPlayerWeaponSlot(index, L4D2WeaponSlot_Primary); + + if (ent > 0 && IsValidEdict(ent)) { + GetEdictClassname(ent, temp, sizeof(temp)); + + if (IsValidSniper(temp)) { + count++; + } + } + } + } + + return count; +} + +static bool IsValidSniper(const char[] sWeaponName) +{ + for (int i = 0; i < sizeof(sSniperNames); i++) { + if (strcmp(sWeaponName, sSniperNames[i], true) == 0) { + return true; + } + } + + return false; +} diff --git a/addons/sourcemod/scripting/confoglcompmod/WeaponInformation.sp b/addons/sourcemod/scripting/confoglcompmod/WeaponInformation.sp new file mode 100644 index 000000000..bda3e180c --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/WeaponInformation.sp @@ -0,0 +1,1292 @@ +#if defined __weapon_information_included + #endinput +#endif +#define __weapon_information_included + +#define DEBUG_WI 0 + +#if (DEBUG_ALL) + #define DEBUG_WI 1 +#endif + +#define WI_MODULE_NAME "WepInfo" + +#define MODEL_PREFIX "models/w_models/weapons/w_" +#define MODEL_SURFIX ".mdl" +#define SPAWN_PREFIX "weapon_" +#define SPAWN_SURFIX "_spawn" + +//==================================================== +// Weapon Index & ID +//==================================================== +#define WEAPON_REMOVE_INDEX -1 +#define WEAPON_NULL_INDEX 0 + +#define WEAPON_SMG_ID 2 +#define WEAPON_SMG_INDEX 1 +#define WEAPON_PUMPSHOTGUN_ID 3 +#define WEAPON_PUMPSHOTGUN_INDEX 2 + +#define WEAPON_AUTOSHOTGUN_ID 4 +#define WEAPON_AUTOSHOTGUN_INDEX 3 +#define WEAPON_RIFLE_ID 5 +#define WEAPON_RIFLE_INDEX 4 + +#define WEAPON_HUNTING_RIFLE_ID 6 +#define WEAPON_HUNTING_RIFLE_INDEX 5 +#define WEAPON_SMG_SILENCED_ID 7 +#define WEAPON_SMG_SILENCED_INDEX 6 + +#define WEAPON_SHOTGUN_CHROME_ID 8 +#define WEAPON_SHOTGUN_CHROME_INDEX 7 +#define WEAPON_RIFLE_DESERT_ID 9 +#define WEAPON_RIFLE_DESERT_INDEX 8 + +#define WEAPON_SNIPER_MILITARY_ID 10 +#define WEAPON_SNIPER_MILITARY_INDEX 9 +#define WEAPON_SHOTGUN_SPAS_ID 11 +#define WEAPON_SHOTGUN_SPAS_INDEX 10 + +#define WEAPON_GRENADE_LAUNCHER_ID 21 +#define WEAPON_GRENADE_LAUNCHER_INDEX 11 +#define WEAPON_RIFLE_AK47_ID 26 +#define WEAPON_RIFLE_AK47_INDEX 12 + +#define WEAPON_RIFLE_M60_ID 37 +#define WEAPON_RIFLE_M60_INDEX 13 + +#define WEAPON_SMG_MP5_ID 33 +#define WEAPON_SMG_MP5_INDEX 14 +#define WEAPON_RIFLE_SG552_ID 34 +#define WEAPON_RIFLE_SG552_INDEX 15 + +#define WEAPON_SNIPER_AWP_ID 35 +#define WEAPON_SNIPER_AWP_INDEX 16 +#define WEAPON_SNIPER_SCOUT_ID 36 +#define WEAPON_SNIPER_SCOUT_INDEX 17 + +#define WEAPON_CHAINSAW_INDEX 18 + +#define WEAPON_PIPE_BOMB_INDEX 19 +#define WEAPON_MOLOTOV_INDEX 20 +#define WEAPON_VOMITJAR_INDEX 21 + +#define WEAPON_FIRST_AID_KIT_INDEX 22 +#define WEAPON_DEFIBRILLATOR_INDEX 23 +#define WEAPON_UPG_EXPLOSIVE_INDEX 24 +#define WEAPON_UPG_INCENDIARY_INDEX 25 + +#define WEAPON_PAIN_PILLS_INDEX 26 +#define WEAPON_ADRENALINE_INDEX 27 + +//==================================================== +#define NUM_OF_WEAPONS 28 + +#define FIRST_WEAPON 1 +#define LAST_WEAPON 18 +#define FIRST_EXTRA 19 +#define LAST_EXTRA 27 + +#define WEAPON_NUMBER_OF_START_KITS 4 + +enum /*WEAPONATTRIBUTES*/ +{ + WeaponID, + Tier1EquivalentIndex, + ReplacementIndex, + + WeaponAttributes_Size +}; + +static const int Weapon_Attributes[NUM_OF_WEAPONS][WeaponAttributes_Size] = { + + //==================================================== + // Weapons + //==================================================== + + // NULL + { + WEAPON_NULL_INDEX, + WEAPON_NULL_INDEX, + WEAPON_NULL_INDEX + }, + + // SMG + { + WEAPON_SMG_ID, + WEAPON_NULL_INDEX, + WEAPON_NULL_INDEX + }, + + // Pumpshotgun + { + WEAPON_PUMPSHOTGUN_ID, + WEAPON_NULL_INDEX, + WEAPON_NULL_INDEX + }, + + // Autoshotgun + { + WEAPON_AUTOSHOTGUN_ID, + WEAPON_PUMPSHOTGUN_INDEX, + WEAPON_NULL_INDEX + }, + + // Rifle + { + WEAPON_RIFLE_ID, + WEAPON_SMG_INDEX, + WEAPON_NULL_INDEX + }, + + // Hunting rifle + { + WEAPON_HUNTING_RIFLE_ID, + WEAPON_NULL_INDEX, + WEAPON_NULL_INDEX + }, + + // SMG silenced + { + WEAPON_SMG_SILENCED_ID, + WEAPON_NULL_INDEX, + WEAPON_NULL_INDEX + }, + + // Chrome shotgun + { + WEAPON_SHOTGUN_CHROME_ID, + WEAPON_NULL_INDEX, + WEAPON_NULL_INDEX + }, + + // Desert rifle + { + WEAPON_RIFLE_DESERT_ID, + WEAPON_SMG_INDEX, + WEAPON_NULL_INDEX + }, + + // Military sniper + { + WEAPON_SNIPER_MILITARY_ID, + WEAPON_HUNTING_RIFLE_INDEX, + WEAPON_NULL_INDEX + }, + + // Spas shotgun + { + WEAPON_SHOTGUN_SPAS_ID, + WEAPON_SHOTGUN_CHROME_INDEX, + WEAPON_NULL_INDEX + }, + + // Grenade launcher + { + WEAPON_GRENADE_LAUNCHER_ID, + WEAPON_NULL_INDEX, + WEAPON_REMOVE_INDEX + }, + + // AK47 + { + WEAPON_RIFLE_AK47_ID, + WEAPON_SMG_SILENCED_INDEX, + WEAPON_NULL_INDEX + }, + + // M60 + { + WEAPON_RIFLE_M60_ID, + WEAPON_NULL_INDEX, + WEAPON_REMOVE_INDEX, + }, + + // MP5 + { + WEAPON_SMG_MP5_ID, + WEAPON_NULL_INDEX, + WEAPON_SMG_INDEX + }, + + // SG552 + { + WEAPON_RIFLE_SG552_ID, + WEAPON_SMG_MP5_INDEX, + WEAPON_RIFLE_INDEX + }, + + // AWP + { + WEAPON_SNIPER_AWP_ID, + WEAPON_SNIPER_SCOUT_INDEX, + WEAPON_SNIPER_MILITARY_INDEX + }, + + // Scout + { + WEAPON_SNIPER_SCOUT_ID, + WEAPON_NULL_INDEX, + WEAPON_HUNTING_RIFLE_INDEX + }, + + //==================================================== + // Melee Weapons + //==================================================== + + // Chainsaw + { + WEAPON_NULL_INDEX, + WEAPON_NULL_INDEX, + WEAPON_REMOVE_INDEX + }, + + //==================================================== + // Extra Items + //==================================================== + + // Pipe Bomb + { + WEAPON_NULL_INDEX, + WEAPON_NULL_INDEX, + WEAPON_NULL_INDEX + }, + + // Molotov + { + WEAPON_NULL_INDEX, + WEAPON_NULL_INDEX, + WEAPON_NULL_INDEX + }, + + // Vomitjar + { + WEAPON_NULL_INDEX, + WEAPON_NULL_INDEX, + WEAPON_NULL_INDEX + }, + + // First Aid Kit + { + WEAPON_NULL_INDEX, + WEAPON_NULL_INDEX, + WEAPON_REMOVE_INDEX + }, + + // Defibrillator + { + WEAPON_NULL_INDEX, + WEAPON_NULL_INDEX, + WEAPON_REMOVE_INDEX + }, + + // Explosive Upgrade Pack + { + WEAPON_NULL_INDEX, + WEAPON_NULL_INDEX, + WEAPON_REMOVE_INDEX + }, + + // Incendiary Upgrade Pack + { + WEAPON_NULL_INDEX, + WEAPON_NULL_INDEX, + WEAPON_REMOVE_INDEX + }, + + // Pain pills + { + WEAPON_NULL_INDEX, + WEAPON_NULL_INDEX, + WEAPON_NULL_INDEX + }, + + // Adrenaline + { + WEAPON_NULL_INDEX, + WEAPON_NULL_INDEX, + WEAPON_NULL_INDEX + } +}; + +static const char Weapon_Models[NUM_OF_WEAPONS][] = { + + //==================================================== + // Weapons + //==================================================== + + // NULL + "", + + // SMG + "smg_uzi", + + // Shotgun + "shotgun", + + // Autoshotgun + "autoshot_m4super", + + // Rifle + "rifle_m16a2", + + // Hunting rifle + "sniper_mini14", + + // SMG silenced + "smg_a", + + // Chrome shotgun + "pumpshotgun_a", + + // Desert rifle + "rifle_b", + + // Military rifle + "sniper_military", + + // Spas shotgun + "shotgun_spas", + + // Grenade launcher + "", + + // AK47 + "rifle_ak47", + + // M60 + "m60", + + // MP5 + "smg_mp5", + + // SG552 + "", + + // AWP + "", + + // Scout + "sniper_scout", + + //==================================================== + // Melee Weapons + //==================================================== + + // Chainsaw + "", + + //==================================================== + // Extra Items + //==================================================== + + // Pipe Bomb + "", + + // Molotov + "", + + // Vomitjar + "", + + // First Aid Kit + "", + + // Defibrillator + "", + + // Explosive Upgrade Pack + "", + + // Incendiary Upgrade Pack + "", + + // Pain pills + "", + + // Adrenaline + "" +}; + +static const char Weapon_Spawns[NUM_OF_WEAPONS][] = { + + //==================================================== + // Weapons + //==================================================== + + // NULL + "", + + // SMG + "", + + // Shotgun + "", + + // Autoshotgun + "autoshotgun", + + // Rifle + "rifle", + + // Hunting rifle + "", + + // SMG silenced + "", + + // Chrome shotgun + "", + + // Desert rifle + "rifle_desert", + + // Military rifle + "sniper_military", + + // Spas shotgun + "shotgun_spas", + + // Grenade launcher + "grenade_launcher", + + // AK47 + "rifle_ak47", + + // M60 + "rifle_m60", + + // MP5 + "", + + // SG552 + "", + + // AWP + "", + + // Scout + "", + + //==================================================== + // Melee Weapons + //==================================================== + + // Chainsaw + "chainsaw", + + //==================================================== + // Extra Items + //==================================================== + + // Pipe Bomb + "pipe_bomb", + + // Molotov + "molotov", + + // Vomitjar + "vomitjar", + + // First Aid Kit + "first_aid_kit", + + // Defibrillator + "defibrillator", + + // Explosive Upgrade Pack + "upgradepack_explosive", + + // Incendiary Upgrade Pack + "upgradepack_incendiary", + + // Pain pills + "pain_pills", + + // Adrenaline + "adrenaline" +}; + +//==================================================== +// Kit Protection +//==================================================== +static int + Weapon_iKitEntity[WEAPON_NUMBER_OF_START_KITS] = {0, ...}, + Weapon_iKitCount = 0; + +//==================================================== +// Map Info +//==================================================== +static float + Weapon_fMapOrigin_Start[3], + Weapon_fMapOrigin_End[3], + Weapon_fMapDist_Start, + Weapon_fMapDist_StartExtra, + Weapon_fMapDist_End; + +static bool + Weapon_bUpdateMapInfo = true; +//==================================================== + +static bool + Weapon_bConvar[NUM_OF_WEAPONS] = {false, ...}, + Weapon_bReplaceTier2 = true, + Weapon_bReplaceTier2_Finale = true, + Weapon_bReplaceTier2_All = true, + Weapon_bLimitTier2 = true, + Weapon_bLimitTier2_Safehouse = true, + Weapon_bReplaceStartKits = true, + Weapon_bReplaceFinaleKits = true, + Weapon_bRemoveLaserSight = true, + Weapon_bRemoveExtraItems = true; + +static ConVar + Weapon_hConvar[NUM_OF_WEAPONS] = {null, ...}, + Weapon_hReplaceTier2 = null, + Weapon_hReplaceTier2_Finale = null, + Weapon_hReplaceTier2_All = null, + Weapon_hLimitTier2 = null, + Weapon_hLimitTier2_Safehouse = null, + Weapon_hReplaceStartKits = null, + Weapon_hReplaceFinaleKits = null, + Weapon_hRemoveLaserSight = null, + Weapon_hRemoveExtraItems = null; + +//==================================================== +// Module setup +//==================================================== +void WI_OnModuleStart() +{ + WI_Convar_Setup(); + + HookEvent("round_start", WI_RoundStart_Event, EventHookMode_PostNoCopy); + HookEvent("round_end", WI_RoundEnd_Event, EventHookMode_PostNoCopy); + HookEvent("spawner_give_item", WI_SpawnerGiveItem_Event); +} + +void WI_OnMapEnd() +{ + Weapon_bUpdateMapInfo = true; +} + +//==================================================== +// Functions +//==================================================== +static void WI_Convar_Setup() +{ + Weapon_hConvar[WEAPON_SMG_MP5_INDEX] = CreateConVarEx("replace_cssweapons", "1", "Replace CSS weapons with normal L4D2 weapons", _, true, 0.0, true, 1.0); + + Weapon_hConvar[WEAPON_RIFLE_SG552_INDEX] = Weapon_hConvar[WEAPON_SMG_MP5_INDEX]; + Weapon_hConvar[WEAPON_SNIPER_AWP_INDEX] = Weapon_hConvar[WEAPON_SMG_MP5_INDEX]; + Weapon_hConvar[WEAPON_SNIPER_SCOUT_INDEX] = Weapon_hConvar[WEAPON_SMG_MP5_INDEX]; + + Weapon_hConvar[WEAPON_GRENADE_LAUNCHER_INDEX] = CreateConVarEx("remove_grenade", "1", "Remove all grenade launchers", _, true, 0.0, true, 1.0); + Weapon_hConvar[WEAPON_CHAINSAW_INDEX] = CreateConVarEx("remove_chainsaw", "1", "Remove all chainsaws", _, true, 0.0, true, 1.0); + Weapon_hConvar[WEAPON_RIFLE_M60_INDEX] = CreateConVarEx("remove_m60", "1", "Remove all M60 rifles", _, true, 0.0, true, 1.0); + + Weapon_hConvar[WEAPON_FIRST_AID_KIT_INDEX] = CreateConVarEx("remove_statickits", "1", "Remove all static medkits (medkits such as the gun shop, these are compiled into the map)", _, true, 0.0, true, 1.0); + Weapon_hConvar[WEAPON_DEFIBRILLATOR_INDEX] = CreateConVarEx("remove_defib", "1", "Remove all defibrillators", _, true, 0.0, true, 1.0); + Weapon_hConvar[WEAPON_UPG_EXPLOSIVE_INDEX] = CreateConVarEx("remove_upg_explosive", "1", "Remove all explosive upgrade packs", _, true, 0.0, true, 1.0); + Weapon_hConvar[WEAPON_UPG_INCENDIARY_INDEX] = CreateConVarEx("remove_upg_incendiary", "1", "Remove all incendiary upgrade packs", _, true, 0.0, true, 1.0); + + for (int index = FIRST_WEAPON; index < NUM_OF_WEAPONS; index++) { + if (Weapon_hConvar[index] == null) { + continue; + } + + Weapon_bConvar[index] = Weapon_hConvar[index].BoolValue; + Weapon_hConvar[index].AddChangeHook(WI_ConvarChange); + } + + Weapon_hReplaceTier2 = CreateConVarEx("replace_tier2", "1", "Replace tier 2 weapons in start and end safe room with their tier 1 equivalent", _, true, 0.0, true, 1.0); + Weapon_hReplaceTier2_Finale = CreateConVarEx("replace_tier2_finale", "1", "Replace tier 2 weapons in start safe room with their tier 1 equivalent, on finale", _, true, 0.0, true, 1.0); + Weapon_hReplaceTier2_All = CreateConVarEx("replace_tier2_all", "1", "Replace ALL tier 2 weapons with their tier 1 equivalent EVERYWHERE", _, true, 0.0, true, 1.0); + Weapon_hLimitTier2 = CreateConVarEx("limit_tier2", "1", "Limit tier 2 weapons outside safe rooms. Replaces a tier 2 stack with tier 1 upon first weapon pickup", _, true, 0.0, true, 1.0); + Weapon_hLimitTier2_Safehouse = CreateConVarEx("limit_tier2_saferoom", "1", "Limit tier 2 weapons inside safe rooms. Replaces a tier 2 stack with tier 1 upon first weapon pickup", _, true, 0.0, true, 1.0); + Weapon_hReplaceStartKits = CreateConVarEx("replace_startkits", "1", "Replaces start medkits with pills", _, true, 0.0, true, 1.0); + Weapon_hReplaceFinaleKits = CreateConVarEx("replace_finalekits", "1", "Replaces finale medkits with pills", _, true, 0.0, true, 1.0); + Weapon_hRemoveLaserSight = CreateConVarEx("remove_lasersight", "1", "Remove all laser sight upgrades", _, true, 0.0, true, 1.0); + Weapon_hRemoveExtraItems = CreateConVarEx("remove_saferoomitems", "1", "Remove all extra items inside saferooms (items for slot 3, 4 and 5, minus medkits)", _, true, 0.0, true, 1.0); + + ConVarsInType(); + + Weapon_hReplaceTier2.AddChangeHook(WI_ConvarChange); + Weapon_hReplaceTier2_Finale.AddChangeHook(WI_ConvarChange); + Weapon_hReplaceTier2_All.AddChangeHook(WI_ConvarChange); + Weapon_hLimitTier2.AddChangeHook(WI_ConvarChange); + Weapon_hLimitTier2_Safehouse.AddChangeHook(WI_ConvarChange); + Weapon_hReplaceStartKits.AddChangeHook(WI_ConvarChange); + Weapon_hReplaceFinaleKits.AddChangeHook(WI_ConvarChange); + Weapon_hRemoveLaserSight.AddChangeHook(WI_ConvarChange); + Weapon_hRemoveExtraItems.AddChangeHook(WI_ConvarChange); +} + +static void ConVarsInType() +{ + Weapon_bReplaceTier2 = Weapon_hReplaceTier2.BoolValue; + Weapon_bReplaceTier2_Finale = Weapon_hReplaceTier2_Finale.BoolValue; + Weapon_bReplaceTier2_All = Weapon_hReplaceTier2_All.BoolValue; + Weapon_bLimitTier2 = Weapon_hLimitTier2.BoolValue; + Weapon_bLimitTier2_Safehouse = Weapon_hLimitTier2_Safehouse.BoolValue; + Weapon_bReplaceStartKits = Weapon_hReplaceStartKits.BoolValue; + Weapon_bReplaceFinaleKits = Weapon_hReplaceFinaleKits.BoolValue; + Weapon_bRemoveLaserSight = Weapon_hRemoveLaserSight.BoolValue; + Weapon_bRemoveExtraItems = Weapon_hRemoveExtraItems.BoolValue; +} + +public void WI_ConvarChange(ConVar hConVar, const char[] sOldValue, const char[] sNewValue) +{ + for (int index = FIRST_WEAPON; index < NUM_OF_WEAPONS; index++) { + if (Weapon_hConvar[index] == null) { + continue; + } + + Weapon_bConvar[index] = Weapon_hConvar[index].BoolValue; + } + + ConVarsInType(); +} + +//================================================ +// GetWeaponIndex( iEntity, const String:sEntityClassName[128] ) +//================================================ +// Searches the weapon index for the given entity +// class +static int WI_GetWeaponIndex(int iEntity, const char[] sEntityClassName) +{ + //------------------------------------------------ + // Check for weapon in class name + //------------------------------------------------ + // If the class name doesn't contain weapon at all + // we don't need to loop thourgh with this entity + // Return false + + if (StrContains(sEntityClassName, "weapon") == -1) { + return WEAPON_NULL_INDEX; + } + +#if (DEBUG_WI) + LogMessage("[%s] GetWeaponIndex( iEntity %i sEntityClassName \"%s\" )", WI_MODULE_NAME, iEntity, sEntityClassName); + LogMessage("[%s] {", WI_MODULE_NAME); +#endif + + //------------------------------------------------ + // Check class name + //------------------------------------------------ + // If the class name is weapon_spawn we got a + // dynamic spawn and as such read the weapon id + // for detimernation of the weapon index + + int WeaponIndex; + bool bFoundIndex = false; + + if (strcmp(sEntityClassName, "weapon_spawn") == 0) { + int WepID = GetEntProp(iEntity, Prop_Send, "m_weaponID"); + + #if (DEBUG_WI) + LogMessage("[%s] Dynamic weapon spawn, weaponID %i", WI_MODULE_NAME, WepID); + #endif + + for (WeaponIndex = FIRST_WEAPON; WeaponIndex < NUM_OF_WEAPONS; WeaponIndex++) { + if (Weapon_Attributes[WeaponIndex][WeaponID] != WepID) { + continue; + } + + #if (DEBUG_WI) + LogMessage("[%s] Weapon WeaponIndex %i", WI_MODULE_NAME, WeaponIndex); + #endif + + bFoundIndex = true; + break; + } + } + //------------------------------------------------ + // Check static spawns + //------------------------------------------------ + // Otherwise loop through the weapon index for + // static classes + // If we got a match we know the index + else { + char sBuffer[MAX_ENTITY_NAME_LENGTH]; + for (WeaponIndex = FIRST_WEAPON; WeaponIndex < NUM_OF_WEAPONS; WeaponIndex++) { + if (strlen(Weapon_Spawns[WeaponIndex]) < 1) { + continue; + } + + Format(sBuffer, sizeof(sBuffer), "%s%s%s", SPAWN_PREFIX, Weapon_Spawns[WeaponIndex], SPAWN_SURFIX); + + if (strcmp(sEntityClassName, sBuffer) != 0) { + continue; + } + + #if (DEBUG_WI) + LogMessage("[%s] Static spawn, weapon WeaponIndex %i", WI_MODULE_NAME, WeaponIndex); + #endif + + bFoundIndex = true; + break; + } + } + + //------------------------------------------------ + // Check index + //------------------------------------------------ + // If we didn't find the index, return false + + if (!bFoundIndex) { + #if (DEBUG_WI) + LogMessage("[%s] Not found in weapon index", WI_MODULE_NAME); + LogMessage("[%s] }", WI_MODULE_NAME); + #endif + + return WEAPON_NULL_INDEX; + } + +#if (DEBUG_WI) + LogMessage("[%s] }", WI_MODULE_NAME); +#endif + + return WeaponIndex; +} + +//================================================ +// IsStatic( iEntity, iWeaponIndex ) +//================================================ +// Checks if the given entity with matching weapon +// index is a static spawn + +static bool WI_IsStatic(int iEntity, int iWeaponIndex) +{ + if (strlen(Weapon_Spawns[iWeaponIndex]) < 1) { + return false; + } + + char sEntityClassName[MAX_ENTITY_NAME_LENGTH], sBuffer[MAX_ENTITY_NAME_LENGTH]; + + GetEdictClassname(iEntity, sEntityClassName, sizeof(sEntityClassName)); + Format(sBuffer, sizeof(sBuffer), "%s%s%s", SPAWN_PREFIX, Weapon_Spawns[iWeaponIndex], SPAWN_SURFIX); + + if (strcmp(sEntityClassName, sBuffer) != 0) { + return false; + } + + // This is to prevent crashing + // Some static spawns doesn't have a model as we just wish to remove them + if (strlen(Weapon_Models[iWeaponIndex]) < 1) { + return false; + } + + return true; +} + +//================================================ +// ReplaceWeapon( iEntity, iWeaponIndex, bool:bSpawnerEvent ) +//================================================ +// Takes care of handling weapon entities, +// killing, replacing, and updateing. + +static void WI_ReplaceWeapon(int iEntity, int iWeaponIndex, bool bSpawnerEvent = false) +{ + #if (DEBUG_WI) + LogMessage("[%s] ReplaceWeapon( iEntity %i, iWeaponIndex %i, bSpawnerEvent %b )", WI_MODULE_NAME, iEntity, iWeaponIndex, bSpawnerEvent); + LogMessage("[%s] {", WI_MODULE_NAME); + #endif + + //------------------------------------------------ + // Removal of weapons + //------------------------------------------------ + // Checks if the replacement index is equal to -1 + // (WEAPON_REMOVE_INDEX) + // If so, check the cvar boolean and kill the + // weapon + + if (!bSpawnerEvent + && Weapon_Attributes[iWeaponIndex][ReplacementIndex] == WEAPON_REMOVE_INDEX + && Weapon_bConvar[iWeaponIndex] + ) { + KillEntity(iEntity); + + #if (DEBUG_WI) + LogMessage("[%s] Killing weapon as requested...", WI_MODULE_NAME); + LogMessage("[%s] }", WI_MODULE_NAME); + #endif + + return; + } + + //------------------------------------------------ + // Replacement of static weapons + //------------------------------------------------ + // Replaces all weapon_*weaponname*_spawn with + // weapon_spawn and the old weapon ID + + char sModelBuffer[PLATFORM_MAX_PATH]; + float fOrigin[3], fRotation[3]; + + if (!bSpawnerEvent + && WI_IsStatic(iEntity, iWeaponIndex) + && (Weapon_Attributes[iWeaponIndex][WeaponID] != WEAPON_NULL_INDEX) + ) { + GetEntPropVector(iEntity, Prop_Send, "m_vecOrigin", fOrigin); + GetEntPropVector(iEntity, Prop_Send, "m_angRotation", fRotation); + KillEntity(iEntity); + + iEntity = CreateEntityByName("weapon_spawn"); + SetEntProp(iEntity, Prop_Send, "m_weaponID", Weapon_Attributes[iWeaponIndex][WeaponID]); + + Format(sModelBuffer, sizeof(sModelBuffer), "%s%s%s", MODEL_PREFIX, Weapon_Models[iWeaponIndex], MODEL_SURFIX); + SetEntityModel(iEntity, sModelBuffer); + + TeleportEntity(iEntity, fOrigin, fRotation, NULL_VECTOR); + DispatchKeyValue(iEntity, "count", "5"); + DispatchSpawn(iEntity); + SetEntityMoveType(iEntity, MOVETYPE_NONE); + + #if (DEBUG_WI) + LogMessage("[%s] Replacing static spawn with weapon_spawn, new iEntity %i, weaponID %i, model \"%s\"", \ + WI_MODULE_NAME, iEntity, Weapon_Attributes[iWeaponIndex][WeaponID], sModelBuffer); + #endif + } + + //------------------------------------------------ + // Replace Weapons + //------------------------------------------------ + // Replace weapons that needs to be done so + // This is to replace CSS weapons, but can be + // adjusted to fit with any weapon + + if ((!bSpawnerEvent + && Weapon_Attributes[iWeaponIndex][ReplacementIndex] != WEAPON_NULL_INDEX + || Weapon_Attributes[iWeaponIndex][ReplacementIndex] != WEAPON_REMOVE_INDEX) + && Weapon_bConvar[iWeaponIndex] + ) { + iWeaponIndex = Weapon_Attributes[iWeaponIndex][ReplacementIndex]; + SetEntProp(iEntity, Prop_Send, "m_weaponID", Weapon_Attributes[iWeaponIndex][WeaponID]); + Format(sModelBuffer, sizeof(sModelBuffer), "%s%s%s", MODEL_PREFIX, Weapon_Models[iWeaponIndex], MODEL_SURFIX); + SetEntityModel(iEntity, sModelBuffer); + + #if (DEBUG_WI) + LogMessage("[%s] Following replacement index, new weaponID %i, new model \"%s\"", WI_MODULE_NAME, iWeaponIndex, sModelBuffer); + #endif + } + + //------------------------------------------------ + // Check for tier 1 equivalent + //------------------------------------------------ + // Check the current weapon index for a tier 1 + // equivalent + + if (Weapon_Attributes[iWeaponIndex][Tier1EquivalentIndex] == WEAPON_NULL_INDEX) { + #if (DEBUG_WI) + LogMessage("[%s] No tier 1 equivalent, no need to proceed", WI_MODULE_NAME); + LogMessage("[%s] }", WI_MODULE_NAME); + #endif + + return; + } + + //------------------------------------------------ + // Check location + //------------------------------------------------ + // Check the location of the weapon, to see if its + // within a saferoom + + bool bIsInSaferoom = false; + GetEntPropVector(iEntity, Prop_Send, "m_vecOrigin", fOrigin); + + // Within start safe room + if (!Weapon_bReplaceTier2_All && IsVersus()) { + if (GetVectorDistance(Weapon_fMapOrigin_Start, fOrigin) > Weapon_fMapDist_StartExtra + && GetVectorDistance(Weapon_fMapOrigin_End, fOrigin) > Weapon_fMapDist_End + ) { + #if (DEBUG_WI) + LogMessage("[%s] Weapon is outside of a saferoom", WI_MODULE_NAME); + #endif + + if (!bSpawnerEvent) { + #if (DEBUG_WI) + LogMessage("[%s] }", WI_MODULE_NAME); + #endif + return; + } + } else { + #if (DEBUG_WI) + LogMessage("[%s] Weapon is inside a saferoom", WI_MODULE_NAME); + #endif + bIsInSaferoom = true; + } + } + + //------------------------------------------------ + // Check tier 2 replacement booleans + //------------------------------------------------ + // Check and see if the plugin is set to replace + // tier 2 weapons + // One for non-finale maps and one for finales + + if (!Weapon_bReplaceTier2_All) { + if (!bSpawnerEvent) { + if ((!Weapon_bReplaceTier2 && !L4D_IsMissionFinalMap()) || (!Weapon_bReplaceTier2_Finale && L4D_IsMissionFinalMap())) { + #if (DEBUG_WI) + LogMessage("[%s] We do not want to replace weapons, IsMapFinale %b", WI_MODULE_NAME, L4D_IsMissionFinalMap()); + LogMessage("[%s] }", WI_MODULE_NAME); + #endif + + return; + } + } else { + if ((!Weapon_bLimitTier2 && !bIsInSaferoom) || (!Weapon_bLimitTier2_Safehouse && bIsInSaferoom)) { + #if (DEBUG_WI) + LogMessage("[%s] We do not want to replace weapons, bLimitTier2 %b, bLimitTier2_Saferoom %b, bIsInSaferoom %b", \ + WI_MODULE_NAME, Weapon_bLimitTier2, Weapon_bLimitTier2_Safehouse, bIsInSaferoom); + LogMessage("[%s] }", WI_MODULE_NAME); + #endif + + return; + } + } + } +#if (DEBUG_WI) + else { + LogMessage("[%s] bReplaceTier2_All %b", WI_MODULE_NAME, Weapon_bReplaceTier2_All); + } +#endif + + //------------------------------------------------ + // Replace tier 2 weapon + //------------------------------------------------ + // And lastly after all these steps, this is where + // the magic happens + // Replace the weapon with its tier 1 equivalent + // and update the model + + iWeaponIndex = Weapon_Attributes[iWeaponIndex][Tier1EquivalentIndex]; + SetEntProp(iEntity, Prop_Send, "m_weaponID", Weapon_Attributes[iWeaponIndex][WeaponID]); + Format(sModelBuffer, sizeof(sModelBuffer), "%s%s%s", MODEL_PREFIX, Weapon_Models[iWeaponIndex], MODEL_SURFIX); + SetEntityModel(iEntity, sModelBuffer); + +#if (DEBUG_WI) + LogMessage("[%s] Replacing Tier 2, new WeaponID %i, model \"%s\"", WI_MODULE_NAME, Weapon_Attributes[iWeaponIndex][WeaponID], sModelBuffer); + LogMessage("[%s] }", WI_MODULE_NAME); +#endif +} + +//================================================ +// ReplaceExtra( iEntity, iWeaponIndex ) +//================================================ +// Takes care of handling extra entities, +// killing, replacing, and updateing. + +static void WI_ReplaceExtra(int iEntity, int iWeaponIndex) +{ +#if (DEBUG_WI) + LogMessage("[%s] ReplaceExtra( iEntity %i, iWeaponIndex %i )", WI_MODULE_NAME, iEntity, iWeaponIndex); + LogMessage("[%s] {", WI_MODULE_NAME); +#endif + + //------------------------------------------------ + // Removal of extras + //------------------------------------------------ + // Checks if the replacement index is equal to -1 + // (WEAPON_REMOVE_INDEX) + // If so, check the cvar boolean and kill the + // weapon, minus medkits as these needs special + // care + + if (Weapon_Attributes[iWeaponIndex][ReplacementIndex] == WEAPON_REMOVE_INDEX + && Weapon_bConvar[iWeaponIndex] + && iWeaponIndex != WEAPON_FIRST_AID_KIT_INDEX + ) { + KillEntity(iEntity); + + #if (DEBUG_WI) + LogMessage("[%s] Killing weapon as requested...", WI_MODULE_NAME); + LogMessage("[%s] }", WI_MODULE_NAME); + #endif + + return; + } + + //------------------------------------------------ + // Check entity + //------------------------------------------------ + // Stop removing extra items that are protected + // (medkits converted to pain pills) + for (int Index = 0; Index < WEAPON_NUMBER_OF_START_KITS; Index++) { + if (Weapon_iKitEntity[Index] == iEntity) { + #if (DEBUG_WI) + LogMessage("[%s] Start kit found, save entity", WI_MODULE_NAME); + LogMessage("[%s] }", WI_MODULE_NAME); + #endif + + return; + } + } + + //------------------------------------------------ + // Check location + //------------------------------------------------ + // If the item is within the end safe room and its + // not finale + // OR + // If the items is within start safe room, and it + // is not a first aid kit + // Remove the item + float fOrigin[3]; + GetEntPropVector(iEntity, Prop_Send, "m_vecOrigin", fOrigin); + + bool bIsInStartSaferoom = false, bIsInStartSaferoomExtra = false; + bool bIsInEndSaferoom = false, bIsInFinaleArea = false; + + float fStartDistance = GetVectorDistance(Weapon_fMapOrigin_Start, fOrigin); + + if (fStartDistance <= Weapon_fMapDist_Start) { + bIsInStartSaferoom = true; + bIsInStartSaferoomExtra = true; + } else if (fStartDistance <= Weapon_fMapDist_StartExtra) { + bIsInStartSaferoomExtra = true; + } else if (GetVectorDistance(Weapon_fMapOrigin_End, fOrigin) <= Weapon_fMapDist_End) { + bIsInFinaleArea = (L4D_IsMissionFinalMap()); + } + + if (Weapon_bRemoveExtraItems && + (bIsInEndSaferoom || (bIsInStartSaferoomExtra && iWeaponIndex != WEAPON_FIRST_AID_KIT_INDEX)) + ) { + KillEntity(iEntity); + + #if (DEBUG_WI) + LogMessage("[%s] Extra item is within a safe room, killing...", WI_MODULE_NAME); + LogMessage("[%s] }", WI_MODULE_NAME); + #endif + + return; + } + + //------------------------------------------------ + // Check for medkit + //------------------------------------------------ + // No need to go on if it is not a medkit + + if (iWeaponIndex != WEAPON_FIRST_AID_KIT_INDEX) { + #if (DEBUG_WI) + LogMessage("[%s] Not a medkit and not inside any saferoom, no need to go on", WI_MODULE_NAME); + LogMessage("[%s] }", WI_MODULE_NAME); + #endif + + return; + } + + //------------------------------------------------ + // Check location of medkit + //------------------------------------------------ + // If its outside the start safe room we assume + // it is a static medkit and it needs removal + + if (Weapon_bConvar[iWeaponIndex] && !bIsInStartSaferoom && !bIsInFinaleArea) { + KillEntity(iEntity); + + #if (DEBUG_WI) + LogMessage("[%s] Static medkit outside saferoom and finale, killing...", WI_MODULE_NAME); + LogMessage("[%s] }", WI_MODULE_NAME); + #endif + + return; + } + + if (Weapon_iKitCount >= WEAPON_NUMBER_OF_START_KITS && bIsInStartSaferoom) { + KillEntity(iEntity); + + #if (DEBUG_WI) + LogMessage("[%s] More than 4 saferoom medkits found, killing entity...", WI_MODULE_NAME); + LogMessage("[%s] }", WI_MODULE_NAME); + #endif + + return; + } + + float fRotation[3]; + char sSpawnBuffer[MAX_ENTITY_NAME_LENGTH]; + + if (bIsInStartSaferoom && Weapon_bReplaceStartKits) { + GetEntPropVector(iEntity, Prop_Send, "m_angRotation", fRotation); + + KillEntity(iEntity); + + Format(sSpawnBuffer, sizeof(sSpawnBuffer), "%s%s%s", SPAWN_PREFIX, Weapon_Spawns[WEAPON_PAIN_PILLS_INDEX], SPAWN_SURFIX); + + iEntity = CreateEntityByName(sSpawnBuffer); + TeleportEntity(iEntity, fOrigin, fRotation, NULL_VECTOR); + DispatchSpawn(iEntity); + SetEntityMoveType(iEntity, MOVETYPE_NONE); + + #if (DEBUG_WI) + LogMessage("[%s] Replacing start medkit with pills", WI_MODULE_NAME); + #endif + } else if (bIsInFinaleArea && Weapon_bReplaceFinaleKits) { + GetEntPropVector(iEntity, Prop_Send, "m_angRotation", fRotation); + + KillEntity(iEntity); + + Format(sSpawnBuffer, sizeof(sSpawnBuffer), "%s%s%s", SPAWN_PREFIX, Weapon_Spawns[WEAPON_PAIN_PILLS_INDEX], SPAWN_SURFIX); + + iEntity = CreateEntityByName(sSpawnBuffer); + TeleportEntity(iEntity, fOrigin, fRotation, NULL_VECTOR); + DispatchSpawn(iEntity); + SetEntityMoveType(iEntity, MOVETYPE_NONE); + + #if (DEBUG_WI) + LogMessage("[%s] Replacing finale medkit with pills", WI_MODULE_NAME); + #endif + } + + if (bIsInStartSaferoom) { + Weapon_iKitEntity[Weapon_iKitCount++] = iEntity; + + #if (DEBUG_WI) + LogMessage("[%s] Start medkit added to array", WI_MODULE_NAME); + LogMessage("[%s] }", WI_MODULE_NAME); + #endif + } +} + +//================================================ +// PrecacheModels +//================================================ +// Loops through all the models and precache the +// ones we need +static void WI_PrecacheModels() +{ + char ModelBuffer[PLATFORM_MAX_PATH]; + for (int index = FIRST_WEAPON; index <= LAST_WEAPON; index++) { + if (strlen(Weapon_Models[index]) == 0) { + continue; + } + + Format(ModelBuffer, sizeof(ModelBuffer), "%s%s%s", MODEL_PREFIX, Weapon_Models[index], MODEL_SURFIX); + + if (IsModelPrecached(ModelBuffer)) { + continue; + } + + PrecacheModel(ModelBuffer); + + #if (DEBUG_WI) + LogMessage("[%s] Model precached: %s", WI_MODULE_NAME, ModelBuffer); + #endif + } +} + +//================================================ +// GetMapInfo +//================================================ +// Updates the global map variables if needed +static void WI_GetMapInfo() +{ + if (!Weapon_bUpdateMapInfo/* || !FindMapId() */) { + return; + } + + Weapon_fMapOrigin_Start[0] = GetMapStartOriginX(); + Weapon_fMapOrigin_Start[1] = GetMapStartOriginY(); + Weapon_fMapOrigin_Start[2] = GetMapStartOriginZ(); + Weapon_fMapOrigin_End[0] = GetMapEndOriginX(); + Weapon_fMapOrigin_End[1] = GetMapEndOriginY(); + Weapon_fMapOrigin_End[2] = GetMapEndOriginZ(); + Weapon_fMapDist_Start = GetMapStartDist(); + Weapon_fMapDist_StartExtra = GetMapStartExtraDist(); + Weapon_fMapDist_End = GetMapEndDist(); + + Weapon_bUpdateMapInfo = false; +} + +public void WI_RoundStart_Event(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + CreateTimer(0.3, WI_RoundStartLoop, _, TIMER_FLAG_NO_MAPCHANGE); +} + +public void WI_RoundEnd_Event(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + Weapon_bUpdateMapInfo = true; +} + +public Action WI_RoundStartLoop(Handle hTimer) +{ + if (!IsPluginEnabled()) { + return Plugin_Stop; + } + + WI_GetMapInfo(); + + if (Weapon_bUpdateMapInfo) { + return Plugin_Stop; + } + + WI_PrecacheModels(); + +#if (DEBUG_WI) + LogMessage("[%s] Round Start Loop( )", WI_MODULE_NAME); + LogMessage("[%s] {", WI_MODULE_NAME); +#endif + + for (int KitIndex = 0; KitIndex < WEAPON_NUMBER_OF_START_KITS; KitIndex++) { + Weapon_iKitEntity[KitIndex] = 0; + } + + Weapon_iKitCount = 0; + + char entclass[MAX_ENTITY_NAME_LENGTH]; + int iEntity, iWeaponIndex, entcount = GetEntityCount(); + + for (iEntity = (MaxClients + 1); iEntity <= entcount; iEntity++) { + if (!IsValidEdict(iEntity)) { + continue; + } + + GetEdictClassname(iEntity, entclass, sizeof(entclass)); + + iWeaponIndex = WI_GetWeaponIndex(iEntity, entclass); + if (iWeaponIndex != WEAPON_NULL_INDEX) { + if (iWeaponIndex <= LAST_WEAPON) { + WI_ReplaceWeapon(iEntity, iWeaponIndex); + } else { + WI_ReplaceExtra(iEntity, iWeaponIndex); + } + } + + if (Weapon_bRemoveLaserSight && StrContains(entclass, "upgrade_laser_sight") != -1) { + KillEntity(iEntity); + + #if (DEBUG_WI) + LogMessage("[%s] Killing laser sight...", WI_MODULE_NAME); + #endif + + continue; + } + } + +#if (DEBUG_WI) + LogMessage("[%s] Round Start Loop End", WI_MODULE_NAME); + LogMessage("[%s] }", WI_MODULE_NAME); +#endif + + return Plugin_Stop; +} + +public void WI_SpawnerGiveItem_Event(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + if (!IsPluginEnabled()) { + return; + } + + int iEntity = hEvent.GetInt("spawner"); + + char sEntityClassName[MAX_ENTITY_NAME_LENGTH]; + GetEdictClassname(iEntity, sEntityClassName, sizeof(sEntityClassName)); + + int iWeaponIndex = WI_GetWeaponIndex(iEntity, sEntityClassName); + if (iWeaponIndex == WEAPON_NULL_INDEX) { + return; + } + + WI_ReplaceWeapon(iEntity, iWeaponIndex, true); +} diff --git a/addons/sourcemod/scripting/confoglcompmod/includes/configs.sp b/addons/sourcemod/scripting/confoglcompmod/includes/configs.sp new file mode 100644 index 000000000..a4810e170 --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/includes/configs.sp @@ -0,0 +1,176 @@ +#if defined __confogl_configs_included + #endinput +#endif +#define __confogl_configs_included + +#define CONFIGS_MODULE_NAME "Configs" + +static const char + customCfgDir[] = "cfgogl"; + +static char + DirSeparator = '\0', + configsPath[PLATFORM_MAX_PATH] = "\0", + cfgPath[PLATFORM_MAX_PATH] = "\0", + customCfgPath[PLATFORM_MAX_PATH] = "\0"; + +static ConVar + hCustomConfig = null; + +void Configs_APL() +{ + CreateNative("LGO_BuildConfigPath", _native_BuildConfigPath); + CreateNative("LGO_ExecuteConfigCfg", _native_ExecConfigCfg); +} + +void Configs_OnModuleStart() +{ + InitPaths(); + + hCustomConfig = CreateConVarEx("customcfg", "", "DONT TOUCH THIS CVAR! This is more magic bullshit!", FCVAR_DONTRECORD|FCVAR_UNLOGGED); + + char cfgString[PLATFORM_MAX_PATH]; + hCustomConfig.GetString(cfgString, sizeof(cfgString)); + SetCustomCfg(cfgString); + + hCustomConfig.RestoreDefault(); +} + +static void InitPaths() +{ + BuildPath(Path_SM, configsPath, sizeof(configsPath), "configs/confogl/"); + BuildPath(Path_SM, cfgPath, sizeof(cfgPath), "../../cfg/"); + + DirSeparator = cfgPath[(strlen(cfgPath) - 1)]; +} + +bool SetCustomCfg(const char[] cfgname) +{ + if (!strlen(cfgname)) { + customCfgPath[0] = 0; + hCustomConfig.RestoreDefault(); + + if (IsDebugEnabled()) { + LogMessage("[%s] Custom Config Path Reset - Using Default", CONFIGS_MODULE_NAME); + } + + return true; + } + + Format(customCfgPath, sizeof(customCfgPath), "%s%s%c%s", cfgPath, customCfgDir, DirSeparator, cfgname); + if (!DirExists(customCfgPath)) { + Debug_LogError(CONFIGS_MODULE_NAME, "Custom config directory %s does not exist!", customCfgPath); + // Revert customCfgPath + customCfgPath[0] = 0; + return false; + } + + int thislen = strlen(customCfgPath); + if ((thislen + 1) < sizeof(customCfgPath)) { + customCfgPath[thislen] = DirSeparator; + customCfgPath[(thislen + 1)] = 0; + } else { + Debug_LogError(CONFIGS_MODULE_NAME, "Custom config directory %s path too long!", customCfgPath); + customCfgPath[0] = 0; + return false; + } + + hCustomConfig.SetString(cfgname); + + return true; +} + +void BuildConfigPath(char[] buffer, const int maxlength, const char[] sFileName) +{ + if (customCfgPath[0]) { + Format(buffer, maxlength, "%s%s", customCfgPath, sFileName); + + if (FileExists(buffer)) { + if (IsDebugEnabled()) { + LogMessage("[%s] Built custom config path: %s", CONFIGS_MODULE_NAME, buffer); + } + + return; + } else { + if (IsDebugEnabled()) { + LogMessage("[%s] Custom config not available: %s", CONFIGS_MODULE_NAME, buffer); + } + } + } + + Format(buffer, maxlength, "%s%s", configsPath, sFileName); + if (IsDebugEnabled()) { + LogMessage("[%s] Built default config path: %s", CONFIGS_MODULE_NAME, buffer); + } +} + +void ExecuteCfg(const char[] sFileName) +{ + if (strlen(sFileName) == 0) { + return; + } + + char sFilePath[PLATFORM_MAX_PATH]; + + if (customCfgPath[0]) { + Format(sFilePath, sizeof(sFilePath), "%s%s", customCfgPath, sFileName); + + if (FileExists(sFilePath)) { + if (IsDebugEnabled()) { + LogMessage("[%s] Executing custom cfg file %s", CONFIGS_MODULE_NAME, sFilePath); + } + + ServerCommand("exec %s%s", customCfgPath[strlen(cfgPath)], sFileName); + + return; + } else { + if (IsDebugEnabled()) { + LogMessage("[%s] Couldn't find custom cfg file %s, trying default", CONFIGS_MODULE_NAME, sFilePath); + } + } + } + + Format(sFilePath, sizeof(sFilePath), "%s%s", cfgPath, sFileName); + + if (FileExists(sFilePath)) { + if (IsDebugEnabled()) { + LogMessage("[%s] Executing default config %s", CONFIGS_MODULE_NAME, sFilePath); + } + + ServerCommand("exec %s", sFileName); + } else { + Debug_LogError(CONFIGS_MODULE_NAME, "Could not execute server config \"%s\", file not found", sFilePath); + } +} + +public int _native_BuildConfigPath(Handle plugin, int numParams) +{ + int iLen = 0; + GetNativeStringLength(3, iLen); + + int iNewLen = iLen + 1; + char[] sFileName = new char[iNewLen]; + GetNativeString(3, sFileName, iNewLen); + + iLen = GetNativeCell(2); + + char[] sBuf = new char[iLen]; + BuildConfigPath(sBuf, iLen, sFileName); + SetNativeString(1, sBuf, iLen); + + return 1; +} + +public int _native_ExecConfigCfg(Handle plugin, int numParams) +{ + int iLen = 0; + GetNativeStringLength(1, iLen); + + int iNewLen = iLen + 1; + char[] sFileName = new char[iNewLen]; + GetNativeString(1, sFileName, iNewLen); + + ExecuteCfg(sFileName); + + return 1; +} diff --git a/addons/sourcemod/scripting/confoglcompmod/includes/constants.sp b/addons/sourcemod/scripting/confoglcompmod/includes/constants.sp new file mode 100644 index 000000000..6ee8fc2ed --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/includes/constants.sp @@ -0,0 +1,115 @@ +#if defined __confogl_constants_included + #endinput +#endif +#define __confogl_constants_included + +#define MAX_ENTITY_NAME_LENGTH 64 + +#define NUM_OF_SURVIVORS 4 + +#define START_SAFEROOM (1 << 0) +#define END_SAFEROOM (1 << 1) + +#define SPAWNFLAG_READY 0 +#define SPAWNFLAG_CANSPAWN (0 << 0) +#define SPAWNFLAG_DISABLED (1 << 0) +#define SPAWNFLAG_WAITFORSURVIVORS (1 << 1) +#define SPAWNFLAG_WAITFORFINALE (1 << 2) +#define SPAWNFLAG_WAITFORTANKTODIE (1 << 3) +#define SPAWNFLAG_SURVIVORESCAPED (1 << 4) +#define SPAWNFLAG_DIRECTORTIMEOUT (1 << 5) +#define SPAWNFLAG_WAITFORNEXTWAVE (1 << 6) +#define SPAWNFLAG_CANBESEEN (1 << 7) +#define SPAWNFLAG_TOOCLOSE (1 << 8) +#define SPAWNFLAG_RESTRICTEDAREA (1 << 9) +#define SPAWNFLAG_BLOCKED (1 << 10) + +enum +{ + L4D2Team_None = 0, + L4D2Team_Spectator, + L4D2Team_Survivor, + L4D2Team_Infected, + + L4D2Team_Size //4 size +}; + +enum +{ + L4D2Infected_Common = 0, + L4D2Infected_Smoker = 1, + L4D2Infected_Boomer, + L4D2Infected_Hunter, + L4D2Infected_Spitter, + L4D2Infected_Jockey, + L4D2Infected_Charger, + L4D2Infected_Witch, + L4D2Infected_Tank, + L4D2Infected_Survivor, + + L4D2Infected_Size //10 size +}; + +enum +{ + L4D2WeaponSlot_Primary = 0, + L4D2WeaponSlot_Secondary, + L4D2WeaponSlot_Throwable, + L4D2WeaponSlot_HeavyHealthItem, + L4D2WeaponSlot_LightHealthItem, + + L4D2WeaponSlot_Size //5 size +}; + +enum /*WeaponIDs*/ +{ + WEPID_PISTOL = 1, + WEPID_SMG, // 2 + WEPID_PUMPSHOTGUN, // 3 + WEPID_AUTOSHOTGUN, // 4 + WEPID_RIFLE, // 5 + WEPID_HUNTING_RIFLE, // 6 + WEPID_SMG_SILENCED, // 7 + WEPID_SHOTGUN_CHROME, // 8 + WEPID_RIFLE_DESERT, // 9 + WEPID_SNIPER_MILITARY, // 10 + WEPID_SHOTGUN_SPAS, // 11 + WEPID_FIRST_AID_KIT, // 12 + WEPID_MOLOTOV, // 13 + WEPID_PIPE_BOMB, // 14 + WEPID_PAIN_PILLS, // 15 + WEPID_GASCAN, // 16 + WEPID_PROPANE_TANK, // 17 + WEPID_AIR_CANISTER, // 18 + WEPID_CHAINSAW = 20, + WEPID_GRENADE_LAUNCHER, // 21 + WEPID_ADRENALINE = 23, + WEPID_DEFIBRILLATOR, // 24 + WEPID_VOMITJAR, // 25 + WEPID_RIFLE_AK47, // 26 + WEPID_GNOME_CHOMPSKI, // 27 + WEPID_COLA_BOTTLES, // 28 + WEPID_FIREWORKS_BOX, // 29 + WEPID_INCENDIARY_AMMO, // 30 + WEPID_FRAG_AMMO, // 31 + WEPID_PISTOL_MAGNUM, // 32 + WEPID_SMG_MP5, // 33 + WEPID_RIFLE_SG552, // 34 + WEPID_SNIPER_AWP, // 35 + WEPID_SNIPER_SCOUT, // 36 + WEPID_RIFLE_M60, // 37 + + WEPID_SIZE +}; + +/*stock const char g_sTeamName[8][] = +{ + "Spectator", + "" , + "Survivor", + "Infected", + "", + "Infected", + "Survivors", + "Infected" +};*/ diff --git a/addons/sourcemod/scripting/confoglcompmod/includes/customtags.sp b/addons/sourcemod/scripting/confoglcompmod/includes/customtags.sp new file mode 100644 index 000000000..df0d0cc7f --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/includes/customtags.sp @@ -0,0 +1,105 @@ +#if defined __confogl_customtags_included + #endinput +#endif +#define __confogl_customtags_included + +// COPYRIGHT PSYCHONIC +// USED WITH PERMISSION + +#define CT_MODULE_NAME "CustomTags" + +#define SV_TAG_SIZE 64 + +static stock bool + are_tags_hooked = false, + ignore_next_change = false; + +static stock ConVar + sv_tags = null; + +static stock ArrayList + custom_tags = null; + +void CT_OnModuleStart() +{ + custom_tags = new ArrayList(ByteCountToCells(SV_TAG_SIZE)); + + sv_tags = FindConVar("sv_tags"); +} + +stock void AddCustomServerTag(const char[] tag) +{ + if (custom_tags.FindString(tag) == -1) { + custom_tags.PushString(tag); + } + + char current_tags[SV_TAG_SIZE]; + sv_tags.GetString(current_tags, sizeof(current_tags)); + + if (StrContains(current_tags, tag) > -1) { + // already have tag + return; + } + + char new_tags[SV_TAG_SIZE]; + Format(new_tags, sizeof(new_tags), "%s%s%s", current_tags, (current_tags[0] != 0) ? "," : "", tag); + + int flags = sv_tags.Flags; + sv_tags.Flags = flags & ~FCVAR_NOTIFY; + + ignore_next_change = true; + sv_tags.SetString(new_tags); + ignore_next_change = false; + + sv_tags.Flags = flags; + + if (!are_tags_hooked) { + sv_tags.AddChangeHook(OnTagsChanged); + are_tags_hooked = true; + } +} + +stock void RemoveCustomServerTag(const char[] tag) +{ + int idx = custom_tags.FindString(tag); + if (idx > -1) { + custom_tags.Erase(idx); + } + + char current_tags[SV_TAG_SIZE]; + sv_tags.GetString(current_tags, sizeof(current_tags)); + + if (StrContains(current_tags, tag) == -1) { + // tag isn't on here, just bug out + return; + } + + ReplaceString(current_tags, sizeof(current_tags), tag, ""); + ReplaceString(current_tags, sizeof(current_tags), ",,", ""); + + int flags = sv_tags.Flags; + sv_tags.Flags = flags & ~FCVAR_NOTIFY; + + ignore_next_change = true; + sv_tags.SetString(current_tags); + ignore_next_change = false; + + sv_tags.Flags = flags; +} + +public void OnTagsChanged(ConVar hConvar, const char[] sOldValue, const char[] sNewValue) +{ + if (ignore_next_change) { + // we fired this callback, no need to reapply tags + return; + } + + // reapply each custom tag + char tag[SV_TAG_SIZE]; + int iSize = custom_tags.Length; + + for (int i = 0; i < iSize; i++) { + custom_tags.GetString(i, tag, sizeof(tag)); + AddCustomServerTag(tag); + } +} diff --git a/addons/sourcemod/scripting/confoglcompmod/includes/debug.sp b/addons/sourcemod/scripting/confoglcompmod/includes/debug.sp new file mode 100644 index 000000000..7b6199262 --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/includes/debug.sp @@ -0,0 +1,77 @@ +#if defined __confogl_debug_included + #endinput +#endif +#define __confogl_debug_included + +#if DEBUG_ALL + #define DEBUG_DEFAULT "1" +#else + #define DEBUG_DEFAULT "0" +#endif + +static char + g_sLogAction[256]; + +static bool + g_bConfoglDebug = false; + +static ConVar + g_hCvarCustomErrorLog = null, + g_hCvarDebugConVar = null; + +void Debug_OnModuleStart() +{ + g_hCvarDebugConVar = CreateConVarEx("debug", DEBUG_DEFAULT, "Turn on Debug Logging in all Confogl Modules", _, true, 0.0, true, 1.0); + + //confogl_custom_error_logs + g_hCvarCustomErrorLog = CreateConVarEx( \ + "custom_error_logs", \ + "1", \ + "Write logs to custom error log file (0 - use sourcemod error log file, 1 - use custom error log file)", \ + _, true, 0.0, true, 1.0 \ + ); + + g_bConfoglDebug = g_hCvarDebugConVar.BoolValue; + g_hCvarDebugConVar.AddChangeHook(Debug_ConVarChange); + + char sTime[64], sBuffer[64]; + FormatTime(sTime, sizeof(sTime), "%Y%m%d"); + FormatEx(sBuffer, sizeof(sBuffer), "logs/confoglcompmod/errors_%s.log", sTime); //errors_20211201.log + BuildPath(Path_SM, g_sLogAction, sizeof(g_sLogAction), sBuffer); + + BuildPath(Path_SM, sBuffer, sizeof(sBuffer), "logs/confoglcompmod"); + if (!DirExists(sBuffer)) { + CreateDirectory(sBuffer, 511); + } +} + +public void Debug_ConVarChange(ConVar hConvar, const char[] sOldValue, const char[] sNewValue) +{ + g_bConfoglDebug = hConvar.BoolValue; +} + +stock bool IsDebugEnabled() +{ + return (g_bConfoglDebug || DEBUG_ALL); +} + +stock void Debug_LogError(const char[] sModuleName, const char[] sMessage, any ...) +{ + static char sFormat[512]; + VFormat(sFormat, sizeof(sFormat), sMessage, 3); + + static char sMap[64]; + GetCurrentMap(sMap, sizeof(sMap)); + + Format(sFormat, sizeof(sFormat), "[%s] [%s] %s", sModuleName, sMap, sFormat); + + if (!g_hCvarCustomErrorLog.BoolValue) { + // L 12/16/2021 - 12:10:15: [confoglcompmod.smx] [CvarSettings] [c4m1_milltown_a] Could not find CVar specified (l4d2_meleecontrol_enable) + LogError(sFormat); + return; + } + + // Same as LogToFile(), except no plugin logtag is prepended. + // L 12/16/2021 - 12:11:45: [CvarSettings] [c4m1_milltown_a] Could not find CVar specified (l4d2_meleecontrol_enable) + LogToFileEx(g_sLogAction, sFormat); +} diff --git a/addons/sourcemod/scripting/confoglcompmod/includes/functions.sp b/addons/sourcemod/scripting/confoglcompmod/includes/functions.sp new file mode 100644 index 000000000..5c498dc0a --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/includes/functions.sp @@ -0,0 +1,201 @@ +#if defined __confogl_functions_included + #endinput +#endif +#define __confogl_functions_included + +#define CVAR_PREFIX "confogl_" +#define CVAR_FLAGS FCVAR_NONE +#define CVAR_PRIVATE (FCVAR_DONTRECORD|FCVAR_PROTECTED) + +static ConVar + g_hCvarMpGameMode = null, + g_hCvarPainPillsDecayRate = null; + +static bool + bIsPluginEnabled = false; + +void Fns_OnModuleStart() +{ + g_hCvarMpGameMode = FindConVar("mp_gamemode"); + g_hCvarPainPillsDecayRate = FindConVar("pain_pills_decay_rate"); +} + +stock ConVar CreateConVarEx(const char[] name, const char[] defaultValue, const char[] description = "", int flags = FCVAR_NONE, \ + bool hasMin = false, float min = 0.0, bool hasMax = false, float max = 0.0) +{ + char sBuffer[128]; + ConVar cvar = null; + + Format(sBuffer, sizeof(sBuffer), "%s%s", CVAR_PREFIX, name); + flags = flags | CVAR_FLAGS; + cvar = CreateConVar(sBuffer, defaultValue, description, flags, hasMin, min, hasMax, max); + + return cvar; +} + +stock ConVar FindConVarEx(const char[] name) +{ + char sBuffer[128]; + Format(sBuffer, sizeof(sBuffer), "%s%s", CVAR_PREFIX, name); + + return FindConVar(sBuffer); +} + +stock bool IsHumansOnServer() +{ + for (int i = 1; i <= MaxClients; i++) { + if (IsClientConnected(i) && !IsFakeClient(i)) { + return true; + } + } + + return false; +} + +stock bool IsVersus() +{ + char GameMode[32]; + g_hCvarMpGameMode.GetString(GameMode, sizeof(GameMode)); + return (StrContains(GameMode, "versus", false) != -1); +} + +/*stock bool IsScavenge() +{ + char GameMode[32]; + g_hCvarMpGameMode.GetString(GameMode, sizeof(GameMode)); + return (StrContains(GameMode, "scavenge", false) != -1); +}*/ + +stock bool IsPluginEnabled(bool bSetStatus = false, bool bStatus = false) +{ + if (bSetStatus) { + bIsPluginEnabled = bStatus; + } + + return bIsPluginEnabled; +} + +stock int GetSurvivorPermanentHealth(int client) +{ + return GetEntProp(client, Prop_Send, "m_iHealth"); +} + +stock int GetSurvivorTempHealth(int client) +{ + float fHealthBuffer = GetEntPropFloat(client, Prop_Send, "m_healthBuffer"); + float fHealthBufferDuration = GetGameTime() - GetEntPropFloat(client, Prop_Send, "m_healthBufferTime"); + + int iTempHp = RoundToCeil(fHealthBuffer - (fHealthBufferDuration * g_hCvarPainPillsDecayRate.FloatValue)) - 1; + + return (iTempHp > 0) ? iTempHp : 0; +} + +stock int GetSurvivorIncapCount(int client) +{ + return GetEntProp(client, Prop_Send, "m_currentReviveCount"); +} + +stock bool IsSurvivor(int client) +{ + return (IsClientInGame(client) && GetClientTeam(client) == L4D2Team_Survivor); +} + +stock void ZeroVector(float vector[3]) +{ + vector = NULL_VECTOR; +} + +stock void AddToVector(float to[3], float from[3]) +{ + to[0] += from[0]; + to[1] += from[1]; + to[2] += from[2]; +} + +stock void CopyVector(float to[3], float from[3]) +{ + to = from; +} + +stock int GetURandomIntRange(int min, int max) +{ + return RoundToNearest((GetURandomFloat() * (max - min)) + min); +} + +stock void KillEntity(int iEntity) +{ +#if SOURCEMOD_V_MINOR > 8 + RemoveEntity(iEntity); +#else + AcceptEntityInput(iEntity, "Kill"); +#endif +} + +/** + * Finds the first occurrence of a pattern in another string. + * + * @param str String to search in. + * @param pattern String pattern to search for + * @param reverse False (default) to search forward, true to search + * backward. + * @return The index of the first character of the first + * occurrence of the pattern in the string, or -1 if the + * character was not found. + */ +/*stock int FindPatternInString(const char[] str, const char[] pattern, bool reverse = false) +{ + int i = 0, len = strlen(pattern); + char c = pattern[0]; + + while (i < len && (i = FindCharInString(str[i], c, reverse)) != -1) { + if (strncmp(str[i], pattern, len)) { + return i; + } + } + + return -1; +}*/ + +/** + * Counts the number of occurences of pattern in another string. + * + * @param str String to search in. + * @param pattern String pattern to search for + * @param overlap False (default) to count only non-overlapping + * occurences, true to count matches within other + * occurences. + * @return The number of occurences of the pattern in the string + */ +/*stock int CountPatternsInString(const char[] str, const char[] pattern, bool overlap = false) +{ + int off = 0, i = 0, delta = 0, cnt = 0; + int len = strlen(str); + + delta = (overlap) ? strlen(pattern) : 1; + + while (i < len && (off = FindPatternInString(str[i], pattern)) != -1) { + cnt++; + i += off + delta; + } + + return cnt; +}*/ + +/** + * Counts the number of occurences of pattern in another string. + * + * @param str String to search in. + * @param c Character to search for. + * @return The number of occurences of the pattern in the string + */ +/*stock int CountCharsInString(const char[] str, int c) +{ + int off, i, cnt, len = strlen(str); + + while (i < len && (off = FindCharInString(str[i], c)) != -1) { + cnt++; + i += off + 1; + } + + return cnt; +}*/ diff --git a/addons/sourcemod/scripting/confoglcompmod/includes/survivorindex.sp b/addons/sourcemod/scripting/confoglcompmod/includes/survivorindex.sp new file mode 100644 index 000000000..74e28e0cb --- /dev/null +++ b/addons/sourcemod/scripting/confoglcompmod/includes/survivorindex.sp @@ -0,0 +1,98 @@ +#if defined __confogl_survivor_index_included + #endinput +#endif +#define __confogl_survivor_index_included + +#define SI_MODULE_NAME "SurvivorIndex" + +static int + iSurvivorIndex[NUM_OF_SURVIVORS] = {0, ...}; + +void SI_OnModuleStart() +{ + HookEvent("round_start", SI_BuildIndex_Event, EventHookMode_PostNoCopy); + HookEvent("round_end", SI_BuildIndex_Event, EventHookMode_PostNoCopy); + HookEvent("player_spawn", SI_BuildIndex_Event, EventHookMode_PostNoCopy); + HookEvent("player_disconnect", SI_BuildIndex_Event, EventHookMode_PostNoCopy); + HookEvent("player_death", SI_BuildIndex_Event, EventHookMode_PostNoCopy); + HookEvent("player_bot_replace", SI_BuildIndex_Event, EventHookMode_PostNoCopy); + HookEvent("bot_player_replace", SI_BuildIndex_Event, EventHookMode_PostNoCopy); + HookEvent("defibrillator_used", SI_BuildIndex_Event, EventHookMode_PostNoCopy); + HookEvent("player_team", SI_BuildIndexDelay_Event, EventHookMode_PostNoCopy); +} + +static void SI_BuildIndex() +{ + if (!IsServerProcessing() || !IsPluginEnabled()) { + return; + } + + int ifoundsurvivors = 0, character = 0; + + // Make sure kicked survivors don't freak us out. + for (int i = 0; i < NUM_OF_SURVIVORS; i++) { + iSurvivorIndex[i] = 0; + } + + for (int client = 1; client <= MaxClients; client++) { + if (ifoundsurvivors == NUM_OF_SURVIVORS) { + break; + } + + if (!IsClientInGame(client) || GetClientTeam(client) != L4D2Team_Survivor) { + continue; + } + + character = GetEntProp(client, Prop_Send, "m_survivorCharacter"); + ifoundsurvivors++; + + if (character > 3 || character < 0) { + continue; + } + + iSurvivorIndex[character] = 0; + + if (!IsPlayerAlive(client)) { + continue; + } + + iSurvivorIndex[character] = client; + } +} + +public void SI_BuildIndexDelay_Event(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + CreateTimer(0.3, SI_BuildIndex_Timer, _, TIMER_FLAG_NO_MAPCHANGE); +} + +public Action SI_BuildIndex_Timer(Handle hTimer) +{ + SI_BuildIndex(); + + return Plugin_Stop; +} + +public void SI_BuildIndex_Event(Event hEvent, const char[] sEventName, bool bDontBroadcast) +{ + SI_BuildIndex(); +} + +stock int GetSurvivorIndex(int index) +{ + if (index < 0 || index > 3) { + return 0; + } + + return iSurvivorIndex[index]; +} + +stock bool IsAnySurvivorsAlive() +{ + for (int index = 0; index < NUM_OF_SURVIVORS; index++) { + if (iSurvivorIndex[index]) { + return true; + } + } + + return false; +} diff --git a/addons/sourcemod/scripting/include/confogl.inc b/addons/sourcemod/scripting/include/confogl.inc index 064fed3fe..595b0f331 100644 --- a/addons/sourcemod/scripting/include/confogl.inc +++ b/addons/sourcemod/scripting/include/confogl.inc @@ -1,6 +1,6 @@ /* * * ============================================================================= - * Confogl.inc + * Confogl.inc * Confogl (C)2011 Confogl Team * ============================================================================= * @@ -9,10 +9,10 @@ * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License, version 3.0, as published by the * Free Software Foundation. - * + * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with @@ -28,17 +28,18 @@ * or . * */ -#if defined _confogl_Included + +#if defined _confogl_included #endinput #endif -#define _confogl_Included +#define _confogl_included /* Forwards */ /** * @brief Called when matchmode is fully loaded, before map restart. * @remarks Called just before confogl_plugins.cfg executes - * + * * @noreturn */ forward void LGO_OnMatchModeLoaded(); @@ -46,7 +47,7 @@ forward void LGO_OnMatchModeLoaded(); /** * @brief Called when matchmode is un-loaded, before map restart. * @remarks Plugins are unloaded immediately after this call finishes - * + * * @noreturn */ forward void LGO_OnMatchModeUnloaded(); @@ -56,7 +57,7 @@ forward void LGO_OnMatchModeUnloaded(); /** * @brief Tells if a confogl match is currently running * @remarks Formerly IsPluginEnabled() internally - * + * * @return True if matchmode is loaded, false otherwise */ native bool LGO_IsMatchModeLoaded(); @@ -64,7 +65,7 @@ native bool LGO_IsMatchModeLoaded(); /** * @brief Build a filepath relative to the current running config. * @remarks Should produce a path in cfg/cfgogl/CONFIG/ or addons/sourcemod/configs/confogl - * + * * @param buffer Buffer to write the path to * @param maxlength Buffer size * @param sFileName Name of the file to look for in the config @@ -75,7 +76,7 @@ native void LGO_BuildConfigPath(char[] buffer, int maxlength, const char[] sFile /** * @brief Execute a cfg file for the current config * @remarks Should execute the named .cfg in cfg/ or cfg/cfgogl/CURRENT_CONFIG/ - * + * * @param sFileName Name of the cfg file to execute * @noreturn */ @@ -84,7 +85,7 @@ native void LGO_ExecuteConfigCfg(const char[] sFileName); /** * @brief Tells if map data is available * @remarks Map data should be available when any map is loaded, after OnMapStart() - * + * * @return True if map data is available, false if it is not. */ native bool LGO_IsMapDataAvailable(); @@ -92,7 +93,7 @@ native bool LGO_IsMapDataAvailable(); /** * @brief Get an Int value from the MapInfo keyvalues for the current map with a specific key * @remarks Mapinfo keyvalues is used to store static data about maps - * + * * @param key Key to read the value from * @param defvalue Default value to return if key is not found (default 0) * @return Integer value for given key, or defvalue if key is not found @@ -102,7 +103,7 @@ native int LGO_GetMapValueInt(const char[] key, const int defvalue = 0); /** * @brief Get a Float value from the MapInfo keyvalues for the current map with a specific key * @remarks Mapinfo keyvalues is used to store static data about maps - * + * * @param key Key to read the value from * @param defvalue Default value to return if key is not found (default 0.0) * @return Float value for given key, or defvalue if key is not found @@ -112,7 +113,7 @@ native float LGO_GetMapValueFloat(const char[] key, const float defvalue = 0.0); /** * @brief Get a Vector from the MapInfo keyvalues for the current map with a specific key * @remarks Mapinfo keyvalues is used to store static data about maps - * + * * @param key Key to read the value from * @param vector Vector to store the result in * @param defvalue Default value to use if key is not found (default NULL_VECTOR) @@ -123,7 +124,7 @@ native void LGO_GetMapValueVector(const char[] key, float vector[3], const float /** * @brief Get a String from the MapInfo keyvalues for the current map with a specific key * @remarks Mapinfo keyvalues is used to store static data about maps - * + * * @param key Key to read the value from * @param value String to store the result in * @param maxlength Maximum length to write to the value String buffer @@ -135,14 +136,26 @@ native void LGO_GetMapValueString(const char[] key, char[] value, int maxlength, /** * @brief Copy a Subsection from the MapInfo keyvalues for the current map * @remarks Mapinfo keyvalues is used to store static data about maps - * + * * @param kv KeyValues Handle to copy to * @param section Name of the section to copy * @noreturn */ native void LGO_CopyMapSubsection(KeyValues kv, const char[] section); -public SharedPlugin __pl_confogl = +/** + * @brief Informs if the module 'ScoreMod' is activated now (confogl activated and scoremod activated) + * @return (bool) returns true if activated, false otherwise + */ +native bool LGO_IsScoremodEnabled(); + +/** + * @brief Returns the amount of bonus if the module 'Scoremod' is activated + * @return (int) bonus amount, or return -1 if confogl disable or scoremod disable + */ +native int LGO_GetHealthScore(); + +public SharedPlugin __pl_confogl = { name = "confogl", file = "confoglcompmod.smx", @@ -165,5 +178,7 @@ public void __pl_confogl_SetNTVOptional() MarkNativeAsOptional("LGO_GetMapValueString"); MarkNativeAsOptional("LGO_CopyMapSubsection"); MarkNativeAsOptional("LGO_IsMatchModeLoaded"); + MarkNativeAsOptional("LGO_IsScoremodEnabled"); + MarkNativeAsOptional("LGO_GetHealthScore"); } #endif