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"
+
+