diff --git a/Changelogs/Roto-AZMod v8.5.9.md b/Changelogs/Roto-AZMod v8.5.9.md new file mode 100644 index 00000000..c84abb3d --- /dev/null +++ b/Changelogs/Roto-AZMod v8.5.9.md @@ -0,0 +1,22 @@ +v8.5.9 + +* Fix l4dtoolz, Please re-download latest "Windows Server files" or "Linux Server files" + +## Delete +None + +## New +* l4d_unreservelobby.smx: Removes lobby reservation when server is full, allow 9+ players to join server + +## Update +* l4d_consistent_escaperoute +* Enhanced_Throwables +* rotoblin-az.smx +* cfg/server.cfg + +## Change +* Now player can connect server from lobby +* Server now has lobby reservation when first player joins the server, and removes lobby reservation once server is full + + + diff --git a/README.md b/README.md index f1f3f807..5f75781c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Rotoblin-AZMod -v8.5.8 +v8.5.9
Developer @ 2017-2024 [Harry](http://steamcommunity.com/profiles/76561198026784913)
- [Navigation](#rotoblin-azmod) @@ -41,7 +41,7 @@ A Competitive L4D1 Versus Configuration. Based upon the L4D2 [Acemod V4 Release] * Install "Roto-AZMod Main files", this contains the configs, plugins, gamedate, and other server settings. * At this step, you already setup Server's base for configs, so you can finally start the server. * Launch parameters: - * ```-console -game left4dead -tickrate 100 +log on +map l4d_vs_airport01_greenhouse +exec server +sv_lan 0``` + * ```-console -game left4dead +log on +map l4d_vs_airport01_greenhouse +exec server +sv_lan 0 -tickrate 100 -maxplayers 31``` - - - - ### Server Install Optional ### diff --git a/SourceCode/scripting-az/include/left4dhooks.inc b/SourceCode/scripting-az/include/left4dhooks.inc index 9f9477a4..70ed6067 100644 --- a/SourceCode/scripting-az/include/left4dhooks.inc +++ b/SourceCode/scripting-az/include/left4dhooks.inc @@ -60,18 +60,18 @@ -// Natives: 273 (including 3 for L4D1 only) +// Natives: 274 (including 3 for L4D1 only) // L4D1 = 31 [left4downtown] + 47 [l4d_direct] + 16 [l4d2addresses] + 73 [silvers - mine!] + 4 [anim] = 172 -// L4D2 = 61 [left4downtown] + 59 [l4d_direct] + 31 [l4d2addresses] + 117 [silvers - mine!] + 4 [anim] = 272 +// L4D2 = 61 [left4downtown] + 59 [l4d_direct] + 31 [l4d2addresses] + 118 [silvers - mine!] + 4 [anim] = 273 // Methods and Natives by "Forgetest": 53 [PlayerAnimState] + 22 [Ammo_t] + 15 [AmmoDef] = 90 -// Forwards: 221 (including 5 for L4D1 only) -// L4D1 = 147 -// L4D2 = 216 +// Forwards: 224 (including 5 for L4D1 only) +// L4D1 = 149 +// L4D2 = 219 // Stocks: 169 (L4D1 = 114, L4D2 = 167) // left4dhooks_silver 46 stocks (L4D1 = 39, L4D2 = 53) -// left4dhooks_stocks 84 stocks (L4D1 = 45, L4D2 = 80) +// left4dhooks_stocks 86 stocks (L4D1 = 46, L4D2 = 81) // left4dhooks_lux_library 34 stocks (L4D1 = 30, L4D2 = 34) @@ -121,6 +121,7 @@ public void __pl_l4dh_SetNTVOptional() MarkNativeAsOptional("L4D2_SetFirstSpawnClass"); MarkNativeAsOptional("L4D_FindRandomSpot"); MarkNativeAsOptional("L4D2_IsVisibleToPlayer"); + MarkNativeAsOptional("L4D2_GetSpecialInfectedDominatingMe"); MarkNativeAsOptional("L4D_HasAnySurvivorLeftSafeArea"); MarkNativeAsOptional("L4D_IsAnySurvivorInStartArea"); MarkNativeAsOptional("L4D_IsAnySurvivorInCheckpoint"); @@ -389,6 +390,7 @@ public void __pl_l4dh_SetNTVOptional() MarkNativeAsOptional("L4D_State_Transition"); MarkNativeAsOptional("L4D_RegisterForbiddenTarget"); MarkNativeAsOptional("L4D_UnRegisterForbiddenTarget"); + MarkNativeAsOptional("L4D_IsEntitySaveable"); MarkNativeAsOptional("L4D2_CTerrorPlayer_OnHitByVomitJar"); MarkNativeAsOptional("L4D2_Infected_OnHitByVomitJar"); MarkNativeAsOptional("L4D2_CTerrorPlayer_Fling"); @@ -842,7 +844,7 @@ enum WeaponType WEAPONTYPE_UNKNOWN }; -stock static const char g_sWeaponTypes[WeaponType][] = +stock const char g_sWeaponTypes[WeaponType][16] = { "pistol", "smg", @@ -1217,6 +1219,28 @@ methodmap AmmoDef +// ==================================================================================================== +// STOCKS +// ==================================================================================================== + +/** + * @brief Returns a weapons classname from the WeaponType valu + * @remarks This is only to prevent SM 1.12 warnings about unused variables + * + * @param type WeaponType + * @return Classname string + * @error Invalid type index + */ +// L4D2 only +stock char[] L4D2_GetWeaponClassname(WeaponType type) +{ + return g_sWeaponTypes[type]; +} + + + + + // ==================================================================================================== // ANIMATION HOOK // ==================================================================================================== @@ -1681,7 +1705,7 @@ forward void L4D_OnMaterializeFromGhost_PostHandled(int client); /** * @brief Called whenever CDirector::OnFinishIntro is invoked * @remarks called when the intro cutscene has finished - * @remarks This is a post hook, it appears to be called before the "L4D_OnReleaseSurvivorPositions" forward. + * @remarks This is a post hook, it appears to be called before the "L4D_OnReleaseSurvivorPositions" forward * * @noreturn */ @@ -2457,6 +2481,16 @@ forward void L4D_OnDoAnimationEvent_PostHandled(int client, int event, int varia // 2020 Left4DHooks update: Blocked on L4D1/L4D2 Linux to prevent crashes. Waiting for DHooks update to support object returns forward Action L4D2_OnSendInRescueVehicle(); +/** + * @brief Called whenever CDirector::CreateRescuableSurvivors is invoked + * @remarks Called when the director is attempting to find survivors to respawn in rescue closets + * @remarks The value for every client in the "players" array will be set to 0, change this value to 1 to prevent their ghost appearing in rescue closets + * @remarks This is called every frame, so don't add complicated expensive logic within here + * + * @return Plugin_Changed to modify who is allowed to spawn, Plugin_Continue otherwise + */ +forward Action L4D_OnCreateRescuableSurvivors(int players[MAXPLAYERS+1]); + /** * @brief Called whenever CDirectorScriptedEventManager::ChangeFinaleStage is invoked * @remarks Called when the director stage changes @@ -3088,7 +3122,7 @@ forward Action L4D2_OnFindScavengeItem(int client, int &item); * * @return Plugin_Handled to block, Plugin_Changed to use overwritten values from plugin, Plugin_Continue otherwise */ -// FOr a future update: +// For a future update: // * @param targetScanFlags targeting flags (unknown) // * @param ignoreTarget entity to ignore targeting // forward Action L4D2_OnChooseVictim_Pre(int specialInfected, int &lastTarget, int &targetScanFlags, int &ignoreTarget); // For a future update @@ -3350,6 +3384,21 @@ forward void L4D2_OnPummelVictim_Post(int attacker, int victim); // L4D2 only forward void L4D2_OnPummelVictim_PostHandled(int attacker, int victim); +/** + * @brief Called when CTerrorPlayer::IsDominatedBySpecialInfected() is invoked and returned true + * @remarks Call when a player is being dominated, called over multiple frames + * @remarks Dominators are: Hunter, Smoker, Jockey, and Charger + * @remarks This forward is called in frames, but instantly tells you when any domination happened. Recommend not to put too much logic in here + * @remarks For Chargers, this forward is called when being carried or being pummelled. Queue pummelling will not trigger this forward + * + * @param victim Client index of the victim + * @param dominator Client index of the dominator + * + * @noreturn + **/ +// L4D2 Only +forward void L4D2_OnDominatedBySpecialInfected(int victim, int dominator); + /** * @brief Called whenever CTerrorPlayer::OnVomitedUpon is invoked * @remarks Called when a Survivor player is covered in Boomer bile, or when using "Bile the World" plugin by "AtomicStryker" @@ -4161,6 +4210,91 @@ forward void L4D_OnGameModeChange(int gamemode); */ forward void L4D_OnServerHibernationUpdate(bool hibernating); +/** + * @brief Called whenever InfoChangelevel::SaveEntities() is invoked + * @brief Called when a map has been finished, and is about to save the entities in the saferoom + * @remarks Called before the event "map_transition" + * @remarks Won't be called if Director::AreHumanZombiesAllowed() returns true, which refers to the versus gamemode, or this entity name is "info_solo_changelevel" + * + * @param info_changelevel The entity index of "info_changelevel" + * @param Kv A KeyValue pointer Address. Null_Address will be returned if the pointer is null + * + * @return Plugin_Handled to prevent saving entities, Plugin_Continue otherwise +*/ +// L4D1 only +forward Action L4D1_OnSavingEntities(int info_changelevel, Address Kv); + +/** + * @brief Called whenever InfoChangelevel::SaveEntities() is invoked + * @brief Called when a map has been finished, and is about to save the entities in the saferoom (usually props or items brought into the saferoom.) + * @remarks Called before the event "map_transition" + * @remarks Won't be called if CTerrorGameRules::HasPlayerControlledZombies() returns true, which refers to the versus/scavenge related pvp gamemode + * @remarks This forward will not trigger if the relative pre-hook forward has been blocked with Plugin_Handled + * + * @param info_changelevel The entity index of "info_changelevel" + * @param Kv A KeyValue pointer Address. Null_Address will be returned if the pointer is null + * + * @noreturn +*/ +// L4D1 only +forward void L4D1_OnSavingEntities_Post(int info_changelevel, Address Kv); + +/** + * @brief Called whenever InfoChangelevel::SaveEntities() is invoked + * @brief Called when a map has been finished, and is about to save the entities in the saferoom + * @remarks Called before the event "map_transition" + * @remarks Won't be called if CTerrorGameRules::HasPlayerControlledZombies() returns true, which refers to the versus/scavenge related pvp gamemode + * @remarks This forward will ONLY trigger if the relative pre-hook forward has been blocked with Plugin_Handled + * + * @param info_changelevel The entity index of "info_changelevel" + * @param Kv A KeyValue pointer Address. Null_Address will be returned if the pointer is null + * + * @noreturn +*/ +// L4D1 only +forward void L4D1_OnSavingEntities_PostHandled(int info_changelevel, Address Kv); + +/** + * @brief Called whenever InfoChangelevel::SaveEntities() is invoked + * @brief Called when a map has been finished, and is about to save the entities in the saferoom (usually props or items brought into the saferoom.) + * @remarks Called before the event "map_transition" + * @remarks Won't be called if CTerrorGameRules::HasPlayerControlledZombies() returns true, which refers to the versus/scavenge related pvp gamemode + * + * @param info_changelevel The entity index of "info_changelevel" + * + * @return Plugin_Handled to prevent saving entities, Plugin_Continue otherwise +*/ +// L4D2 only +forward Action L4D2_OnSavingEntities(int info_changelevel); + +/** + * @brief Called whenever InfoChangelevel::SaveEntities() is invoked + * @brief Called when a map has been finished, and the game has finished saving the entities in the saferoom + * @remarks Called before the event "map_transition" + * @remarks Won't be called if CTerrorGameRules::HasPlayerControlledZombies() returns true, which refers to the versus/scavenge related pvp gamemode + * @remarks This forward will not trigger if the relative pre-hook forward has been blocked with Plugin_Handled + * + * @param info_changelevel The entity index of "info_changelevel" + * + * @noreturn +*/ +// L4D2 only +forward void L4D2_OnSavingEntities_Post(int info_changelevel); + +/** + * @brief Called whenever InfoChangelevel::SaveEntities() is invoked + * @brief Called when a map has been finished, and the game has finished saving the entities in the saferoom + * @remarks Called before the event "map_transition" + * @remarks Won't be called if CTerrorGameRules::HasPlayerControlledZombies() returns true, which refers to the versus/scavenge related pvp gamemode + * @remarks This forward will ONLY trigger if the relative pre-hook forward has been blocked with Plugin_Handled + * + * @param info_changelevel The entity index of "info_changelevel" + * + * @noreturn +*/ +// L4D2 only +forward void L4D2_OnSavingEntities_PostHandled(int info_changelevel); + /** * @brief Called when the client's material system is expecting instructions from the server in regards to addons * @remarks Doesn't fire if l4d2_addons_eclipse is -1 or 0 @@ -4601,6 +4735,18 @@ native void L4D_FindRandomSpot(int NavArea, float vecPos[3]); */ native bool L4D2_IsVisibleToPlayer(int client, int team, int team_target, int NavArea, float vecPos[3]); +/** + * @brief Given a victim client index, returns the client index of the Special Infected that is dominating the victim + * @remarks Returns -1 if victim index is invalid, or not a survivor, or not being dominated by a Special Infected + * @remarks You can see this native as the SDKCall version of L4D2_GetInfectedAttacker() + * + * @param victim The client index of the victim to check + * + * @return The client index of the Special Infected that is dominating the victim + */ +// L4D2 Only +native int L4D2_GetSpecialInfectedDominatingMe(int victim) + /** * @brief Teleports a player to a valid position if they are stuck * @@ -7369,4 +7515,16 @@ native int L4D_RegisterForbiddenTarget(int entity); * * @return Some memory address (large value) or possibly ID if already registered (low value from 1+) */ -native void L4D_UnRegisterForbiddenTarget(int entity); \ No newline at end of file +native void L4D_UnRegisterForbiddenTarget(int entity); + +/** + * @brief To see if an entity is saveable to be transitioned to next map + * @remarks Calls InfoChangelevel::IsSaveableEntity. Entities that are saveable follow the rules below: + * @remarks 1. Entity is not a player, and its root hierarchical parent entity is not a player either + * @remarks 2. Entity has a capability flag "FCAP_ACROSS_TRANSITION", or the entity has no flag "EFL_DORMANT" + * + * @param entity Entity to check, usaully a prop, should not be a brush, etc + * + * @return True if entity is saveable, false otherwise + */ +native void L4D_IsEntitySaveable(int entity); \ No newline at end of file diff --git a/SourceCode/scripting-az/include/left4dhooks_lux_library.inc b/SourceCode/scripting-az/include/left4dhooks_lux_library.inc index 6e83841a..cf49d7bc 100644 --- a/SourceCode/scripting-az/include/left4dhooks_lux_library.inc +++ b/SourceCode/scripting-az/include/left4dhooks_lux_library.inc @@ -554,6 +554,7 @@ stock void TE_SetupPhysicsProp(float vecModelOrigin[3], TE_WriteNum("r", RGB[0]); TE_WriteNum("g", RGB[1]); TE_WriteNum("b", RGB[2]); + if( iSkin ) iSkin += 1; // Fix "symbol is never used" in SM 1.12 } /** diff --git a/SourceCode/scripting-az/include/left4dhooks_silver.inc b/SourceCode/scripting-az/include/left4dhooks_silver.inc index 20381287..73cd0e9d 100644 --- a/SourceCode/scripting-az/include/left4dhooks_silver.inc +++ b/SourceCode/scripting-az/include/left4dhooks_silver.inc @@ -54,7 +54,7 @@ enum L4D_WEAPON_SLOT_GRENADE = 2, L4D_WEAPON_SLOT_MEDKIT = 3, // L4D2: Also upgrade ammo packs and defibrillator L4D_WEAPON_SLOT_PILLS = 4, // L4D2: Also Adrenaline - L4D_WEAPON_SLOT_CARRIED = 5 // Physics props such as GasCan etc. + L4D_WEAPON_SLOT_CARRIED = 5 // Physics props such as GasCan etc } enum @@ -240,7 +240,7 @@ stock int L4D_GetDoorFlag(int entity) // ================================================== /** - * @brief Returns a players current weapon, or -1 if none. + * @brief Returns a players current weapon, or -1 if none * * @param client Client ID of the player to check * @@ -386,7 +386,7 @@ stock bool L4D_IsTankProp(int entity) /** * @brief Creates a panic event mob horde * @remarks Subject to horde cooldown timer - * @remarks Can probably reset the timer with either "L4D_ResetMobTimer();" native or using "L4D2CT_MobSpawnTimer" with the timer natives. + * @remarks Can probably reset the timer with either "L4D_ResetMobTimer();" native or using "L4D2CT_MobSpawnTimer" with the timer natives * * @noreturn */ @@ -509,7 +509,7 @@ stock int L4D_GetVictimSmoker(int client) * * @return Victim client index, or 0 if none */ -// L4D2 only. +// L4D2 only stock int L4D_GetVictimCharger(int client) { int attacker; @@ -530,7 +530,7 @@ stock int L4D_GetVictimCharger(int client) * * @return Victim client index, or 0 if none */ -// L4D2 only. +// L4D2 only stock int L4D_GetVictimCarry(int client) { int attacker; @@ -551,7 +551,7 @@ stock int L4D_GetVictimCarry(int client) * * @return Victim client index, or 0 if none */ -// L4D2 only. +// L4D2 only stock int L4D_GetVictimJockey(int client) { int attacker; @@ -612,7 +612,7 @@ stock int L4D_GetAttackerSmoker(int client) * * @return Attacker client index, or 0 if none */ -// L4D2 only. +// L4D2 only stock int L4D_GetAttackerCharger(int client) { int attacker; @@ -633,7 +633,7 @@ stock int L4D_GetAttackerCharger(int client) * * @return Attacker client index, or 0 if none */ -// L4D2 only. +// L4D2 only stock int L4D_GetAttackerCarry(int client) { int attacker; @@ -654,7 +654,7 @@ stock int L4D_GetAttackerCarry(int client) * * @return Attacker client index, or 0 if none */ -// L4D2 only. +// L4D2 only stock int L4D_GetAttackerJockey(int client) { int attacker; @@ -754,7 +754,7 @@ stock int L4D_GetPinnedSurvivor(int client) * * @return Returns true when someone is being carried/pummelled by more than 1 Charger */ -// L4D2 only. +// L4D2 only stock bool L4D2_IsMultiCharged(int victim) { if( !L4D_IsEngineLeft4Dead2() ) @@ -815,7 +815,7 @@ stock bool L4D_HasReachedSmoker(int client) #define QueuedPummel_Attacker 8 /** - * @brief Internally used to get offset to the start of queued pummel field. + * @brief Internally used to get offset to the start of queued pummel field * * @return Offset into CTerrorPlayer to the start of queued pummel props */ @@ -829,7 +829,7 @@ static stock int L4D2_OffsQueuedPummelInfo() } /** - * @brief Returns the timestamp when the queued pummel begins. + * @brief Returns the timestamp when the queued pummel begins * * @param client Client ID of the charger to check * @@ -841,7 +841,7 @@ stock float L4D2_GetQueuedPummelStartTime(int charger) } /** - * @brief Sets the timestamp when the queued pummel begins. + * @brief Sets the timestamp when the queued pummel begins * * @param client Client ID of the charger to check * @param timestamp Timestamp to set @@ -854,7 +854,7 @@ stock void L4D2_SetQueuedPummelStartTime(int charger, float timestamp) } /** - * @brief Returns if a Charger is in a queued pummel. + * @brief Returns if a Charger is in a queued pummel * * @param charger Client ID of the charger to check * @@ -868,7 +868,7 @@ stock bool L4D2_IsInQueuedPummel(int charger) } /** - * @brief Returns the victim of a Charger in a queued pummel. + * @brief Returns the victim of a Charger in a queued pummel * * @param client Client ID of the player to check * @@ -880,7 +880,7 @@ stock int L4D2_GetQueuedPummelVictim(int client) } /** - * @brief Sets the victim of a Charger in a queued pummel. + * @brief Sets the victim of a Charger in a queued pummel * * @param client Client ID of the player to set * @param target Client ID of the target to set @@ -893,7 +893,7 @@ stock void L4D2_SetQueuedPummelVictim(int client, int target) } /** - * @brief Returns the attacker of a Survivor in a queued pummel. + * @brief Returns the attacker of a Survivor in a queued pummel * * @param client Client ID of the player to check * @@ -905,7 +905,7 @@ stock int L4D2_GetQueuedPummelAttacker(int client) } /** - * @brief Sets the attacker of a Survivor in a queued pummel. + * @brief Sets the attacker of a Survivor in a queued pummel * * @param client Client ID of the player to set * @param target Client ID of the target to set @@ -992,7 +992,7 @@ stock void L4D_LedgeHangDisable(int client) * * @return Returns true if player is staggering, false otherwise */ -// Updated more accurate version thanks to "HarryPotter" for providing. +// Updated more accurate version thanks to "HarryPotter" for providing stock bool L4D_IsPlayerStaggering(int client) { static int Activity = -1; @@ -1184,7 +1184,7 @@ stock void L4D_StopReviveAction(int client) if( L4D_IsEngineLeft4Dead2() ) { - owner = GetEntPropEnt(client, Prop_Send, "m_useActionOwner"); // used when healing e.t.c. + owner = GetEntPropEnt(client, Prop_Send, "m_useActionOwner"); // used when healing etc target = GetEntPropEnt(client, Prop_Send, "m_useActionTarget"); SetEntPropEnt(client, Prop_Send, "m_useActionOwner", -1); SetEntPropEnt(client, Prop_Send, "m_useActionTarget", -1); diff --git a/SourceCode/scripting-az/include/left4dhooks_stocks.inc b/SourceCode/scripting-az/include/left4dhooks_stocks.inc index 96afb904..c97fc869 100644 --- a/SourceCode/scripting-az/include/left4dhooks_stocks.inc +++ b/SourceCode/scripting-az/include/left4dhooks_stocks.inc @@ -161,7 +161,7 @@ enum L4DResourceType L4DResource_TankTickets2 } -stock static const char L4D1ZombieClassname[6][] = +stock const char L4D1ZombieClassname[6][32] = { "smoker", "boomer", @@ -171,7 +171,7 @@ stock static const char L4D1ZombieClassname[6][] = "error_bad_L4D1ZombieClassType" }; -stock static const char L4D2ZombieClassname[9][] = +stock const char L4D2ZombieClassname[9][32] = { "smoker", "boomer", @@ -274,6 +274,32 @@ stock void L4D2_SetPlayerZombieClass(int client, L4D2ZombieClassType class) SetEntProp(client, Prop_Send, "m_zombieClass", class); } +/** + * Returns zombie player L4D1 zombie classname from the L4D1ZombieClassType value + * + * @param type L4D1ZombieClassType + * @return Classname string + * @error Invalid type index + */ +// L4D1 only +stock char[] L4D1_GetZombieClassname(L4D1ZombieClassType type) +{ + return L4D1ZombieClassname[type]; +} + +/** + * Returns zombie player L4D2 zombie classname from the L4D2ZombieClassType value + * + * @param type L4D1ZombieClassType + * @return Classname string + * @error Invalid type index + */ +// L4D2 only +stock char[] L4D2_GetZombieClassname(L4D2ZombieClassType type) +{ + return L4D2ZombieClassname[type]; +} + /** * Returns ghost state of zombie player * @@ -1155,6 +1181,8 @@ stock void L4D2_SetWeaponUpgrades(int weapon, int upgrades) * Note: Infected attacker means the infected player that is currently * pinning down the survivor. Such as hunter, smoker, charger and jockey * + * You can use the native L4D2_GetSpecialInfectedDominatingMe() which is likely faster, instead of this stock + * * @param client Survivor client index * @return Infected attacker index, -1 if not found * @error Invalid client index diff --git a/SourceCode/scripting-az/l4d_fix_nextbot_collision.sp b/SourceCode/scripting-az/l4d_fix_nextbot_collision.sp index 64fd08c0..2c221a9f 100644 --- a/SourceCode/scripting-az/l4d_fix_nextbot_collision.sp +++ b/SourceCode/scripting-az/l4d_fix_nextbot_collision.sp @@ -67,7 +67,7 @@ public void OnPluginStart() delete gd; CreateConVarHook("l4d_nextbot_collision_resolve_scale", - "0.05", + "0.05", //30tick = 0.65, 60tick = 0.15, 100tick = 0.05 "How much to scale the move vector as a result of resolving zombie collision.", FCVAR_CHEAT, true, 0.0, false, 0.0, diff --git a/SourceCode/scripting-az/l4d_unreservelobby.sp b/SourceCode/scripting-az/l4d_unreservelobby.sp new file mode 100644 index 00000000..6256f12f --- /dev/null +++ b/SourceCode/scripting-az/l4d_unreservelobby.sp @@ -0,0 +1,283 @@ +#pragma newdecls required + +#include +#include +#include + +#define PLUGIN_VERSION "1.1h-2024/10/26" +#define PLUGIN_NAME "l4d_unreservelobby" +#define DEBUG 0 + +public Plugin myinfo = +{ + name = "L4D1/2 Remove Lobby Reservation", + author = "Downtown1, Harry", + description = "Removes lobby reservation when server is full or empty", + version = PLUGIN_VERSION, + url = "https://forums.alliedmods.net/showthread.php?t=94415" +} + +public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) +{ + EngineVersion test = GetEngineVersion(); + + if( test != Engine_Left4Dead && test != Engine_Left4Dead2 ) + { + strcopy(error, err_max, "Plugin only supports Left 4 Dead 1 & 2."); + return APLRes_SilentFailure; + } + + if( !IsDedicatedServer() ) + { + strcopy(error, err_max, "Get a dedicated server. This plugin does not work on Listen servers."); + return APLRes_SilentFailure; + } + + return APLRes_Success; +} + +#define CVAR_FLAGS FCVAR_NOTIFY +#define CVAR_FLAGS_PLUGIN_VERSION FCVAR_NOTIFY|FCVAR_DONTRECORD|FCVAR_SPONLY + +#define L4D_MAXHUMANS_LOBBY_VERSUS 8 +#define L4D_MAXHUMANS_LOBBY_OTHER 4 + +ConVar sv_allow_lobby_connect_only; +int sv_allow_lobby_connect_only_default; + +ConVar g_hCvarUnreserveFull, g_hCvarUnreserveEmpty, g_hCvarUnreserveTrigger; +bool g_bCvarUnreserveFull, g_bCvarUnreserveEmpty; +int g_iCvarUnreserveTrigger; + +bool + g_bFirstMap, + g_bFirstLoadedConfigs, + g_bIsServerUnreserved; + +Handle + COLD_DOWN_Timer; + +public void OnPluginStart() +{ + sv_allow_lobby_connect_only = FindConVar("sv_allow_lobby_connect_only") + sv_allow_lobby_connect_only.AddChangeHook(ConVarChanged_sv_allow_lobby_connect_only); + + g_hCvarUnreserveFull = CreateConVar( PLUGIN_NAME ... "_full", "1", "Automatically unreserve server after server lobby reserved and full in gamemode (8 in versus/scavenge, 4 in coop/survival/realism)", CVAR_FLAGS, true, 0.0, true, 1.0); + g_hCvarUnreserveEmpty = CreateConVar( PLUGIN_NAME ... "_empty", "1", "Automatically unreserve server after all playes have disconnected", CVAR_FLAGS, true, 0.0, true, 1.0); + g_hCvarUnreserveTrigger = CreateConVar( PLUGIN_NAME ... "_trigger", "0", "When player number reaches the following number, the server unreserves.\n0 = 8 in versus/scavenge, 4 in coop/survival/realism.\n>0 = Any number greater than zero.", CVAR_FLAGS, true, 0.0, true, 8.0); + CreateConVar( PLUGIN_NAME ... "_version", PLUGIN_VERSION, PLUGIN_NAME ... " Plugin Version", CVAR_FLAGS_PLUGIN_VERSION); + AutoExecConfig(true, PLUGIN_NAME); + + GetCvars(); + g_hCvarUnreserveFull.AddChangeHook(ConVarChanged_Cvars); + g_hCvarUnreserveEmpty.AddChangeHook(ConVarChanged_Cvars); + g_hCvarUnreserveTrigger.AddChangeHook(ConVarChanged_Cvars); + + HookEvent("player_disconnect", Event_PlayerDisconnect); + + RegAdminCmd("sm_unreserve", Command_Unreserve, ADMFLAG_ROOT, "sm_unreserve - manually force removes the lobby reservation"); + + g_bFirstMap = true; + g_bFirstLoadedConfigs = true; + +} + +// Cvars------------------------------- + +void ConVarChanged_sv_allow_lobby_connect_only(ConVar hCvar, const char[] sOldVal, const char[] sNewVal) +{ + if(g_bIsServerUnreserved) + { + if(!L4D_LobbyIsReserved()) + { + //大廳狀態: unreserved, 須將sv_allow_lobby_connect_only設置為0 + SetAllowLobby(0); + } + else + { + g_bIsServerUnreserved = false; + } + } +} + +void ConVarChanged_Cvars(ConVar hCvar, const char[] sOldVal, const char[] sNewVal) +{ + GetCvars(); +} + +void GetCvars() +{ + g_bCvarUnreserveFull = g_hCvarUnreserveFull.BoolValue; + g_bCvarUnreserveEmpty = g_hCvarUnreserveEmpty.BoolValue; + g_iCvarUnreserveTrigger = g_hCvarUnreserveTrigger.IntValue; +} + +// Sourcemod API Forward------------------------------- + +public void OnMapEnd() +{ + delete COLD_DOWN_Timer; +} + +public void OnConfigsExecuted() +{ + if(g_bFirstLoadedConfigs) + { + sv_allow_lobby_connect_only_default = sv_allow_lobby_connect_only.IntValue; + g_bFirstLoadedConfigs = false; + } + + if(!g_bFirstMap) + { + delete COLD_DOWN_Timer; + COLD_DOWN_Timer = CreateTimer(10.0, Timer_COLD_DOWN); + } + + g_bFirstMap = false; +} + +public void OnClientConnected(int client) +{ + if(IsFakeClient(client)) return; + + if(g_bCvarUnreserveFull && L4D_LobbyIsReserved() && IsServerLobbyFull()) + { + //PrintToChatAll("[SM] Lobby reservation has been removed by l4dunreservelobby.smx(Full)"); + PrintToServer("[SM] Lobby reservation has been removed by l4dunreservelobby.smx(Full)"); + L4D_LobbyUnreserve(); + SetAllowLobby(0); + g_bIsServerUnreserved = true; + } +} + +// Event------------------------------- + +void Event_PlayerDisconnect(Event event, const char[] name, bool dontBroadcast) +{ + // event.GetBool("bot") always return false in l4d1/2 + if(event.GetBool("bot")) return; + + static char networkid[32]; + event.GetString("networkid", networkid, sizeof(networkid)); + // "networkid" is "BOT" is fake client + if(strcmp(networkid, "BOT", false) == 0) return; + + int userid = event.GetInt("userid"); + int client = GetClientOfUserId(userid); + if(userid > 0 && client == 0 && !CheckIfPlayerInServer(0)) //player leaves during map change + { + delete COLD_DOWN_Timer; + if(g_bCvarUnreserveEmpty && L4D_LobbyIsReserved()) + { + PrintToServer("[SM] Lobby reservation has been removed by l4dunreservelobby.smx(Empty)"); + L4D_LobbyUnreserve(); + } + g_bIsServerUnreserved = false; + SetAllowLobby(sv_allow_lobby_connect_only_default); + } + + if(client && !IsFakeClient(client) && !CheckIfPlayerInServer(client)) //檢查是否還有玩家以外的人還在伺服器 + { + delete COLD_DOWN_Timer; + if(g_bCvarUnreserveEmpty && L4D_LobbyIsReserved()) + { + PrintToServer("[SM] Lobby reservation has been removed by l4dunreservelobby.smx(Empty)"); + L4D_LobbyUnreserve(); + } + g_bIsServerUnreserved = false; + SetAllowLobby(sv_allow_lobby_connect_only_default); + } +} + +// Command------------------------------- + +Action Command_Unreserve(int client, int args) +{ + if(!L4D_LobbyIsReserved()) + { + ReplyToCommand(client, "[SM] Server is already unreserved."); + } + + PrintToChatAll("[SM] Lobby reservation has been removed by l4dunreservelobby.smx(sm_unreserve)"); + PrintToServer("[SM] Lobby reservation has been removed by l4dunreservelobby.smx(sm_unreserve)"); + L4D_LobbyUnreserve(); + SetAllowLobby(0); + g_bIsServerUnreserved = true; + + return Plugin_Handled; +} + +// Timer------------------------------- + +Action Timer_COLD_DOWN(Handle timer, any client) +{ + COLD_DOWN_Timer = null; + + if(CheckIfPlayerInServer(0)) //有玩家在伺服器中 + { + return Plugin_Continue; + } + + if(g_bCvarUnreserveEmpty && L4D_LobbyIsReserved()) + { + PrintToServer("[SM] Lobby reservation has been removed by l4dunreservelobby.smx(Empty)"); + L4D_LobbyUnreserve(); + } + g_bIsServerUnreserved = false; + SetAllowLobby(sv_allow_lobby_connect_only_default); + + return Plugin_Continue; +} + +// Others------------------------------- + +void SetAllowLobby(int value) +{ + sv_allow_lobby_connect_only.IntValue = value; +} + +int IsServerLobbyFull() +{ + int humans = GetHumanCount(); + if(g_iCvarUnreserveTrigger > 0) + { + return humans >= g_iCvarUnreserveTrigger; + } + + if(L4D_HasPlayerControlledZombies()) + { + return humans >= L4D_MAXHUMANS_LOBBY_VERSUS; + } + + return humans >= L4D_MAXHUMANS_LOBBY_OTHER; +} + +bool IsClientConnectHuman(int client) +{ + return IsClientConnected(client) && !IsFakeClient(client); +} + +int GetHumanCount() +{ + int humans = 0; + + int i; + for(i = 1; i <= MaxClients; i++) + { + if(IsClientConnectHuman(i)) + { + humans++ + } + } + + return humans; +} + +bool CheckIfPlayerInServer(int client) +{ + for (int i = 1; i <= MaxClients; i++) + if(IsClientConnected(i) && !IsFakeClient(i) && i!=client) + return true; + + return false; +} \ No newline at end of file diff --git a/SourceCode/scripting-az/l4dd/l4dd_forwards.sp b/SourceCode/scripting-az/l4dd/l4dd_forwards.sp index 0c0205a8..77a1fd74 100644 --- a/SourceCode/scripting-az/l4dd/l4dd_forwards.sp +++ b/SourceCode/scripting-az/l4dd/l4dd_forwards.sp @@ -120,6 +120,7 @@ GlobalForward g_hFWD_StartMeleeSwing_Post; GlobalForward g_hFWD_StartMeleeSwing_PostHandled; GlobalForward g_hFWD_GetDamageForVictim; GlobalForward g_hFWD_CDirectorScriptedEventManager_SendInRescueVehicle; +GlobalForward g_hFWD_CDirector_CreateRescuableSurvivors; GlobalForward g_hFWD_CDirectorScriptedEventManager_ChangeFinaleStage; GlobalForward g_hFWD_CDirectorScriptedEventManager_ChangeFinaleStage_Post; GlobalForward g_hFWD_CDirectorScriptedEventManager_ChangeFinaleStage_PostPost; @@ -172,6 +173,9 @@ GlobalForward g_hFWD_CGasCan_OnActionComplete; GlobalForward g_hFWD_CGasCan_OnActionComplete_Post; GlobalForward g_hFWD_CGasCan_OnActionComplete_PostHandled; GlobalForward g_hFWD_CServerGameDLL_ServerHibernationUpdate; +GlobalForward g_hFWD_InfoChangelevel_SaveEntities; +GlobalForward g_hFWD_InfoChangelevel_SaveEntities_Post; +GlobalForward g_hFWD_InfoChangelevel_SaveEntities_PostHandled; GlobalForward g_hFWD_CTerrorPlayer_OnPouncedOnSurvivor; GlobalForward g_hFWD_CTerrorPlayer_OnPouncedOnSurvivor_Post; GlobalForward g_hFWD_CTerrorPlayer_OnPouncedOnSurvivor_PostHandled; @@ -185,6 +189,7 @@ GlobalForward g_hFWD_CTerrorPlayer_OnStartCarryingVictim; GlobalForward g_hFWD_CTerrorPlayer_OnStartCarryingVictim_Post; GlobalForward g_hFWD_CTerrorPlayer_OnStartCarryingVictim_PostHandled; GlobalForward g_hFWD_CCharge_ImpactStagger; +GlobalForward g_hFWD_CTerrorPlayer_OnDominatedBySpecialInfected; GlobalForward g_hFWD_CInsectSwarm_CanHarm; GlobalForward g_hFWD_CInsectSwarm_CanHarm_Post; GlobalForward g_hFWD_CInsectSwarm_CanHarm_PostHandled; @@ -381,6 +386,7 @@ void SetupDetours(GameData hGameData = null) CreateDetour(hGameData, DTR_CDirectorScriptedEventManager_SendInRescueVehicle, INVALID_FUNCTION, "L4DD::CDirectorScriptedEventManager::SendInRescueVehicle", "L4D2_OnSendInRescueVehicle"); } + CreateDetour(hGameData, DTR_CDirector_CreateRescuableSurvivors, DTR_CDirector_CreateRescuableSurvivors_Post, "L4DD::CDirector::CreateRescuableSurvivors", "L4D_OnCreateRescuableSurvivors"); CreateDetour(hGameData, DTR_CDirector_TryOfferingTankBot, DTR_CDirector_TryOfferingTankBot_Post, "L4DD::CDirector::TryOfferingTankBot", "L4D_OnTryOfferingTankBot"); CreateDetour(hGameData, DTR_CDirector_TryOfferingTankBot, DTR_CDirector_TryOfferingTankBot_Post, "L4DD::CDirector::TryOfferingTankBot", "L4D_OnTryOfferingTankBot_Post", true); CreateDetour(hGameData, DTR_CDirector_TryOfferingTankBot, DTR_CDirector_TryOfferingTankBot_Post, "L4DD::CDirector::TryOfferingTankBot", "L4D_OnTryOfferingTankBot_PostHandled", true); @@ -470,6 +476,19 @@ void SetupDetours(GameData hGameData = null) CreateDetour(hGameData, DTR_CTerrorPlayer_CancelStagger, DTR_CTerrorPlayer_CancelStagger_Post, "L4DD::CTerrorPlayer::CancelStagger", "L4D_OnCancelStagger_Post", true); CreateDetour(hGameData, DTR_CTerrorPlayer_CancelStagger, DTR_CTerrorPlayer_CancelStagger_Post, "L4DD::CTerrorPlayer::CancelStagger", "L4D_OnCancelStagger_PostHandled", true); + if( !g_bLeft4Dead2 ) + { + CreateDetour(hGameData, DTR_InfoChangelevel_SaveEntities_L4D1, DTR_InfoChangelevel_SaveEntities_Post_L4D1, "L4DD::InfoChangelevel::SaveEntities", "L4D1_OnSavingEntities"); + CreateDetour(hGameData, DTR_InfoChangelevel_SaveEntities_L4D1, DTR_InfoChangelevel_SaveEntities_Post_L4D1, "L4DD::InfoChangelevel::SaveEntities", "L4D1_OnSavingEntities_Post", true); + CreateDetour(hGameData, DTR_InfoChangelevel_SaveEntities_L4D1, DTR_InfoChangelevel_SaveEntities_Post_L4D1, "L4DD::InfoChangelevel::SaveEntities", "L4D1_OnSavingEntities_PostHandled", true); + } + else + { + CreateDetour(hGameData, DTR_InfoChangelevel_SaveEntities_L4D2, DTR_InfoChangelevel_SaveEntities_Post_L4D2, "L4DD::InfoChangelevel::SaveEntities", "L4D2_OnSavingEntities"); + CreateDetour(hGameData, DTR_InfoChangelevel_SaveEntities_L4D2, DTR_InfoChangelevel_SaveEntities_Post_L4D2, "L4DD::InfoChangelevel::SaveEntities", "L4D2_OnSavingEntities_Post", true); + CreateDetour(hGameData, DTR_InfoChangelevel_SaveEntities_L4D2, DTR_InfoChangelevel_SaveEntities_Post_L4D2, "L4DD::InfoChangelevel::SaveEntities", "L4D2_OnSavingEntities_PostHandled", true); + } + if( !g_bLeft4Dead2 ) { // Different detours, same forward (L4D_OnSpawnSpecial). @@ -511,6 +530,7 @@ void SetupDetours(GameData hGameData = null) CreateDetour(hGameData, DTR_CTerrorPlayer_OnStartCarryingVictim, DTR_CTerrorPlayer_OnStartCarryingVictim_Post, "L4DD::CTerrorPlayer::OnStartCarryingVictim", "L4D2_OnStartCarryingVictim_Post", true); CreateDetour(hGameData, DTR_CTerrorPlayer_OnStartCarryingVictim, DTR_CTerrorPlayer_OnStartCarryingVictim_Post, "L4DD::CTerrorPlayer::OnStartCarryingVictim", "L4D2_OnStartCarryingVictim_PostHandled", true); CreateDetour(hGameData, DTR_CCharge_ImpactStagger, INVALID_FUNCTION, "L4DD::CCharge::ImpactStagger", "L4D2_OnChargerImpact"); + CreateDetour(hGameData, INVALID_FUNCTION, DTR_CTerrorPlayer_IsDominatedBySpecialInfected, "L4DD::CTerrorPlayer::IsDominatedBySpecialInfected", "L4D2_OnDominatedBySpecialInfected"); CreateDetour(hGameData, DTR_CGasCanEvent_Killed, DTR_CGasCanEvent_Killed_Post, "L4DD::CGasCan::Event_Killed", "L4D2_CGasCan_EventKilled"); CreateDetour(hGameData, DTR_CGasCanEvent_Killed, DTR_CGasCanEvent_Killed_Post, "L4DD::CGasCan::Event_Killed", "L4D2_CGasCan_EventKilled_Post", true); CreateDetour(hGameData, DTR_CGasCanEvent_Killed, DTR_CGasCanEvent_Killed_Post, "L4DD::CGasCan::Event_Killed", "L4D2_CGasCan_EventKilled_PostHandled", true); @@ -2519,6 +2539,7 @@ MRESReturn DTR_CDirectorScriptedEventManager_SendInRescueVehicle(DHookReturn hRe // MRESReturn DTR_CDirectorScriptedEventManager_SendInRescueVehicle(DHookParam hParams) { //PrintToServer("##### DTR_CDirectorScriptedEventManager_SendInRescueVehicle"); + Action aResult = Plugin_Continue; Call_StartForward(g_hFWD_CDirectorScriptedEventManager_SendInRescueVehicle); Call_Finish(aResult); @@ -2534,6 +2555,57 @@ MRESReturn DTR_CDirectorScriptedEventManager_SendInRescueVehicle(DHookReturn hRe return MRES_Ignored; } +int g_iRescuePlayers[MAXPLAYERS+1]; +MRESReturn DTR_CDirector_CreateRescuableSurvivors(DHookReturn hReturn) // Forward "L4D_OnCreateRescuableSurvivors" +{ + //PrintToServer("##### DTR_CDirector_CreateRescuableSurvivors"); + bool isDead; + + for( int i = 1; i <= MaxClients; i++ ) + { + g_iRescuePlayers[i] = 0; + + if( !isDead && IsClientInGame(i) && GetClientTeam(i) == 2 && !IsPlayerAlive(i) ) + { + isDead = true; + } + } + + if( !isDead ) return MRES_Ignored; + + Action aResult = Plugin_Continue; + Call_StartForward(g_hFWD_CDirector_CreateRescuableSurvivors); + Call_PushArrayEx(g_iRescuePlayers, sizeof(g_iRescuePlayers), SM_PARAM_COPYBACK); + Call_Finish(aResult); + + if( aResult == Plugin_Changed ) + { + for( int i = 1; i <= MaxClients; i++ ) + { + if( g_iRescuePlayers[i] == 1 && IsClientInGame(i) && !IsPlayerAlive(i) && GetClientTeam(i) == 2 ) // Ignore those not on team 2, the game already cannot respawn them + { + SetEntProp(i, Prop_Send, "m_iTeamNum", 4); + } + } + } + + return MRES_Ignored; +} + +MRESReturn DTR_CDirector_CreateRescuableSurvivors_Post(DHookReturn hReturn) // Forward "L4D_OnCreateRescuableSurvivors" +{ + // return MRES_Ignored; + for( int i = 1; i <= MaxClients; i++ ) + { + if( g_iRescuePlayers[i] == 1 && IsClientInGame(i) ) + { + SetEntProp(i, Prop_Send, "m_iTeamNum", 2); + } + } + + return MRES_Ignored; +} + bool g_bBlock_CDirectorScriptedEventManager_ChangeFinaleStage; MRESReturn DTR_CDirectorScriptedEventManager_ChangeFinaleStage(DHookReturn hReturn, DHookParam hParams) // Forward "L4D2_OnChangeFinaleStage" { @@ -3807,6 +3879,8 @@ MRESReturn DTR_CMolotovProjectile_Create_Post(DHookReturn hReturn, DHookParam hP bool g_bBlock_CPipeBombProjectile_Create; MRESReturn DTR_CPipeBombProjectile_Create_Pre(DHookReturn hReturn, DHookParam hParams) // Forward "L4D_PipeBombProjectile_Pre" { + if( g_bBreakable ) return MRES_Ignored; + //PrintToServer("##### DTR_CPipeBombProjectile_Create_Pre"); g_bBlock_CPipeBombProjectile_Create = false; @@ -3855,6 +3929,8 @@ MRESReturn DTR_CPipeBombProjectile_Create_Pre(DHookReturn hReturn, DHookParam hP MRESReturn DTR_CPipeBombProjectile_Create_Post(DHookReturn hReturn, DHookParam hParams) // Forward "L4D_PipeBombProjectile_Post" and "L4D_PipeBombProjectile_PostHandled" { + if( g_bBreakable ) return MRES_Ignored; + //PrintToServer("##### DTR_CPipeBombProjectile_Create_Post"); int client; if( !hParams.IsNull(5) ) @@ -4093,6 +4169,8 @@ MRESReturn DTR_CMolotovProjectile_Detonate(int pThis, DHookReturn hReturn, DHook bool g_bBlock_CPipeBombProjectile_Detonate; MRESReturn DTR_CPipeBombProjectile_Detonate_Pre(int pThis, DHookReturn hReturn, DHookParam hParams) // Forward "L4D_PipeBomb_Detonate" { + if( g_bBreakable ) return MRES_Ignored; + //PrintToServer("##### DTR_CPipeBombProjectile_Detonate_Pre"); g_bBlock_CPipeBombProjectile_Detonate = false; @@ -4117,6 +4195,8 @@ MRESReturn DTR_CPipeBombProjectile_Detonate_Pre(int pThis, DHookReturn hReturn, MRESReturn DTR_CPipeBombProjectile_Detonate(int pThis, DHookReturn hReturn, DHookParam hParams) // Forward "L4D_PipeBomb_Detonate_Post" and "L4D_PipeBomb_Detonate_PostHandled" { + if( g_bBreakable ) return MRES_Ignored; + //PrintToServer("##### DTR_CPipeBombProjectile_Detonate"); int client = GetEntPropEnt(pThis, Prop_Send, "m_hThrower"); @@ -4206,12 +4286,16 @@ MRESReturn DTR_CGrenadeLauncher_Projectile_Explode(int pThis, DHookReturn hRetur MRESReturn DTR_CBreakableProp_Break_Pre(int pThis, DHookReturn hReturn, DHookParam hParams) { + g_bBreakable = true; + //PrintToServer("##### DTR_CBreakableProp_Break_Pre"); return MRES_Ignored; } MRESReturn DTR_CBreakableProp_Break_Post(int pThis, DHookReturn hReturn, DHookParam hParams) // Forward "L4D_CBreakableProp_Break" { + g_bBreakable = false; + //PrintToServer("##### DTR_CBreakableProp_Break_Post"); int entity; if( !hParams.IsNull(1) ) @@ -4643,6 +4727,80 @@ MRESReturn DTR_CServerGameDLL_ServerHibernationUpdate(int pThis, DHookReturn hRe return MRES_Ignored; } +bool g_bBlock_InfoChangelevel_SaveEntities_L4D1; +MRESReturn DTR_InfoChangelevel_SaveEntities_L4D1(int pThis, DHookParam hParams) // Forward "L4D1_OnSavingEntities" +{ + //PrintToServer("##### DTR_InfoChangelevel_SaveEntities_L4D1"); + if( !IsValidEntity(pThis) ) return MRES_Ignored; + + Address pKv = view_as
(hParams.Get(1)); + + Action aResult = Plugin_Continue; + Call_StartForward(g_hFWD_InfoChangelevel_SaveEntities); + Call_PushCell(pThis); + Call_PushCell(pKv); + Call_Finish(aResult); + + if( aResult == Plugin_Handled ) + { + g_bBlock_InfoChangelevel_SaveEntities_L4D1 = true; + + return MRES_Supercede; + } + + return MRES_Ignored; +} + +MRESReturn DTR_InfoChangelevel_SaveEntities_Post_L4D1(int pThis, DHookParam hParams) // Forward "L4D1_OnSavingEntities_Post" and "L4D1_OnSavingEntities_PostHandled" +{ + //PrintToServer("##### DTR_InfoChangelevel_SaveEntities_Post_L4D1"); + if( !IsValidEntity(pThis) ) return MRES_Ignored; + + Address pKv = view_as
(hParams.Get(1)); + + Call_StartForward(g_bBlock_InfoChangelevel_SaveEntities_L4D1 ? g_hFWD_InfoChangelevel_SaveEntities_PostHandled : g_hFWD_InfoChangelevel_SaveEntities_Post); + Call_PushCell(pThis); + Call_PushCell(pKv); + Call_Finish(); + + return MRES_Ignored; +} + +bool g_bBlock_InfoChangelevel_SaveEntities_L4D2; +MRESReturn DTR_InfoChangelevel_SaveEntities_L4D2(int pThis) // Forward "L4D2_OnSavingEntities" +{ + //PrintToServer("##### DTR_InfoChangelevel_SaveEntities_L4D2"); + g_bBlock_InfoChangelevel_SaveEntities_L4D2 = false; + + if( !IsValidEntity(pThis) ) return MRES_Ignored; + + Action aResult = Plugin_Continue; + Call_StartForward(g_hFWD_InfoChangelevel_SaveEntities); + Call_PushCell(pThis); + Call_Finish(aResult); + + if( aResult == Plugin_Handled ) + { + g_bBlock_InfoChangelevel_SaveEntities_L4D2 = true; + + return MRES_Supercede; + } + + return MRES_Ignored; +} + +MRESReturn DTR_InfoChangelevel_SaveEntities_Post_L4D2(int pThis) // Forward "L4D2_OnSavingEntities_Post" and "L4D2_OnSavingEntities_PostHandled" +{ + //PrintToServer("##### DTR_InfoChangelevel_SaveEntities_Post_L4D2"); + if( !IsValidEntity(pThis) ) return MRES_Ignored; + + Call_StartForward(g_bBlock_InfoChangelevel_SaveEntities_L4D2 ? g_hFWD_InfoChangelevel_SaveEntities_PostHandled : g_hFWD_InfoChangelevel_SaveEntities_Post); + Call_PushCell(pThis); + Call_Finish(); + + return MRES_Ignored; +} + bool g_bBlock_CTerrorPlayer_OnPouncedOnSurvivor; MRESReturn DTR_CTerrorPlayer_OnPouncedOnSurvivor(int pThis, DHookReturn hReturn, DHookParam hParams) // Forward "L4D_OnPouncedOnSurvivor" { @@ -4825,6 +4983,30 @@ MRESReturn DTR_CCharge_ImpactStagger(int pThis, DHookReturn hReturn) // Forward return MRES_Ignored; } +MRESReturn DTR_CTerrorPlayer_IsDominatedBySpecialInfected(int pThis, DHookReturn hReturn) // Forward "L4D2_OnDominatedBySpecialInfected" +{ + //PrintToServer("##### DTR_CTerrorPlayer_IsDominatedBySpecialInfected"); + + // Is domination happening + if( hReturn.Value ) + { + // This function is called literally for everyone, including infected clients. (wtf?) + if( GetClientTeam(pThis) != 2 ) return MRES_Ignored; + + // Only alive survivors. in case of some weird bugs ? + if( !IsPlayerAlive(pThis) ) return MRES_Ignored; + + int attacker = SDKCall(g_hSDK_CTerrorPlayer_GetSpecialInfectedDominatingMe, pThis); + + Call_StartForward(g_hFWD_CTerrorPlayer_OnDominatedBySpecialInfected); + Call_PushCell(pThis); + Call_PushCell(attacker); + Call_Finish(); + } + + return MRES_Ignored; +} + bool g_bBlock_CInsectSwarm_CanHarm; MRESReturn DTR_CInsectSwarm_CanHarm(int pThis, DHookReturn hReturn, DHookParam hParams) // Forward "L4D2_CInsectSwarm_CanHarm" { diff --git a/SourceCode/scripting-az/l4dd/l4dd_gamedata.sp b/SourceCode/scripting-az/l4dd/l4dd_gamedata.sp index 0cf28b0f..e878f88b 100644 --- a/SourceCode/scripting-az/l4dd/l4dd_gamedata.sp +++ b/SourceCode/scripting-az/l4dd/l4dd_gamedata.sp @@ -313,6 +313,17 @@ void LoadGameData() if( g_bLeft4Dead2 ) { + StartPrepSDKCall(SDKCall_Player); + if( PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, "CTerrorPlayer::GetSpecialInfectedDominatingMe") == false ) + { + LogError("Failed to find signature: \"CTerrorPlayer::GetSpecialInfectedDominatingMe\" (%s)", g_sSystem); + } else { + PrepSDKCall_SetReturnInfo(SDKType_CBasePlayer, SDKPass_Pointer); + g_hSDK_CTerrorPlayer_GetSpecialInfectedDominatingMe = EndPrepSDKCall(); + if( g_hSDK_CTerrorPlayer_GetSpecialInfectedDominatingMe == null ) + LogError("Failed to create SDKCall: \"CTerrorPlayer::GetSpecialInfectedDominatingMe\" (%s)", g_sSystem); + } + StartPrepSDKCall(SDKCall_Static); if( !PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, "IsVisibleToPlayer") ) { @@ -1930,6 +1941,18 @@ void LoadGameData() LogError("Failed to create SDKCall: \"CDirector::UnregisterForbiddenTarget\" (%s)", g_sSystem); } + StartPrepSDKCall(SDKCall_Entity); + if( PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, "InfoChangelevel::IsEntitySaveable") == false ) + { + LogError("Failed to find signature: \"InfoChangelevel::IsEntitySaveable\" (%s)", g_sSystem); + } else { + PrepSDKCall_AddParameter(SDKType_CBaseEntity, SDKPass_Pointer); + PrepSDKCall_SetReturnInfo(SDKType_Bool, SDKPass_Plain); + g_hSDK_InfoChangeLevel_IsEntitySaveable = EndPrepSDKCall(); + if( g_hSDK_InfoChangeLevel_IsEntitySaveable == null ) + LogError("Failed to create SDKCall: \"InfoChangeLevel::IsEntitySaveable\" (%s)", g_sSystem); + } + StartPrepSDKCall(SDKCall_Raw); if( PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, "CDirectorVersusMode::EndVersusModeRound") == false ) { diff --git a/SourceCode/scripting-az/l4dd/l4dd_natives.sp b/SourceCode/scripting-az/l4dd/l4dd_natives.sp index c132a870..ff6e529a 100644 --- a/SourceCode/scripting-az/l4dd/l4dd_natives.sp +++ b/SourceCode/scripting-az/l4dd/l4dd_natives.sp @@ -80,6 +80,7 @@ Handle g_hSDK_CNavMesh_GetNearestNavArea; Handle g_hSDK_TerrorNavArea_FindRandomSpot; Handle g_hSDK_CTerrorPlayer_WarpToValidPositionIfStuck; Handle g_hSDK_IsVisibleToPlayer; +Handle g_hSDK_CTerrorPlayer_GetSpecialInfectedDominatingMe; Handle g_hSDK_CDirector_HasAnySurvivorLeftSafeArea; Handle g_hSDK_CBaseTrigger_IsTouching; // Handle g_hSDK_CDirector_IsAnySurvivorInExitCheckpoint; @@ -174,6 +175,7 @@ Handle g_hSDK_CDirectorScavengeMode_HideScoreboardNonVirtual; Handle g_hSDK_CDirector_HideScoreboard; Handle g_hSDK_CDirector_RegisterForbiddenTarget; Handle g_hSDK_CDirector_UnregisterForbiddenTarget; +Handle g_hSDK_InfoChangeLevel_IsEntitySaveable; @@ -1159,6 +1161,16 @@ int Native_CTerrorPlayer_WarpToValidPositionIfStuck(Handle plugin, int numParams return 0; } +int Native_CTerrorPlayer_GetSpecialInfectedDominatingMe(Handle plugin, int numParams) // Native "L4D2_GetSpecialInfectedDominatingMe" +{ + ValidateNatives(g_hSDK_CTerrorPlayer_GetSpecialInfectedDominatingMe, "CTerrorPlayer::GetSpecialInfectedDominatingMe"); + + int client = GetNativeCell(1); + + //PrintToServer("#### CALL g_hSDK_CTerrorPlayer_GetSpecialInfectedDominatingMe"); + return SDKCall(g_hSDK_CTerrorPlayer_GetSpecialInfectedDominatingMe, client); +} + int Native_IsVisibleToPlayer(Handle plugin, int numParams) // Native "L4D2_IsVisibleToPlayer" { ValidateNatives(g_hSDK_IsVisibleToPlayer, "IsVisibleToPlayer"); @@ -5640,6 +5652,49 @@ int Native_CDirector_UnregisterForbiddenTarget(Handle plugin, int numParams) // return 0; } +/* +- Should be something like this. +bool InfoChangeLevel::IsEntitySaveable(CBaseEntity* pEntity) +{ + int objCap = pEntity->ObjectCaps(); + if( objCap >= 0 ) + { + if( pEntity && !pEntity->IsPlayer() ) + { + CBaseEntity* pRootMoveParent = pEntity->GetRootMoveParent(); + if( pRootMoveParent && !pRootMoveParent->IsPlayer() + && ( ( (objCap & FCAP_ACROSS_TRANSITION ) != 0) || (pEntity->m_iClassname && !pEntity->IsDormant()) ) ) + { + return true; + } + } + } + return false; +} +*/ + +any Native_InfoChangelevel_IsEntitySaveable(Handle plugin, int numParams) // Native "L4D_IsEntitySaveable" +{ + ValidateNatives(g_hSDK_InfoChangeLevel_IsEntitySaveable, "InfoChangelevel::IsEntitySaveable"); + + int entity = GetNativeCell(1); + if( !entity || entity > GetMaxEntities() ) return 0; + + static int info_changelevel = INVALID_ENT_REFERENCE; + if( EntRefToEntIndex(info_changelevel) == INVALID_ENT_REFERENCE ) + { + info_changelevel = FindEntityByClassname(-1, "info_changelevel"); + if( info_changelevel == INVALID_ENT_REFERENCE ) + { + return 0; + } + + info_changelevel = EntIndexToEntRef(info_changelevel); + } + + //PrintToServer("#### CALL g_hSDK_InfoChangeLevel_IsEntitySaveable"); + return view_as(SDKCall(g_hSDK_InfoChangeLevel_IsEntitySaveable, info_changelevel, entity)); +} @@ -6219,7 +6274,7 @@ any Native_AmmoDef_GetAmmoOfIndex(Handle plugin, int numParams) { int nAmmoIndex = GetNativeCell(1); - if ( nAmmoIndex >= AmmoDef_m_nAmmoIndex() ) + if( nAmmoIndex >= AmmoDef_m_nAmmoIndex() ) return view_as(Address_Null); return AmmoDef_m_AmmoType(nAmmoIndex); @@ -6235,7 +6290,7 @@ any Native_AmmoDef_Index(Handle plugin, int numParams) { AmmoDef_m_AmmoType(i).GetName(name, sizeof(name)); - if (strcmp(name, psz, false) == 0) + if( strcmp(name, psz, false) == 0) return i; } return -1; @@ -6245,12 +6300,12 @@ any Native_AmmoDef_PlrDamage(Handle plugin, int numParams) { int nAmmoIndex = GetNativeCell(1); - if ( nAmmoIndex < 1 || nAmmoIndex >= AmmoDef_m_nAmmoIndex() ) + if( nAmmoIndex < 1 || nAmmoIndex >= AmmoDef_m_nAmmoIndex() ) return 0; - if ( AmmoDef_m_AmmoType(nAmmoIndex).pPlrDmg == USE_CVAR ) + if( AmmoDef_m_AmmoType(nAmmoIndex).pPlrDmg == USE_CVAR ) { - if ( AmmoDef_m_AmmoType(nAmmoIndex).pPlrDmgCVar ) + if( AmmoDef_m_AmmoType(nAmmoIndex).pPlrDmgCVar ) { return AmmoDef_m_AmmoType(nAmmoIndex).pPlrDmgCVar.GetInt(); } @@ -6267,12 +6322,12 @@ any Native_AmmoDef_NPCDamage(Handle plugin, int numParams) { int nAmmoIndex = GetNativeCell(1); - if ( nAmmoIndex < 1 || nAmmoIndex >= AmmoDef_m_nAmmoIndex() ) + if( nAmmoIndex < 1 || nAmmoIndex >= AmmoDef_m_nAmmoIndex() ) return 0; - if ( AmmoDef_m_AmmoType(nAmmoIndex).pNPCDmg == USE_CVAR ) + if( AmmoDef_m_AmmoType(nAmmoIndex).pNPCDmg == USE_CVAR ) { - if ( AmmoDef_m_AmmoType(nAmmoIndex).pNPCDmgCVar ) + if( AmmoDef_m_AmmoType(nAmmoIndex).pNPCDmgCVar ) { return AmmoDef_m_AmmoType(nAmmoIndex).pNPCDmgCVar.GetInt(); } @@ -6289,12 +6344,12 @@ any Native_AmmoDef_MaxCarry(Handle plugin, int numParams) { int nAmmoIndex = GetNativeCell(1); - if ( nAmmoIndex < 1 || nAmmoIndex >= AmmoDef_m_nAmmoIndex() ) + if( nAmmoIndex < 1 || nAmmoIndex >= AmmoDef_m_nAmmoIndex() ) return 0; - if ( AmmoDef_m_AmmoType(nAmmoIndex).pMaxCarry == USE_CVAR ) + if( AmmoDef_m_AmmoType(nAmmoIndex).pMaxCarry == USE_CVAR ) { - if ( AmmoDef_m_AmmoType(nAmmoIndex).pMaxCarryCVar ) + if( AmmoDef_m_AmmoType(nAmmoIndex).pMaxCarryCVar ) return AmmoDef_m_AmmoType(nAmmoIndex).pMaxCarryCVar.GetInt(); return 0; @@ -6309,7 +6364,7 @@ any Native_AmmoDef_DamageType(Handle plugin, int numParams) { int nAmmoIndex = GetNativeCell(1); - if (nAmmoIndex < 1 || nAmmoIndex >= AmmoDef_m_nAmmoIndex()) + if( nAmmoIndex < 1 || nAmmoIndex >= AmmoDef_m_nAmmoIndex()) return 0; return AmmoDef_m_AmmoType(nAmmoIndex).nDamageType; @@ -6319,7 +6374,7 @@ any Native_AmmoDef_Flags(Handle plugin, int numParams) { int nAmmoIndex = GetNativeCell(1); - if (nAmmoIndex < 1 || nAmmoIndex >= AmmoDef_m_nAmmoIndex()) + if( nAmmoIndex < 1 || nAmmoIndex >= AmmoDef_m_nAmmoIndex()) return 0; return AmmoDef_m_AmmoType(nAmmoIndex).nFlags; @@ -6329,7 +6384,7 @@ any Native_AmmoDef_MinSplashSize(Handle plugin, int numParams) { int nAmmoIndex = GetNativeCell(1); - if (nAmmoIndex < 1 || nAmmoIndex >= AmmoDef_m_nAmmoIndex()) + if( nAmmoIndex < 1 || nAmmoIndex >= AmmoDef_m_nAmmoIndex()) return 4; return AmmoDef_m_AmmoType(nAmmoIndex).nMinSplashSize; @@ -6339,7 +6394,7 @@ any Native_AmmoDef_MaxSplashSize(Handle plugin, int numParams) { int nAmmoIndex = GetNativeCell(1); - if (nAmmoIndex < 1 || nAmmoIndex >= AmmoDef_m_nAmmoIndex()) + if( nAmmoIndex < 1 || nAmmoIndex >= AmmoDef_m_nAmmoIndex()) return 8; return AmmoDef_m_AmmoType(nAmmoIndex).nMaxSplashSize; @@ -6349,7 +6404,7 @@ any Native_AmmoDef_TracerType(Handle plugin, int numParams) { int nAmmoIndex = GetNativeCell(1); - if (nAmmoIndex < 1 || nAmmoIndex >= AmmoDef_m_nAmmoIndex()) + if( nAmmoIndex < 1 || nAmmoIndex >= AmmoDef_m_nAmmoIndex()) return 0; return AmmoDef_m_AmmoType(nAmmoIndex).eTracerType; @@ -6359,7 +6414,7 @@ any Native_AmmoDef_DamageForce(Handle plugin, int numParams) { int nAmmoIndex = GetNativeCell(1); - if ( nAmmoIndex < 1 || nAmmoIndex >= AmmoDef_m_nAmmoIndex() ) + if( nAmmoIndex < 1 || nAmmoIndex >= AmmoDef_m_nAmmoIndex() ) return 0.0; return AmmoDef_m_AmmoType(nAmmoIndex).physicsForceImpulse; diff --git a/SourceCode/scripting-az/l4dd/l4dd_setup.sp b/SourceCode/scripting-az/l4dd/l4dd_setup.sp index db31d628..cbd33bdd 100644 --- a/SourceCode/scripting-az/l4dd/l4dd_setup.sp +++ b/SourceCode/scripting-az/l4dd/l4dd_setup.sp @@ -112,6 +112,7 @@ void SetupForwardsNatives() g_hFWD_CTerrorPlayer_DoAnimationEvent_Post = new GlobalForward("L4D_OnDoAnimationEvent_Post", ET_Event, Param_Cell, Param_Cell, Param_Cell); g_hFWD_CTerrorPlayer_DoAnimationEvent_PostHandled = new GlobalForward("L4D_OnDoAnimationEvent_PostHandled", ET_Event, Param_Cell, Param_Cell, Param_Cell); g_hFWD_CDirectorScriptedEventManager_SendInRescueVehicle = new GlobalForward("L4D2_OnSendInRescueVehicle", ET_Event); + g_hFWD_CDirector_CreateRescuableSurvivors = new GlobalForward("L4D_OnCreateRescuableSurvivors", ET_Event, Param_Array); g_hFWD_CDirectorVersusMode_EndVersusModeRound_Pre = new GlobalForward("L4D2_OnEndVersusModeRound", ET_Event, Param_Cell); g_hFWD_CDirectorVersusMode_EndVersusModeRound_Post = new GlobalForward("L4D2_OnEndVersusModeRound_Post", ET_Event); g_hFWD_CDirectorVersusMode_EndVersusModeRound_PostHandled = new GlobalForward("L4D2_OnEndVersusModeRound_PostHandled", ET_Event); @@ -203,6 +204,19 @@ void SetupForwardsNatives() // g_hFWD_InfectedShoved = new GlobalForward("L4D_OnInfectedShoved", ET_Event, Param_Cell, Param_Cell); // g_hFWD_OnWaterMove = new GlobalForward("L4D2_OnWaterMove", ET_Event, Param_Cell); + if( g_bLeft4Dead2 ) + { + g_hFWD_InfoChangelevel_SaveEntities = new GlobalForward("L4D2_OnSavingEntities", ET_Event, Param_Cell); + g_hFWD_InfoChangelevel_SaveEntities_Post = new GlobalForward("L4D2_OnSavingEntities_Post", ET_Event, Param_Cell); + g_hFWD_InfoChangelevel_SaveEntities_PostHandled = new GlobalForward("L4D2_OnSavingEntities_PostHandled", ET_Event, Param_Cell); + } + else + { + g_hFWD_InfoChangelevel_SaveEntities = new GlobalForward("L4D1_OnSavingEntities", ET_Event, Param_Cell, Param_Cell); + g_hFWD_InfoChangelevel_SaveEntities_Post = new GlobalForward("L4D1_OnSavingEntities_Post", ET_Event, Param_Cell, Param_Cell); + g_hFWD_InfoChangelevel_SaveEntities_PostHandled = new GlobalForward("L4D1_OnSavingEntities_PostHandled", ET_Event, Param_Cell, Param_Cell); + } + if( g_bLeft4Dead2 ) { g_hFWD_CVomitJarProjectile_Create_Pre = new GlobalForward("L4D2_VomitJarProjectile_Pre", ET_Event, Param_Cell, Param_Array, Param_Array, Param_Array, Param_Array); @@ -227,6 +241,7 @@ void SetupForwardsNatives() g_hFWD_CTerrorPlayer_OnStartCarryingVictim_Post = new GlobalForward("L4D2_OnStartCarryingVictim_Post", ET_Event, Param_Cell, Param_Cell); g_hFWD_CTerrorPlayer_OnStartCarryingVictim_PostHandled = new GlobalForward("L4D2_OnStartCarryingVictim_PostHandled", ET_Event, Param_Cell, Param_Cell); g_hFWD_CCharge_ImpactStagger = new GlobalForward("L4D2_OnChargerImpact", ET_Event, Param_Cell); + g_hFWD_CTerrorPlayer_OnDominatedBySpecialInfected = new GlobalForward("L4D2_OnDominatedBySpecialInfected", ET_Event, Param_Cell, Param_Cell); g_hFWD_CGasCanEvent_Killed = new GlobalForward("L4D2_CGasCan_EventKilled", ET_Event, Param_Cell, Param_CellByRef, Param_CellByRef); g_hFWD_CGasCanEvent_Killed_Post = new GlobalForward("L4D2_CGasCan_EventKilled_Post", ET_Event, Param_Cell, Param_Cell, Param_Cell); g_hFWD_CGasCanEvent_Killed_PostHandled = new GlobalForward("L4D2_CGasCan_EventKilled_PostHandled", ET_Event, Param_Cell, Param_Cell, Param_Cell); @@ -330,6 +345,7 @@ void SetupForwardsNatives() CreateNative("L4D_GetRandomPZSpawnPosition", Native_ZombieManager_GetRandomPZSpawnPosition); CreateNative("L4D_FindRandomSpot", Native_TerrorNavArea_FindRandomSpot); CreateNative("L4D_WarpToValidPositionIfStuck", Native_CTerrorPlayer_WarpToValidPositionIfStuck); + CreateNative("L4D2_GetSpecialInfectedDominatingMe", Native_CTerrorPlayer_GetSpecialInfectedDominatingMe); CreateNative("L4D2_IsVisibleToPlayer", Native_IsVisibleToPlayer); CreateNative("L4D_GetNearestNavArea", Native_CNavMesh_GetNearestNavArea); CreateNative("L4D_GetLastKnownArea", Native_CTerrorPlayer_GetLastKnownArea); @@ -600,6 +616,7 @@ void SetupForwardsNatives() CreateNative("L4D_State_Transition", Native_CCSPlayer_State_Transition); CreateNative("L4D_RegisterForbiddenTarget", Native_CDirector_RegisterForbiddenTarget); CreateNative("L4D_UnRegisterForbiddenTarget", Native_CDirector_UnregisterForbiddenTarget); + CreateNative("L4D_IsEntitySaveable", Native_InfoChangelevel_IsEntitySaveable); // L4D2 only: CreateNative("L4D2_CTerrorPlayer_OnHitByVomitJar", Native_CTerrorPlayer_OnHitByVomitJar); diff --git a/SourceCode/scripting-az/l4dd/left4dhooks_changelog.txt b/SourceCode/scripting-az/l4dd/left4dhooks_changelog.txt index f4a4d32a..2d1983f9 100644 --- a/SourceCode/scripting-az/l4dd/left4dhooks_changelog.txt +++ b/SourceCode/scripting-az/l4dd/left4dhooks_changelog.txt @@ -1,11 +1,35 @@ -1.153 (17-Sep-2024) - - Changed natives "L4D2Direct_SetVSCampaignScore" and "L4D2_SetVersusCampaignScores" to update the tab scoreboard and real scores. Thanks to "Pa4H" for reporting. - - Fixed the "NAV_SPAWN_*" attribute comments in the "left4dhooks.inc" include file. Thanks to "Marttt" for reporting. +1.156 (15-Dec-2024) + - Added forwards "L4D1_OnSavingEntities" and "L4D2_OnSavingEntities" to trigger when entities are being saved on level change. Thanks to "blueblur0730" for adding. + - Added native "L4D_IsEntitySaveable" to test if an entity is savable. Thanks to "blueblur0730" for adding. + - Fixed the "L4D_PipeBombProjectile_*" and "L4D_PipeBomb_Detonate*" forwards triggering for breakable props when only "L4D_CBreakableProp_Break" should trigger. Thanks to "blueblur0730" for reporting. + - Fixed forward "L4D_OnCreateRescuableSurvivors" not loading in L4D1 due to GameData file typo. Thanks to "Chenhupo" for reporting. + - Wildcarded the "CTerrorGameRules::RecomputeTeamScores" signature in L4D1 to avoid failing if detoured. Thanks to "Chenhupo" for reporting. - Updated: Plugin and test plugin. + - Updated: "/gamedata/left4dhooks.l4d1.txt" GameData file. + - Updated: "/gamedata/left4dhooks.l4d2.txt" GameData file. + - Updated: "/scripting/l4dd/l4dd_forwards.sp" project file. + - Updated: "/scripting/l4dd/l4dd_gamedata.sp" project file. - Updated: "/scripting/l4dd/l4dd_natives.sp" project file. + - Updated: "/scripting/l4dd/l4dd_setup.sp" project file. - Updated: "/scripting/include/left4dhooks.inc" include file. +1.155 (05-Nov-2024) + - Fixed incorrect GameData file in project archive. Thanks to "kayletid201" for reporting. + - Reverted changing "L4D1ZombieClassname" and "L4D2ZombieClassname" to "static" in the "left4dhooks_stocks.inc" file. Thanks to "ilham92-cc-sakura" for reporting. + +1.154 (05-Nov-2024) + - Added forward "L4D_OnCreateRescuableSurvivors" to allow blocking specific players from respawning. Requested by "Kerouha". + - Added forward "L4D2_OnDominatedBySpecialInfected" to trigger when someone is being dominated by Special Infected. Thanks to "blueblur0730" for adding. + - Added native "L4D2_GetSpecialInfectedDominatingMe" to chec if someone is being dominated by Special Infected. Thanks to "blueblur0730" for adding. + - Added stocks "L4D1_GetZombieClassname" and "L4D2_GetZombieClassname" to prevent SM 1.12 warnings. + - Minor change to "left4dhooks_lux_library.inc" to prevent SM 1.12 warnings. + - Fixed warnings in SM 1.12. Thanks to "Sist" for reporting. + +1.153 (17-Sep-2024) + - Changed natives "L4D2Direct_SetVSCampaignScore" and "L4D2_SetVersusCampaignScores" to update the tab scoreboard and real scores. Thanks to "Pa4H" for reporting. + - Fixed the "NAV_SPAWN_*" attribute comments in the "left4dhooks.inc" include file. Thanks to "Marttt" for reporting. + 1.152 (07-Sep-2024) - Added 4 member pointers of CDirector for L4D_GetPointer() to use. Thanks to "blueblur0730" for adding on GitHub. - Added native "L4D_SetCampaignScores" to set the current campaign scores stored in the Director. diff --git a/SourceCode/scripting-az/l4dready.sp b/SourceCode/scripting-az/l4dready.sp index 71da5331..4c2dfe99 100644 --- a/SourceCode/scripting-az/l4dready.sp +++ b/SourceCode/scripting-az/l4dready.sp @@ -20,7 +20,7 @@ #define READY_DEBUG 0 #define READY_DEBUG_LOG 0 -#define READY_VERSION "8.5.8" +#define READY_VERSION "8.5.9" #define READY_LIVE_COUNTDOWN 2 #define READY_UNREADY_HINT_PERIOD 5.0 #define READY_LIST_PANEL_LIFETIME 2 diff --git a/SourceCode/scripting-az/l4dscores.sp b/SourceCode/scripting-az/l4dscores.sp index 8105557d..7fc23efc 100644 --- a/SourceCode/scripting-az/l4dscores.sp +++ b/SourceCode/scripting-az/l4dscores.sp @@ -3,8 +3,7 @@ #include #include #include - -#define SCORE_VERSION "8.5.8" +#define SCORE_VERSION "8.5.9" #define SCORE_DEBUG 0 #define SCORE_DEBUG_LOG 0 diff --git a/SourceCode/scripting-az/left4dhooks.sp b/SourceCode/scripting-az/left4dhooks.sp index 39ea60eb..66cd19f8 100644 --- a/SourceCode/scripting-az/left4dhooks.sp +++ b/SourceCode/scripting-az/left4dhooks.sp @@ -18,8 +18,8 @@ -#define PLUGIN_VERSION "1.153" -#define PLUGIN_VERLONG 1153 +#define PLUGIN_VERSION "1.156" +#define PLUGIN_VERLONG 1156 #define DEBUG 0 // #define DEBUG 1 // Prints addresses + detour info (only use for debugging, slows server down). @@ -370,6 +370,7 @@ bool g_bLeft4Dead2; bool g_bFinalCheck; bool g_bMapStarted; bool g_bRoundEnded; +bool g_bBreakable; bool g_bCheckpointFirst[MAXPLAYERS+1]; bool g_bCheckpointLast[MAXPLAYERS+1]; ConVar g_hCvar_VScriptBuffer; @@ -1005,10 +1006,13 @@ public void OnMapEnd() { hPlug = ReadPlugin(hIter); - for( int i = 1; i <= MaxClients; i++ ) + if( hPlug ) { - g_hAnimationCallbackPre[i].RemoveAllFunctions(hPlug); - g_hAnimationCallbackPost[i].RemoveAllFunctions(hPlug); + for( int i = 1; i <= MaxClients; i++ ) + { + g_hAnimationCallbackPre[i].RemoveAllFunctions(hPlug); + g_hAnimationCallbackPost[i].RemoveAllFunctions(hPlug); + } } } @@ -1352,7 +1356,7 @@ void AddonsDisabler_Unpatch() // ==================================================================================================== // ADDONS DISABLER DETOUR // ==================================================================================================== -MRESReturn DTR_AddonsDisabler(int pThis, Handle hReturn, DHookParam hParams) // Forward "L4D2_OnClientDisableAddons" +MRESReturn DTR_AddonsDisabler(int pThis, DHookReturn hReturn, DHookParam hParams) // Forward "L4D2_OnClientDisableAddons" { // Details on finding offsets can be found here: https://github.com/ProdigySim/left4dhooks/pull/1 // Big thanks to "ProdigySim" for updating for The Last Stand update. diff --git a/SourceCode/scripting-az/rotoblin-az.sp b/SourceCode/scripting-az/rotoblin-az.sp index 7bd3cd0a..ef75e4e8 100644 --- a/SourceCode/scripting-az/rotoblin-az.sp +++ b/SourceCode/scripting-az/rotoblin-az.sp @@ -41,7 +41,6 @@ // ********************************************** // Reference // ********************************************** -#define SERVER_INDEX 0 // The client index of the server #define FIRST_CLIENT 1 // First valid client index #define TEAM_SPECTATOR 1 #define TEAM_SURVIVOR 2 @@ -54,7 +53,7 @@ #define PLUGIN_SHORTNAME "rotoblin" // Shorter version of the full name, used in file paths, and other things #define PLUGIN_AUTHOR "Rotoblin Team, HarryPotter" // Author of the plugin #define PLUGIN_DESCRIPTION "A competitive mod for L4D1" // Description of the plugin -#define PLUGIN_VERSION "8.5.8" // Version +#define PLUGIN_VERSION "8.5.9" // Version #define PLUGIN_URL "https://github.com/fbef0102/Rotoblin-AZMod" // URL associated with the project #define PLUGIN_CVAR_PREFIX PLUGIN_SHORTNAME // Prefix for cvars #define PLUGIN_CMD_PREFIX PLUGIN_SHORTNAME // Prefix for cmds @@ -100,7 +99,6 @@ bool g_bGasMap, g_bWAIT_FOR_FINALE_map; #include "rotoblin/rotoblin.pause.sp" #include "rotoblin/rotoblin.reportstatus.sp" #include "rotoblin/rotoblin.pumpswap.sp" -#include "rotoblin/rotoblin.unreservelobby.sp" #include "rotoblin/rotoblin.limitweapon.sp" #include "rotoblin/rotoblin.weaponcontrol.sp" #include "rotoblin/rotoblin.itemcontrol.sp" @@ -194,7 +192,6 @@ public OnPluginStartEx() _HordeControl_OnPluginStart(); _2vs2Mod_OnPluginStart(); _ReportStatus_OnPluginStart(); - _UnreserveLobby_OnPluginStart(); _PumpSwap_OnPluginStart(); _LimitHuntingRifl_OnPluginStart(); _ItemControl_OnPluginStart(); diff --git a/SourceCode/scripting-az/rotoblin/rotoblin.unreservelobby.sp b/SourceCode/scripting-az/rotoblin/rotoblin.unreservelobby.sp deleted file mode 100644 index 4707af0a..00000000 --- a/SourceCode/scripting-az/rotoblin/rotoblin.unreservelobby.sp +++ /dev/null @@ -1,110 +0,0 @@ -/* - * ============================================================================ - * - * Rotoblin - * - * File: rotoblin.unreservelobby.sp - * Type: Module - * Description: Unreserves the lobby so more than 8 players can join. - * Credits: Downtown1 for original source, - * http://forums.alliedmods.net/showthread.php?p=846083 - * - * Copyright (C) 2010 Mr. Zero - * Copyright (C) 2017-2024 Harry - * This file is part of Rotoblin. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * 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 . - * - * ============================================================================ - */ - -// -------------------- -// Private -// -------------------- - -static g_iDebugChannel = 0; -static const String: DEBUG_CHANNEL_NAME[] = "UnreserveLobby"; - -// ********************************************** -// Forwards -// ********************************************** - -/** - * Plugin is starting. - * - * @noreturn - */ -public _UnreserveLobby_OnPluginStart() -{ - HookPublicEvent(EVENT_ONPLUGINENABLE, _UL_OnPluginEnabled); - HookPublicEvent(EVENT_ONPLUGINDISABLE, _UL_OnPluginDisabled); - - g_iDebugChannel = DebugAddChannel(DEBUG_CHANNEL_NAME); - DebugPrintToAllEx("Module is now setup"); -} - -/** - * Plugin is now enabled. - * - * @noreturn - */ -public _UL_OnPluginEnabled() -{ - HookPublicEvent(EVENT_ONCLIENTPUTINSERVER, _UL_OnClientPutInServer); - - DebugPrintToAllEx("Module is now loaded"); -} - -/** - * Plugin is now disabled. - * - * @noreturn - */ -public _UL_OnPluginDisabled() -{ - UnhookPublicEvent(EVENT_ONCLIENTPUTINSERVER, _UL_OnClientPutInServer); - - DebugPrintToAllEx("Module is now unloaded"); -} - -/** - * A client is put in server. - * - * @noreturn - */ -public _UL_OnClientPutInServer(client) -{ - if (!client || IsFakeClient(client)) return; - L4D_LobbyUnreserve(); - DebugPrintToAllEx("Lobby reservation was removed"); -} - -// ********************************************** -// Private API -// ********************************************** - -/** - * Wrapper for printing a debug message without having to define channel index - * everytime. - * - * @param format Formatting rules. - * @param ... Variable number of format parameters. - * @noreturn - */ -static DebugPrintToAllEx(const String:format[], any:...) -{ - decl String:buffer[DEBUG_MESSAGE_LENGTH]; - VFormat(buffer, sizeof(buffer), format, 2); - DebugPrintToAll(g_iDebugChannel, buffer); -} \ No newline at end of file diff --git a/SourceCode/scripting-az/staggersolver.sp b/SourceCode/scripting-az/staggersolver.sp index 203ba04b..9d8939c0 100644 --- a/SourceCode/scripting-az/staggersolver.sp +++ b/SourceCode/scripting-az/staggersolver.sp @@ -29,6 +29,8 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max /** * 修復以下第一個官方bug * 爬梯子時被Hunter控然後解控,如果還黏在梯子上會導致第三人稱卡住,無法恢復第一人稱並無法移動 (任何按鍵均無效) + * (一代被boomer 瓦斯桶震退到不會有這bug) + * (二代不會發生) */ methodmap GameDataWrapper < GameData { public GameDataWrapper(const char[] file) { @@ -146,8 +148,9 @@ public void L4D2_OnPounceOrLeapStumble_PostHandled(int client, int attacker) // @remarks This forward will not trigger if the relative pre-hook forward has been blocked with Plugin_Handled public void L4D2_OnPounceOrLeapStumble_Post(int client, int attacker) { - //修復第二個官方bug - //爬梯子時被Hunter控然後解控,如果還黏在梯子上會導致第三人稱卡住,無法恢復第一人稱並無法移動 (任何按鍵均無效) + // 修復第二個官方bug + // 在爬梯子時被Hunter震退,如果還黏在梯子上會導致無法移動上下左右 (空白鍵依然可以按) + // 二代也會發生 if (GetEntityMoveType(client) == MOVETYPE_LADDER) { SetEntPropVector(client, Prop_Send, "m_shoveForce", NULL_VECTOR); diff --git a/left4dead/addons/sourcemod/gamedata/left4dhooks.l4d1.txt b/left4dead/addons/sourcemod/gamedata/left4dhooks.l4d1.txt index 3d278de2..c58532f7 100644 --- a/left4dead/addons/sourcemod/gamedata/left4dhooks.l4d1.txt +++ b/left4dead/addons/sourcemod/gamedata/left4dhooks.l4d1.txt @@ -736,6 +736,13 @@ "this" "ignore" } + "L4DD::CDirector::CreateRescuableSurvivors" + { + "signature" "CDirector::CreateRescuableSurvivors" + "callconv" "thiscall" + "return" "int" + } + "L4DD::CDirectorVersusMode::EndVersusModeRound" { "signature" "CDirectorVersusMode::EndVersusModeRound" @@ -1205,6 +1212,21 @@ } } } + + "L4DD::InfoChangelevel::SaveEntities" + { + "signature" "InfoChangelevel::SaveEntities" + "callconv" "thiscall" + "return" "void" + "this" "entity" + "arguments" + { + "KeyValues" + { + "type" "int" + } + } + } } @@ -1763,8 +1785,8 @@ { "library" "server" "windows" "\xD9\x05\x2A\x2A\x2A\x2A\x6A\x0E\x6A\x0A\x6A\x04\x2A\xD9\x2A\x2A\x68\x2A\x2A\x2A\x2A\x6A\x00\x6A\x00\x6A\x01\x68\x02\x00\x00\x80" - /* not actual function beginning, starts at the second call */ - /* D9 05 ? ? ? ? 6A 0E 6A 0A 6A 04 ? D9 ? ? 68 ? ? ? ? 6A 00 6A 00 6A 01 68 02 00 00 80 */ + /* not actual function beginning, starts at the second call */ + /* D9 05 ? ? ? ? 6A 0E 6A 0A 6A 04 ? D9 ? ? 68 ? ? ? ? 6A 00 6A 00 6A 01 68 02 00 00 80 */ } // ========================= @@ -2223,7 +2245,7 @@ "library" "server" "linux" "@_ZN9CTankClaw7DoSwingEv" "windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x8B\x2A\x85\x2A\x74\x2A\x8D\x2A\x2A\x2A\x50\x8D\x2A\x2A\x2A\x51\x68" - /* ? ? ? ? ? ? ? E8 ? ? ? ? 8B ? 85 ? 74 ? 8D ? ? ? 50 8D ? ? ? 51 68 */ + /* ? ? ? ? ? ? ? E8 ? ? ? ? 8B ? 85 ? 74 ? 8D ? ? ? 50 8D ? ? ? 51 68 */ } /** @@ -2241,7 +2263,7 @@ "library" "server" "linux" "@_ZN9CTankClaw11GroundPoundEv" "windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x81\xEC\x2A\x2A\x2A\x2A\x53\x56\x57\x8B\x2A\xE8\x2A\x2A\x2A\x2A\x8B\x2A\x85" - /* ? ? ? ? ? ? 81 EC ? ? ? ? 53 56 57 8B ? E8 ? ? ? ? 8B ? 85 */ + /* ? ? ? ? ? ? 81 EC ? ? ? ? 53 56 57 8B ? E8 ? ? ? ? 8B ? 85 */ } /** @@ -2263,7 +2285,7 @@ "library" "server" "linux" "@_ZN9CTankClaw11OnPlayerHitEP13CTerrorPlayerb" "windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x53\x55\x56\x57\x8B\x2A\xE8\x2A\x2A\x2A\x2A\x8B\xB4" - /* ? ? ? ? ? ? 53 55 56 57 8B ? E8 ? ? ? ? 8B B4 */ + /* ? ? ? ? ? ? 53 55 56 57 8B ? E8 ? ? ? ? 8B B4 */ } /** @@ -2285,7 +2307,7 @@ "library" "server" "linux" "@_ZN9CTankRock8DetonateEv" "windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x8B\x2A\x80\xBE\x2A\x2A\x2A\x2A\x2A\x57\x0F\x84\x2A\x2A\x2A\x2A\xD9" - /* ? ? ? ? ? ? 8B ? 80 BE ? ? ? ? ? 57 0F 84 ? ? ? ? D9 */ + /* ? ? ? ? ? ? 8B ? 80 BE ? ? ? ? ? 57 0F 84 ? ? ? ? D9 */ } /** @@ -2301,7 +2323,7 @@ "library" "server" "linux" "@_ZN9CTankRock9OnReleaseERK6VectorRK6QAngleS2_S2_" "windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\xC7\x86\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x8B\x2A\x2A\x2A\x57" - /* ? ? ? ? ? ? ? ? ? ? ? C7 86 ? ? ? ? ? ? ? ? E8 ? ? ? ? 8B ? ? ? 57 */ + /* ? ? ? ? ? ? ? ? ? ? ? C7 86 ? ? ? ? ? ? ? ? E8 ? ? ? ? 8B ? ? ? 57 */ } /** @@ -2322,7 +2344,7 @@ "library" "server" "linux" "@_ZN9CTankRock11BounceTouchEP11CBaseEntity" "windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x53\x8B\x9C\x2A\x2A\x2A\x2A\x2A\x0F" - /* ? ? ? ? ? ? 53 8B 9C ? ? ? ? ? 0F */ + /* ? ? ? ? ? ? 53 8B 9C ? ? ? ? ? 0F */ } /** @@ -2341,7 +2363,7 @@ "library" "server" "linux" "@_ZN16CDeathFallCamera6EnableEP11CBasePlayer" "windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x8B\x2A\x8B\x2A\xE8\x2A\x2A\x2A\x2A\x85\x2A\x74\x2A\x6A" - /* ? ? ? ? ? ? 8B ? 8B ? E8 ? ? ? ? 85 ? 74 ? 6A */ + /* ? ? ? ? ? ? 8B ? 8B ? E8 ? ? ? ? 85 ? 74 ? 6A */ } /* CTerrorPlayer::Cough(CTerrorPlayer *this, CBasePlayer *) */ @@ -2389,7 +2411,7 @@ "library" "server" "linux" "@_ZN13CTerrorPlayer9OnFallingEv" "windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x57\x8B\x2A\xE8\x2A\x2A\x2A\x2A\x83\x2A\x2A\x0F\x85\x2A\x2A\x2A\x2A\x8D" - /* ? ? ? ? ? ? 57 8B ? E8 ? ? ? ? 83 ? ? 0F 85 ? ? ? ? 8D */ + /* ? ? ? ? ? ? 57 8B ? E8 ? ? ? ? 83 ? ? 0F 85 ? ? ? ? 8D */ } /* CTerrorPlayer::EstimateFallingDamage(CTerrorPlayer *this) */ @@ -2419,7 +2441,7 @@ "library" "server" "linux" "@_ZN4Tank11EnterStasisEv" "windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x0F\x85\x2A\x2A\x2A\x2A\x83\x2A\x2A\x2A\x0F\x84\x2A\x2A\x2A\x2A\x0F" - /* ? ? ? ? ? ? ? ? ? ? 0F 85 ? ? ? ? 83 ? ? ? 0F 84 ? ? ? ? 0F */ + /* ? ? ? ? ? ? ? ? ? ? 0F 85 ? ? ? ? 83 ? ? ? 0F 84 ? ? ? ? 0F */ } /** @@ -2435,7 +2457,7 @@ "library" "server" "linux" "@_ZN4Tank11LeaveStasisEv" "windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x0F\x84\x2A\x2A\x2A\x2A\x83\x2A\x2A\x2A\x74\x2A\x0F" - /* ? ? ? ? ? ? ? ? ? ? 0F 84 ? ? ? ? 83 ? ? ? 74 ? 0F */ + /* ? ? ? ? ? ? ? ? ? ? 0F 84 ? ? ? ? 83 ? ? ? 74 ? 0F */ } // ========================= @@ -3031,7 +3053,7 @@ "library" "server" "linux" "@_ZN12CFirstAidKit12StartHealingENS_14HealTargetTypeE.part.38" "windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x53\x55\x56\x8D\xB1\x2A\x2A\x2A\x2A\x57\x89" - /* ? ? ? ? ? ? ? ? 53 55 56 8D B1 ? ? ? ? 57 89 */ + /* ? ? ? ? ? ? ? ? 53 55 56 8D B1 ? ? ? ? 57 89 */ } "BossZombiePlayerBot::ChooseVictim" @@ -3053,6 +3075,19 @@ /* Search: "%s_%s_%d%s" and xref to vtable, function is above this. */ } + /** + * Windows sig: + * Search for string "Would change level, but not going to!\n" to find InfoChangelevel::StartChangeLevel + * the function above string "map_transition" is InfoChangeLevel::SavingEntities + */ + /* */ + "InfoChangelevel::SaveEntities" + { + "library" "server" + "linux" "@_ZN15InfoChangelevel12SaveEntitiesEP9KeyValues" + "windows" "\x55\x8B\x2A\x83\x2A\x2A\x83\x2A\x2A\x53\x56\x8B\x2A\x57\xB9\x2A\x2A\x2A\x2A\x89" + /* 55 8B ? 83 ? ? 83 ? ? 53 56 8B ? 57 B9 ? ? ? ? 89 */ + } // ==================================================================================================== @@ -3202,14 +3237,14 @@ } /* - * CTerrorGameRules::RecomputeTeamScores(void) - */ + * CTerrorGameRules::RecomputeTeamScores(void) + */ "CTerrorGameRules::RecomputeTeamScores" { - "library" "server" - "linux" "@_ZN16CTerrorGameRules19RecomputeTeamScoresEv" - "windows" "\xA1\x2A\x2A\x2A\x2A\x83\xEC\x34\x80\x78\x2A\x2A\x56\x8B\xF1\x0F\x84\x2A\x2A\x2A\x2A\x53\x33\xDB" - /* A1 ? ? ? ? 83 EC 34 80 78 ? ? 56 8B F1 0F 84 ? ? ? ? 53 33 DB */ + "library" "server" + "linux" "@_ZN16CTerrorGameRules19RecomputeTeamScoresEv" + "windows" "\x2A\x2A\x2A\x2A\x2A\x2A\xEC\x34\x80\x78\x2A\x2A\x56\x8B\xF1\x0F\x84\x2A\x2A\x2A\x2A\x53\x33\xDB" + /* ? ? ? ? ? ? EC 34 80 78 ? ? 56 8B F1 0F 84 ? ? ? ? 53 33 DB */ } /* CTerrorPlayer::RoundRespawn(CTerrorPlayer *this) */ @@ -3541,6 +3576,23 @@ /* Search "PanicEvent" for "CCarProp::InputSurvivorStandingOnCar". Called in here. */ } + /* + * InfoChangelevel::IsEntitySaveable(CBaseEntity *) + */ + + /** + * windows sig: + * Find InfoChangelevel::SaveEntities (see signature description InfoChangelevel::SaveEntities), + * At the top of the function, see a 'while' statement, inside of it there's 'if' statement, the second condition call is InfoChangelevel::IsEntitySaveable. + */ + "InfoChangelevel::IsEntitySaveable" + { + "library" "server" + "linux" "@_ZN15InfoChangelevel16IsEntitySaveableEP11CBaseEntity" + "windows" "\x53\x56\x8B\x2A\x2A\x2A\x8B\x2A\x8B\x2A\x2A\x2A\x2A\x2A\x8B\x2A\xFF\x2A\x8B\x2A\x85\x2A\x78\x2A\x8B" + /* 53 56 8B ? ? ? 8B ? 8B ? ? ? ? ? 8B ? FF ? 8B ? 85 ? 78 ? 8B */ + } + /* * CBaseServer::SetReservationCookie(uint64_t, char*, va_list) */ diff --git a/left4dead/addons/sourcemod/plugins/l4d_unreservelobby.smx b/left4dead/addons/sourcemod/plugins/l4d_unreservelobby.smx new file mode 100644 index 00000000..040115e3 Binary files /dev/null and b/left4dead/addons/sourcemod/plugins/l4d_unreservelobby.smx differ diff --git a/left4dead/addons/sourcemod/plugins/left4dhooks.smx b/left4dead/addons/sourcemod/plugins/left4dhooks.smx index 8c6770a0..bfeb767b 100644 Binary files a/left4dead/addons/sourcemod/plugins/left4dhooks.smx and b/left4dead/addons/sourcemod/plugins/left4dhooks.smx differ diff --git a/left4dead/addons/sourcemod/plugins/rotoblin-az.smx b/left4dead/addons/sourcemod/plugins/rotoblin-az.smx index f4dc9a3e..017077a6 100644 Binary files a/left4dead/addons/sourcemod/plugins/rotoblin-az.smx and b/left4dead/addons/sourcemod/plugins/rotoblin-az.smx differ diff --git a/left4dead/addons/stripper/Roto-AZMod/maps/l4d_vs_airport05_runway.cfg b/left4dead/addons/stripper/Roto-AZMod/maps/l4d_vs_airport05_runway.cfg index 7a184be5..2518b1a3 100644 --- a/left4dead/addons/stripper/Roto-AZMod/maps/l4d_vs_airport05_runway.cfg +++ b/left4dead/addons/stripper/Roto-AZMod/maps/l4d_vs_airport05_runway.cfg @@ -418,4 +418,19 @@ filter: ; ===================================================== ; == BLANK HEADER == ; == Blank description == -; ===================================================== \ No newline at end of file +; ===================================================== + +; Harry Modify 2024 +; Harry personal +modify: +{ + match: + { + "hammerid" "4027526" + } + delete: + { + ; fix witch not moving before plane crash + "OnMapSpawn" "planecrash_navblocker,BlockNav,,0,-1" + } +} \ No newline at end of file diff --git a/left4dead/cfg/Reloadables/server_custom_convars.cfg b/left4dead/cfg/Reloadables/server_custom_convars.cfg index 38d239dd..4eb2638e 100644 --- a/left4dead/cfg/Reloadables/server_custom_convars.cfg +++ b/left4dead/cfg/Reloadables/server_custom_convars.cfg @@ -1,3 +1,5 @@ +// write down your own settings here + //sm plugins unlock sm plugins load_unlock diff --git a/left4dead/cfg/cheats.cfg b/left4dead/cfg/cheats.cfg index f4ab663b..e5bd7fd5 100644 --- a/left4dead/cfg/cheats.cfg +++ b/left4dead/cfg/cheats.cfg @@ -1,12 +1,11 @@ sv_cheats 1 -sb_all_bot_team 1 -vs_max_team_switches 100 -sb_stop 1 director_stop -god 1 -nb_blind 1 -sv_alltalk 1 -sm_cvar director_afk_timeout 99999999 +sm_cvar sb_all_bot_team 1 +sm_cvar vs_max_team_switches 100 +sm_cvar sb_stop 1 +sm_cvar god 1 +sm_cvar nb_blind 1 +sm_cvar sv_alltalk 1 l4d_teamswitch_during_game_seconds_block 0 rotoblin_health_style 0 diff --git a/left4dead/cfg/rotoblin_hardcore_5v5_map.cfg b/left4dead/cfg/rotoblin_hardcore_5v5_map.cfg index 372f2c21..14cd31ac 100644 --- a/left4dead/cfg/rotoblin_hardcore_5v5_map.cfg +++ b/left4dead/cfg/rotoblin_hardcore_5v5_map.cfg @@ -51,7 +51,7 @@ exec server_shared_convars.cfg //----------------------------------------- rotoblin_limit_smg 4 -rotoblin_limit_pumpshotgun 4 +rotoblin_limit_pumpshotgun -1 //----------------------------------------- //Execute Custom convars diff --git a/left4dead/cfg/rotoblin_pub.cfg b/left4dead/cfg/rotoblin_pub.cfg index 94ef6eb5..4763405e 100644 --- a/left4dead/cfg/rotoblin_pub.cfg +++ b/left4dead/cfg/rotoblin_pub.cfg @@ -15,13 +15,33 @@ l4d_ready_league_notice "Pub" l4d_game_type_name "Roto-AZ / Pub VS" //----------------------------------------- //Rotoblin convars -rotoblin_enable 1 // Sets if Rotoblin is enabled -rotoblin_pause 0 // Sets if game can be paused -rotoblin_health_style 2 // Replace saferoom medkits with pills + allow kits on the map + 1 kit only on final rescue -rotoblin_weapon_style 0 // How weapons will be replaced. 0 - Don't replace any weapons, 1 - Replace all tier 2 weapons -rotoblin_melee_penalty 2 // Shove penalty added for each non-fatigued melee swipe. Melee fatigue kicks in at 4, meaning the third fast melee will cause fatigue. -rotoblin_enable_throwables 1 // Pipes and mollys -rotoblin_enable_cannisters 1 // Explosive/flammable cannisters + +// Sets if Rotoblin is enabled +rotoblin_enable 1 + +// If 1, Player can type !pause to pause game +rotoblin_pause 0 + +// 0=Don't replace any medkits with pills +// 1=Replace all medkits with pills +// 2=Replace saferoom medkits with pills + allow few kits on the map and final +// 3=Replace the finale kits with pills and remove all other pills/kits + give pills +// 4=Replace all medkits with pills (use data/mapinfo to control pill limit) + remove saferoom kits + give pills when round starts +rotoblin_health_style 2 + +// 0 - Don't replace any weapons, 1 - Replace all tier 2 weapons +rotoblin_weapon_style 0 + +// Sets the value to be added to a survivor's shove penalty. +// This _only_ gets added when that survivor is not already fatigued +// so basically, setting this to a large value will make the survivors become fatigued more quickly, but the cooldown effect won't change once fatigue has set in +rotoblin_melee_penalty 2 + +// 0=Remove all Pipes and Molotovs. 1=Allow Pipes and Molotovs +rotoblin_enable_throwables 1 + +// 0=Remove all Explosive Prop Tanks and Gas Cans. 1=Allow Explosive Prop Tanks and Gas Cans +rotoblin_enable_cannisters 1 //----------------------------------------- //executing map config exec rotoblin_pub_map.cfg diff --git a/left4dead/cfg/server.cfg b/left4dead/cfg/server.cfg index 17ba9023..2c4e7d11 100644 --- a/left4dead/cfg/server.cfg +++ b/left4dead/cfg/server.cfg @@ -5,9 +5,9 @@ // ----------------------------------------------------------------------- log on //Creates a logfile (on | off) sv_logecho 0 //default 0; Echo log information to the console. -sv_logfile 1 //default 1; Log server information in the log file. +sv_logfile 1 //default 1; Log server information in the log file. sv_log_onefile 0 //default 0; Log server information to only one file. -sv_logbans 1 //default 0; Log server bans in the server logs. +sv_logbans 1 //default 0; Log server bans in the server logs. sv_logflush 0 //default 0; Flush the log files to disk on each write (slow). sv_logsdir logs //Folder in the game directory where server logs will be stored. @@ -15,7 +15,7 @@ sv_logsdir logs //Folder in the game directory where se // ----------------------------------------------------------------------- //hostname "HarryPotter TS BETA" // Hostname, I suggest use l4d_DynamicHostname plugin: https://github.com/fbef0102/L4D1_2-Plugins/tree/master/l4d_DynamicHostname -rcon_password "ThePasswordHereYouEnter" // Rcon password, used for remote access mostly. Use "" disable remote +//rcon_password "ThePasswordHereYouEnter" // Rcon password, used for remote access mostly. Use "" disable remote sv_steamgroup "25572448" sv_search_key "L4D1 CompetitiveRework" sv_steamgroup_exclusive "0" // If set, only members of Steam group will be able to join the server when it's empty, public people will be able to join the server only if it has players. @@ -25,6 +25,7 @@ motd_enabled "1" motdfile "mymotd.txt" // This ensures that Valve doesn't overwrite the MoTD every Update. [Edit this file instead of motd.txt, found in the same folder (/left4dead)] hostfile "myhost.txt" // This ensures that Valve doesn't overwrite the Hostfile every Update. [Edit this file instead of host.txt, found in the same folder (/left4dead)] + // [File Consistency] // ----------------------------------------------------------------------- sv_consistency "1" // Whether the server enforces file consistency for critical files. @@ -32,15 +33,15 @@ sv_pure "2" // The server will force all client fil sv_pure_kick_clients "1" // If set to 1, the server will kick clients with mismatching files. // [Wait Commands] -sm_cvar sv_allow_wait_command "0" // If set to 0, disallow the wait command on clients +sm_cvar sv_allow_wait_command 0 / If set to 1, disallow the wait command on clients // [Server Cvars] sv_alltalk "1" sv_pausable "0" sv_voiceenable "1" -sv_contact "fbef0102@gmail.com" -sv_tags "TS,Roto2-AZmod v8.5.8" //Tags that appear in the server browser (In-Game) +sv_contact "Your_email@gmail.com" +sv_tags "TS,Roto2-AZmod v8.5.9" //Tags that appear in the server browser (In-Game) // [Remote settings] sv_rcon_minfailures "3" //ban who tries to log in server @@ -53,23 +54,17 @@ sv_rcon_banpenalty "720" //Number of minutes to ban users who fail rcon authenti //If 1, Allow to join this server from matchmaking lobby only //If 1, server has reserve match system no matter how players join server //If 1, Now allow to change sv_cheats to 1 -sv_allow_lobby_connect_only 0 +sv_allow_lobby_connect_only 1 //This cvar from l4dtoolz extension //If 1, force sv_allow_lobby_connect_only to be 0 //If 1, no reserved cookie + don't reply reservation request form lobby -sv_force_unreserved 1 - -sv_region 4 //4=Asia - -// Spray frequency -sm_cvar decalfrequency 0.1 - -// Switch Team Max limit -sm_cvar vs_max_team_switches 9999 +sv_force_unreserved 0 -// Fix hunter skeet -sm_cvar z_pounce_damage_interrupt 150 +// Set your server region to steam master +// https://developer.valvesoftware.com/wiki/Sv_region +// 4=Asia +sv_region 4 // Write banip,banid writeid diff --git a/left4dead/cfg/server_pub_convars.cfg b/left4dead/cfg/server_pub_convars.cfg index c176f72e..88bc221b 100644 --- a/left4dead/cfg/server_pub_convars.cfg +++ b/left4dead/cfg/server_pub_convars.cfg @@ -112,7 +112,7 @@ no_escape_tank 0 //----------------------------------------- tank_control_disable 1 //----------------------------------------- -//team switch disabled after 60 seconds leave saferoom +//team switch disabled after 60 seconds leave saferoom (0=off) l4d_teamswitch_during_game_seconds_block 60 //----------------------------------------- //anti_friendly_fire diff --git a/left4dead/cfg/sourcemod/l4d_unreservelobby.cfg b/left4dead/cfg/sourcemod/l4d_unreservelobby.cfg new file mode 100644 index 00000000..6b6c325f --- /dev/null +++ b/left4dead/cfg/sourcemod/l4d_unreservelobby.cfg @@ -0,0 +1,28 @@ +// This file was auto-generated by SourceMod (v1.11.0.6968) +// ConVars for plugin "l4d_unreservelobby.smx" + + +// Automatically unreserve server after all playes have disconnected +// - +// Default: "1" +// Minimum: "0.000000" +// Maximum: "1.000000" +l4d_unreservelobby_empty "1" + +// Automatically unreserve server after server lobby reserved and full in gamemode (8 in versus/scavenge, 4 in coop/survival/realism) +// - +// Default: "1" +// Minimum: "0.000000" +// Maximum: "1.000000" +l4d_unreservelobby_full "1" + +// When player number reaches the following number, the server unreserves. +// 0 = 8 in versus/scavenge, 4 in coop/survival/realism. +// >0 = Any number greater than zero. +// - +// Default: "0" +// Minimum: "0.000000" +// Maximum: "8.000000" +l4d_unreservelobby_trigger "0" + +