diff --git a/serverfiles/left4dead2/addons/sourcemod/extensions/left4downtown.autoload b/serverfiles/left4dead2/addons/sourcemod/extensions/left4downtown.autoload new file mode 100755 index 0000000..e69de29 diff --git a/serverfiles/left4dead2/addons/sourcemod/extensions/left4downtown.ext.2.l4d2.so b/serverfiles/left4dead2/addons/sourcemod/extensions/left4downtown.ext.2.l4d2.so new file mode 100755 index 0000000..4111192 Binary files /dev/null and b/serverfiles/left4dead2/addons/sourcemod/extensions/left4downtown.ext.2.l4d2.so differ diff --git a/serverfiles/left4dead2/addons/sourcemod/gamedata/abm.txt b/serverfiles/left4dead2/addons/sourcemod/gamedata/abm.txt new file mode 100644 index 0000000..ac1cee9 --- /dev/null +++ b/serverfiles/left4dead2/addons/sourcemod/gamedata/abm.txt @@ -0,0 +1,64 @@ +"Games" { + + "#default" { + "Offsets" { + "OS" { // Thank you Sammy-ROCK! + "windows" "1" + "linux" "0" + } + } + } + + // Big thanks to cravenge and Spirit_12 on AlliedModders for being awesome :D + + "left4dead2" { + "Signatures" { + "State_Transition" { + "library" "server" + "linux" "@_ZN9CCSPlayer16State_TransitionE13CSPlayerState" + "windows" "\x55\x8B\xEC\x56\x8B\xF1\x8B\x86\x2A\x2A\x2A\x2A\x57\x8B\x7D\x2A\x85\xC0\x74\x2A\x83" + /* 55 8B EC 56 8B F1 8B 86 ? ? ? ? 57 8B 7D ? 85 C0 74 ? 83 */ + } + + "TakeOverZombieBot" { + "library" "server" + "linux" "@_ZN13CTerrorPlayer17TakeOverZombieBotEPS_" + "windows" "\x55\x8B\xEC\x81\xEC\x2A\x2A\x2A\x2A\xA1\xD8\x2A\x2A\x2A\x33\xC5\x89\x45\x2A\x53\x8B\x5D\x2A\x80" + /* 55 8B EC 81 EC ? ? ? ? ? D8 ? ? ? 33 C5 89 45 ? 53 8B 5D ? 80 */ + } + + "RoundRespawn" { + "library" "server" + "linux" "@_ZN13CTerrorPlayer12RoundRespawnEv" + "windows" "\x56\x8B\xF1\xE8\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x84\xC0\x75" + /* 56 8B F1 E8 ? ? ? ? E8 ? ? ? ? 84 C0 75 */ + } + + "SetHumanSpec" { + "library" "server" + "linux" "@_ZN11SurvivorBot17SetHumanSpectatorEP13CTerrorPlayer" + "windows" "\x55\x8B\xEC\x56\x8B\xF1\x83\xBE\x2A\x2A\x2A\x2A\x00\x7E\x07\x32\xC0\x5E\x5D\xC2\x04\x00\x8B\x0D" + /* 55 8B EC 56 8B F1 83 BE ? ? ? ? 00 7E 07 32 C0 5E 5D C2 04 00 8B 0D */ + } + + //"SetHumanSpec" { // older version + // "library" "server" + // "linux" "@_ZN11SurvivorBot17SetHumanSpectatorEP13CTerrorPlayer" + // "windows" "\x55\x8B\xEC\x56\x8B\xF1\x83\xBE\x44\x43\x00\x00\x00\x7E\x07\x32\xC0\x5E\x5D\xC2\x04" + //} + + "TakeOverBot" { + "library" "server" + "linux" "@_ZN13CTerrorPlayer11TakeOverBotEb" + "windows" "\x55\x8B\xEC\x81\xEC\x2A\x2A\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x33\xC5\x89\x45\xFC\x53\x56\x8D\x85" + /* 55 8B EC 81 EC ? ? ? ? A1 ? ? ? ? 33 C5 89 45 FC 53 56 8D 85 */ + } + + //"TakeOverBot" { // older version + // "library" "server" + // "linux" "@_ZN13CTerrorPlayer11TakeOverBotEb" + // "windows" "\x55\x8B\xEC\x81\xEC\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x53\x56\x8D\x85" + //} + } + } +} diff --git a/serverfiles/left4dead2/addons/sourcemod/gamedata/left4downtown.l4d2.txt b/serverfiles/left4dead2/addons/sourcemod/gamedata/left4downtown.l4d2.txt new file mode 100644 index 0000000..28f0c63 --- /dev/null +++ b/serverfiles/left4dead2/addons/sourcemod/gamedata/left4downtown.l4d2.txt @@ -0,0 +1,1028 @@ +"Games" +{ + "left4dead2" + { + "Addresses" + { + "ZombieManager" + { + "windows" + { + "signature" "StartChangeLevel" + "read" "293" + } + "linux" + { + "signature" "TheZombieManager" + "read" "0" + } + } + "WeaponInfoDatabase" + { + "windows" + { + "signature" "ReadWeaponDataFromFileForSlot" + "read" "75" + } + "linux" + { + "signature" "WeaponInfoDatabase" + } + } + "MeleeWeaponInfoStore" + { + "windows" + { + "signature" "CTerrorPlayer_GiveNamedItem" + "read" "340" + } + "linux" + { + "signature" "CMeleeWeaponInfoStore" + } + } + + "CDirector" + { + "windows" + { + "signature" "DirectorMusicBanks_OnRoundStart" + "read" "12" + } + "linux" + { + "signature" "TheDirector" + } + } + } + "Offsets" + { + /* Offset into CDirector::AreWanderersAllowed */ + "CDirectorScavengeMode" + { + "windows" "11" /* mov ecx, [esi+offs] */ + "linux" "13" /* mov eax, [ebx+offs] */ + } + + /* Offset from ConnectClientLobbyCheck to cmp with max players check + + string #Valve_Reject_Server_Full + */ + "ValveRejectServerFullFirst" + { + "windows" "30" /* cmp eax, [esi+180h] -> cmp eax, imm32 */ + "linux" "0" /* cmp esi, [ebx+17Ch] -> cmp esi, imm32 */ + } + + /* Member variable offset into CTerrorGameRules + * + * - Look for CTerrorGameRules::GetVersusMaxCompletionScore, which is ref'd + * - by CL4DGameStats::AddSurvivorStats--unique string "CharacterId" + */ + "VersusMaxCompletionScore" + { + "windows" "3568" + "linux" "3560" + } + + /* Offset into CTerrorPlayer + * Is this right? How do we find it? + */ + "SpawnTimer" + { + "windows" "11308" + "linux" "11288" + } + } + + "Signatures" + { + + /* + * CTerrorGameRules::GetTeamScore(int,bool) + * Find "Staying on original map %s\n" + * -> CDirector::Restart(void) + * -> showed up near "info_window" + * -> called twice along with another function called twice (CterrorGameRules::UpdateChapterScores) + */ + "GetTeamScore" + { + "library" "server" + "linux" "@_ZN16CTerrorGameRules12GetTeamScoreEib" + "windows" "\x55\x8B\xEC\x8B\x2A\x2A\x85\xC0\x2A\x2A\x33\xC0\x5D\xC2" + /* 55 8B EC 8B ? ? 85 C0 ? ? 33 C0 5D C2 */ + } + + /* + * CTerrorGameRules::SetCampaignScores(int,int) + * Search for unique string "singlechapter" + * -> has two xref from same function, CTerrorGameRules::IsSingleChapterMode() + * -> has two xref, one is CRestartGameIssue::ExecuteCommand() (exclude the other, CServerGameDLL::ServerHibernationUpdate(), which has string "FCVAR_NEVER_AS_STRING") + * -> CRestartGameIssue::ExecuteCommand() calls CDirectorVersusMode::VoteRestartVersusLevel() (fourth call..?) + * -> first call is CTerrorGameRules::SetCampaignScores() + * make sure to double check uniqueness when done + */ + "SetCampaignScores" + { + "library" "server" + "linux" "@_ZN16CTerrorGameRules17SetCampaignScoresEii" + "windows" "\x55\x8B\xEC\x56\x57\x8B\x7D\x08\x8B\xF1\x39\xBE\x2A\x2A\x2A\x2A\x74\x2A\xE8\x2A\x2A\x2A\x2A\x89\xBE\x2A\x2A\x2A\x2A\x8B" + /* 55 8B EC 56 57 8B 7D 08 8B F1 39 BE ? ? ? ? 74 ? E8 ? ? ? ? 89 BE ? ? ? ? 8B */ + } + + /* + * CTerrorGameRules::ClearTeamScores(bool) + */ + "ClearTeamScores" + { + "library" "server" + "linux" "@_ZN16CTerrorGameRules15ClearTeamScoresEb" + "windows" "\x55\x8B\xEC\x51\x0F\x57\xC0\x53\x56\x57\x33\xDB\x8B" + /* 55 8B EC 51 0F 57 C0 53 56 57 33 DB 8B */ + } + + /* + * CBaseServer::SetReservationCookie(uint64_t, char*, va_list) + * - clear the reservation by setting a cookie of 0 + */ + "SetReservationCookie" + { + "library" "engine" + "linux" "@_ZN11CBaseServer20SetReservationCookieEyPKcz" + "windows" "\x55\x8B\xEC\x81\xEC\x2A\x2A\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x33\xC5\x89\x45\xFC\x53\x8B\x5D\x10\x56\x8B\x75\x08\x57\x8B\x7D\x0C\x3B" + /* 55 8B EC 81 EC ? ? ? ? A1 ? ? ? ? 33 C5 89 45 FC 53 8B 5D 10 56 8B 75 08 57 8B 7D 0C 3B */ + } + + /* + * CTerrorPlayer::TakeOverBot + * unique string "[TAKEOVER]: %s (%d) possessed %s" + */ + "TakeOverBot" + { + "library" "server" + "linux" "@_ZN13CTerrorPlayer11TakeOverBotEb" + "windows" "\x55\x8B\xEC\x81\xEC\x2A\x2A\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x33\xC5\x89\x45\xFC\x53\x56\x8D\x85" + /* 55 8B EC 81 EC ? ? ? ? A1 ? ? ? ? 33 C5 89 45 FC 53 56 8D 85 */ + } + + /* + * SurvivorBot::SetHumanSpectator(CTerrorPlayer*) + * Very similar to BossZombiePlayerBot::SetHumanSpectator() + * SurvivorBot version has 5 xref (one of them is CTerrorPlayer::TakeOverBot), BossZombie has just 1 (CTerrorPlayer::TakeOverBot) + */ + "SetHumanSpec" + { + "library" "server" + "linux" "@_ZN11SurvivorBot17SetHumanSpectatorEP13CTerrorPlayer" + "windows" "\x55\x8B\xEC\x56\x8B\xF1\x83\xBE\x2A\x2A\x2A\x2A\x00\x7E\x07\x32\xC0\x5E\x5D\xC2\x04\x00\x8B\x0D" + /* 55 8B EC 56 8B F1 83 BE ? ? ? ? 00 7E 07 32 C0 5E 5D C2 04 00 8B 0D */ + } + + /* + * CDirectorScavengeMode::OnBeginRoundSetupTime + * used to reset the setup timer during scavenge mode + * has one of five references to string "ready_countdown" + */ + "CDirectorScavengeMode_OnBeginRoundSetupTime" + { + "library" "server" + "linux" "@_ZN21CDirectorScavengeMode21OnBeginRoundSetupTimeEv" + "windows" "\x55\x8B\xEC\x83\xEC\x10\x56\x8B\xF1\xE8\x2A\x2A\x2A\x2A\x84\xC0\x74\x2A\xF3" + /* 55 8B EC 83 EC 10 56 8B F1 E8 ? ? ? ? 84 C0 74 ? F3 */ + } + + /* CTerrorGameRules::ResetRoundNumber + * used to reset the round number during scavenge mode + * Search for unique string "singlechapter" + * -> has two xref from same function, CTerrorGameRules::IsSingleChapterMode() + * -> has two xref, one is CRestartGameIssue::ExecuteCommand() (exclude the other, CServerGameDLL::ServerHibernationUpdate(), which has string "FCVAR_NEVER_AS_STRING") + * -> calls CTerrorGameRules::GetMissionFirstMap (TODO more detail on where this is) + * -> xref from CDirector::Rematch + * -> CTerrorGameRules::ResetRoundNumber is called right before CTerrorGameRules::IsVersusMode + */ + "CTerrorGameRules_ResetRoundNumber" + { + "library" "server" + "linux" "@_ZN16CTerrorGameRules16ResetRoundNumberEv" + "windows" "\x56\x8B\xF1\x83\xBE\x2A\x2A\x2A\x2A\x00\x74\x2A\xE8\x2A\x2A\x2A\x2A\xC7\x86\x2A\x2A\x2A\x2A\x00\x00\x00\x00\x5E\xC3" + /* 56 8B F1 83 BE ? ? ? ? 00 74 ? E8 ? ? ? ? C7 86 ? ? ? ? 00 00 00 00 5E C3 */ + } + + /* CTerrorGameRules::SetRoundEndTime(float) + * used to freeze the scavenge game clock + * start with unique string "scavenge_round_halftime" in function CDirectorScavengeMode::EndScavengeRound + * -> first call in CDirectorScavengeMode::EndScavengeRound + */ + "CTerrorGameRules_SetRoundEndTime" + { + "library" "server" + "linux" "@_ZN16CTerrorGameRules15SetRoundEndTimeEf" + "windows" "\x55\x8B\xEC\x56\x8B\xF1\xF3\x0F\x10\x86\x2A\x2A\x2A\x2A\x0F\x2E\x45\x08\x9F\x57" + /* 55 8B EC 56 8B F1 F3 0F 10 86 ? ? ? ? 0F 2E 45 08 9F 57 */ + } + + + /* CDirector::AreWanderersAllowed(void) + * Used to get offset for CDirectorScavengeMode + * *(director + offset) == ptr to CDirectorScavengeMode + * has unique string "AlwaysAllowWanderers" + */ + "CDirector_AreWanderersAllowed" + { + "library" "server" + "linux" "@_ZNK9CDirector19AreWanderersAllowedEv" + "windows" "\x55\x8B\xEC\x83\xEC\x2A\x56\x8B\xF1\x8B\x8E\x2A\x2A\x2A\x2A\x8D\x45\xFF" + /* 55 8B EC 83 EC ? 56 8B F1 8B 8E ? ? ? ? 8D 45 FF */ + } + + /* Used solely to get the offset for TheDirector + * CDirectorMusicBanks::OnRoundStart + * Has unique string "Event.Reveal" + */ + "DirectorMusicBanks_OnRoundStart" + { + "library" "server" + "windows" "\x55\x8B\xEC\x83\xEC\x2A\x56\x57\x8B\xF9\x8B\x0D\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x84" + /* 55 8B EC 83 EC ? 56 57 8B F9 8B 0D ? ? ? ? E8 ? ? ? ? 84 */ + + } + + /* Find the Director/ZombieManager singleton classes */ + + "TheDirector" + { + "library" "server" + "linux" "@TheDirector" + } + + "TheZombieManager" + { + "library" "server" + "linux" "@TheZombieManager" + } + + /* Find the WeaponInfo Database dictionary */ + "WeaponInfoDatabase" + { + "library" "server" + "linux" "@_ZL20m_WeaponInfoDatabase" + } + + /* We can find the WeaponInfoDatabase location in this sub on windows + * + * - Look for "scripts/%s", should be the ref that's furthest into a func. + * OR + * Look for unique string "scripts/weapon_manifest.txt", then look in same func for almost unique string "Expecting 'file', got %s\n", should be two calls before that string + */ + "ReadWeaponDataFromFileForSlot" + { + "library" "server" + "windows" "\x55\x8B\xEC\x81\xEC\x2A\x2A\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x33\xC5\x89\x45\xFC\x8B\x45\x14\x53\x8B\x5D\x10" + /* 55 8B EC 81 EC ? ? ? ? A1 ? ? ? ? 33 C5 89 45 FC 8B 45 14 53 8B 5D 10 */ + } + + /* Find the Melee Weapon Info dictionary */ + "CMeleeWeaponInfoStore" + { + "library" "server" + "linux" "@g_MeleeWeaponInfoStore" + } + + /* We can find the CMeleeWeaponInfo location in this sub on windows + * + * - "NULL Ent '%s' in GiveNamedItem!\n" is unique in thie function + * - There are at least 3 calls using the g_MeleeWeaponInfoStore here--use some brain for offset. + */ + "CTerrorPlayer_GiveNamedItem" + { + "library" "server" + "windows" "\x55\x8B\xEC\x81\xEC\x2A\x2A\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x33\xC5\x89\x45\xFC\x8B\x45\x14\x53\x8B\x5D\x08" + /* 55 8B EC 81 EC ? ? ? ? A1 ? ? ? ? 33 C5 89 45 FC 8B 45 14 53 8B 5D 08 */ + } + + /* + * CDirector::RestartScenarioFromVote(const char*) + * Search for unique string "singlechapter" + * -> has two xref from same function, CTerrorGameRules::IsSingleChapterMode() + * -> has two xref, one is CRestartGameIssue::ExecuteCommand() (exclude the other, CServerGameDLL::ServerHibernationUpdate(), which has string "FCVAR_NEVER_AS_STRING") + * -> Last call in CRestartGameIssue::ExecuteCommand + */ + "RestartScenarioFromVote" + { + "library" "server" + "linux" "@_ZN9CDirector23RestartScenarioFromVoteEPKc" + "windows" "\x55\x8B\xEC\x56\x8B\xF1\x8B\x0D\x2A\x2A\x2A\x2A\x57\x85" + /* 55 8B EC 56 8B F1 8B 0D ? ? ? ? 57 85 */ + } + + /* + * ZombieManager::SpawnSpecial(ZombieClassType, Vector const&, QAngle const&) + * Be careful, there are a few overrides for SpawnSpecial + * Make sure the one you have has like 11 xrefs, 6 from CCommentaryZombieSpawner::InputSpawnZombie + * To find, look for non-unique string "common_", has three refs, one ref will have strings for all classes, that's CCommentaryZombieSpawner::InputSpawnZombie + */ + "SpawnSpecial" + { + "library" "server" + "linux" "@_ZN13ZombieManager12SpawnSpecialE15ZombieClassTypeRK6VectorRK6QAngle" + "windows" "\x55\x8B\xEC\x53\x8B\x5D\x08\x8D\x43\xFF\x56" + /* 55 8B EC 53 8B 5D 08 8D 43 FF 56 */ + } + + /* + * ZombieManager::SpawnTank(Vector const&, QAngle const&) + * + * find by Navarea variant method and "Failed to find a tank spawn position i" + * OR + * To find, look for non-unique string "common_", has three refs, one ref will have strings for all classes, that's CCommentaryZombieSpawner::InputSpawnZombie + * SpawnTank will be called after string "tank" + */ + "SpawnTank" + { + "library" "server" + "linux" "@_ZN13ZombieManager9SpawnTankERK6VectorRK6QAngle" + "windows" "\x55\x8B\xEC\x57\x8B\xF9\x8B\x0D\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x85\xC0\x78\x2A\x8B\x0D\x2A\x2A\x2A\x2A\x39" + /* 55 8B EC 57 8B F9 8B 0D ? ? ? ? E8 ? ? ? ? 85 C0 78 ? 8B 0D ? ? ? ? 39 */ + } + + /* + * ZombieManager::SpawnWitch(Vector const&, QAngle const&) + * + * find by Navarea variant method and "Failed to find a witch spawn position i" + * OR + * To find, look for non-unique string "common_", has three refs, one ref will have strings for all classes, that's CCommentaryZombieSpawner::InputSpawnZombie + * SpawnWitch will be called after string "witch" + */ + "SpawnWitch" + { + "library" "server" + "linux" "@_ZN13ZombieManager10SpawnWitchERK6VectorRK6QAngle" + "windows" "\x55\x8B\xEC\x8B\x0D\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x85\xC0\x78\x2A\x8B\x0D\x2A\x2A\x2A\x2A\x39\x81" + /* 55 8B EC 8B 0D ? ? ? ? E8 ? ? ? ? 85 C0 78 */ + } + + /* + * ZombieManager::SpawnWitchBride(Vector const&, QAngle const&) + * Has three xref, one is CInfoZombieSpawn::SpawnZombie (shared with SpawnWitch above) + * where SpawnWitch is the third call after string "bride", and SpawnWitchBride is the second call after "bride" + */ + "SpawnWitchBride" + { + "library" "server" + "linux" "@_ZN13ZombieManager15SpawnWitchBrideERK6VectorRK6QAngle" + "windows" "\x55\x8B\xEC\x8B\x0D\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x85\xC0\x75" + /* 55 8B EC 8B 0D ? ? ? ? E8 ? ? ? ? 85 C0 75 */ + } + + /* + * CDirectorVersusMode::OnVersusRoundStarted() + * Unused? Nothing in source accesses this signature + * Last call in CDirector::OnFirstSurvivorLeftSafeArea() + * Also has string "versus_round_start" + */ + "OnVersusRoundStarted" + { + "library" "server" + "linux" "@_ZN19CDirectorVersusMode20OnVersusRoundStartedEv" + "windows" "\x8B\x0D\x2A\x2A\x2A\x2A\x85\xC9\x74\x2A\xA1\x2A\x2A\x2A\x2A\xF3\x0F\x2A\x2A\x2A\x51\xF3\x0F\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x8B" + /* 8B 0D ? ? ? ? 85 C9 74 ? A1 ? ? ? ? F3 0F ? ? ? 51 F3 0F ? ? ? E8 ? ? ? ? 8B */ + } + + /* + * CDirector::OnFirstSurvivorLeftSafeArea(CTerrorPlayer *) + * + * string "Allowing spawning - %s left safe area\n" + */ + "OnFirstSurvivorLeftSafeArea" + { + "library" "server" + "linux" "@_ZN9CDirector27OnFirstSurvivorLeftSafeAreaEP13CTerrorPlayer" + "windows" "\x55\x8B\xEC\x83\xEC\x2A\x56\x57\x8B\x7D\x2A\x8B\xF1\x8B\x8E\x2A\x2A\x2A\x2A\x57\xE8" + /* 55 8B EC 83 EC ? 56 57 8B 7D ? 8B F1 8B 8E ? ? ? ? 57 E8 */ + } + + /* + * CDirector::GetScriptValue(const char*, int) + * Find CTerrorPlayer::OnRevived(), then look for string SurvivorMaxIncapacitatedCount + * If you look for string "No conversion from %s to int now\n" you will be one call too deep + */ + "CDirector_GetScriptValueInt" + { + "library" "server" + "linux" "@_ZN9CDirector14GetScriptValueEPKci" + "windows" "\x55\x8B\xEC\x8B\x81\x2A\x2A\x2A\x2A\x83\xEC\x10\x83\xF8\xFF\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x8B\x45\x2A\x8B" + /* 55 8B EC 8B 81 ? ? ? ? 83 EC 10 83 F8 FF ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 8B 45 ? 8B */ + } + + /* + * CDirector::GetScriptValue(const char*, float) + * Called in CDirector::OnMobRushStart + */ + "CDirector_GetScriptValueFloat" + { + "library" "server" + "linux" "@_ZN9CDirector14GetScriptValueEPKcf" + "windows" "\x55\x8B\xEC\x8B\x81\x2A\x2A\x2A\x2A\x83\xEC\x10\x83\xF8\xFF\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\xD9" + /* 55 8B EC 8B 81 ? ? ? ? 83 EC 10 83 F8 FF ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? D9 */ + } + + /* + * CDirector::GetScriptValue(const char*, const char*, char*, int) + * unique string "OnChangeFinaleMusic", call right after it + */ + "CDirector_GetScriptValueString" + { + "library" "server" + "linux" "@_ZN9CDirector14GetScriptValueEPKcS1_Pci" + "windows" "\x55\x8B\xEC\x8B\x81\x2A\x2A\x2A\x2A\x83\xEC\x2A\x56\x8B" + /* 55 8B EC 8B 81 ? ? ? ? 83 EC ? 56 8B */ + } + + /* + * CDirector::IsFinaleEscapeInProgress(void) + * unique string "#L4D_idle_spectator" in CTerrorPlayer::PreThink() + * CDirector::IsFinaleEscapeInProgress is a couple calls before the string, and a couple calls after CountdownTimer::Now + */ + "CDirector_IsFinaleEscapeInProgress" + { + "library" "server" + "linux" "@_ZNK9CDirector24IsFinaleEscapeInProgressEv" + "windows" "\x8B\x81\x2A\x2A\x2A\x2A\x83\x38\x2A\x75\x03\x32\xC0\xC3\x33\xC0\x83\xB9\x2A\x2A\x2A\x2A\x02\x0F\x94\xC0\xC3" + /* 8B 81 ? ? ? ? 83 38 ? 75 03 32 C0 C3 33 C0 83 B9 ? ? ? ? 02 0F 94 C0 C3 */ + } + + /* + * CTerrorPlayer::CanBecomeGhost(bool areSpawnsDisabled) + * unique string "ghost_spawn_time" + */ + "CTerrorPlayer_CanBecomeGhost" + { + "library" "server" + "linux" "@_ZN13CTerrorPlayer14CanBecomeGhostEb" + "windows" "\x53\x8B\xDC\x83\xEC\x2A\x83\xE4\xF0\x83\xC4\x2A\x55\x8B\x6B\x04\x89\x6C\x24\x04\x8B\xEC\x83\xEC\x2A\x56\x57\x8B\xF1\xE8\x0E" + /* 53 8B DC 83 EC ? 83 E4 F0 83 C4 ? 55 8B 6B 04 89 6C 24 04 8B EC 83 EC ? 56 57 8B F1 E8 0E */ + } + + /* + * CTerrorPlayer::OnEnterGhostState() + * almost unique string spawnmode_bar has three refs, one ref has strings "zombieClass" and "data" + */ + "CTerrorPlayer_OnEnterGhostState" + { + "library" "server" + "linux" "@_ZN13CTerrorPlayer17OnEnterGhostStateEv" + "windows" "\x55\x8B\xEC\x83\xEC\x08\x53\x56\x8B\xF1\x8B\x86\x2A\x2A\x2A\x2A\x8B" + /* 55 8B EC 83 EC 08 53 56 8B F1 8B 86 ? ? ? ? 8B */ + } + + /* + * CDirector::IsFinale(void)const + */ + "CDirector_IsFinale" + { + "library" "server" + "linux" "@_ZNK9CDirector8IsFinaleEv" + "windows" "\x8B\x81\x2A\x2A\x2A\x2A\x33\xC9\x83\x38\x2A\x0F\x95\xC0\xC3" + /* 8B 81 ? ? ? ? 33 C9 83 38 ? 0F 95 C0 C3 */ + } + + /* + * CDirector::TryOfferingTankBot(void) + * unique string "Tank offer: Starting the lottery\n" + */ + "TryOfferingTankBot" + { + "library" "server" + "linux" "@_ZN9CDirector18TryOfferingTankBotEP11CBaseEntityb" + "windows" "\x55\x8B\xEC\x51\x83\x7D\x08\x00\x56\x8B\xF1\x89" + /* 55 8B EC 51 83 7D 08 00 56 8B F1 89 */ + } + + /* + * CDirector::OnMobRushStart(void) - used by boomer and natural horde functions. Resets natural horde timer. + * + * find by String: "MobMinSize", its inlined in Windows + */ + "OnMobRushStart" + { + "library" "server" + "linux" "@_ZN9CDirector14OnMobRushStartEv" + "windows" "\x55\x8B\xEC\x83\xEC\x08\xA1\x2A\x2A\x2A\x2A\xF3\x0F\x10\x40\x2A\x56\x57\x51" + /* 55 8B EC 83 EC 08 A1 ? ? ? ? F3 0F 10 40 ? 56 57 51 */ + } + + /* + * ZombieManager::SpawnITMob(int) - used for bile hordes, increases spawn count + * + * search for unique strings with "SpawnITMob" + */ + "Zombiemanager_SpawnITMob" + { + "library" "server" + "linux" "@_ZN13ZombieManager10SpawnITMobEi" + "windows" "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\xF3\x0F\x10\x40\x2A\x56\x57" + /* 55 8B EC A1 ? ? ? ? F3 0F 10 40 ? 56 57 */ + } + + /* + * ZombieManager::SpawnMob(int) - used for natural/z_spawn + * hordes, increases spawn count and calls horde music, etc + * + * search for unique strings with "SpawnMob" + */ + "Zombiemanager_SpawnMob" + { + "library" "server" + "linux" "@_ZN13ZombieManager8SpawnMobEi" + "windows" "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\xF3\x0F\x10\x40\x2A\x83\xEC\x2A\x53\x56\x57" + /* 55 8B EC A1 ? ? ? ? F3 0F 10 40 ? 83 EC ? 53 56 57 */ + } + + /* + * CTerrorPlayer::OnStaggered(CBaseEntity *, Vector const*) - used by L4D2 on Survivors, causes staggering (e.g. Charger Impact nearby) + * + * - string "PlayerShoved" has 3 refs, the one furthest into a function should be this one. + */ + "CTerrorPlayer_OnStaggered" + { + "library" "server" + "linux" "@_ZN13CTerrorPlayer11OnStaggeredEP11CBaseEntityPK6Vector" + "windows" "\x53\x8B\xDC\x83\xEC\x2A\x83\xE4\xF0\x83\xC4\x04\x55\x8B\x6B\x04\x89\x6C\x24\x04\x8B\xEC\x83\xEC\x2A\x56\x57\x8B\xF1\xE8\x2A\x2A\x2A\x2A\x84\xC0\x0F\x85\x73\x08" + /* 53 8B DC 83 EC ? 83 E4 F0 83 C4 04 55 8B 6B 04 89 6C 24 04 8B EC 83 EC ? 56 57 8B F1 E8 ? ? ? ? 84 C0 0F 85 73 08 + * Using a long local jump as the unique portion (last few bytes of sig) + */ + } + + /* + * CTerrorPlayer::OnShovedBySurvivor(CTerrorPlayer*, Vector const&) - used by L4D2 on Special Infected (got melee'd) + * unique string "jockey_ride" in CTerrorPlayer::OnLeptOnSurvivor(), look up for "JockeyZombie.Ride", look up for var_14, CTerrorPlayer::OnShovedBySurvivor is call after that + */ + "CTerrorPlayer_OnShovedBySurvivor" + { + "library" "server" + "linux" "@_ZN13CTerrorPlayer18OnShovedBySurvivorEPS_RK6Vector" + "windows" "\x55\x8B\xEC\x81\xEC\x2A\x2A\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x33\xC5\x89\x45\xFC\x53\x8B\x5D\x0C\x56\x57\x8B\x7D\x08\x8B\xF1" + /* 55 8B EC 81 EC ? ? ? ? A1 ? ? ? ? 33 C5 89 45 FC 53 8B 5D 0C 56 57 8B 7D 08 8B F1 */ + } + + /* + * CTerrorPlayer::GetWalkTopSpeed(void)const + * an xref from GetRunTopSpeed + */ + "CTerrorPlayer_GetWalkTopSpeed" + { + "library" "server" + "linux" "@_ZNK13CTerrorPlayer15GetWalkTopSpeedEv" + "windows" "\x56\x8B\xF1\x80\x2A\x2A\x2A\x2A\x2A\x2A\x74\x2A\x5E\xE9\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x50\xE8" + /* 56 8B F1 80 ? ? ? ? ? ? 74 ? 5E E9 ? ? ? ? E8 ? ? ? ? 50 E8 */ + } + + /* + * CTerrorPlayer::GetRunTopSpeed(void)const + * + * - Only references to float value 115.0 (00 00 E6 42) are in this func. + */ + "CTerrorPlayer_GetRunTopSpeed" + { + "library" "server" + "linux" "@_ZNK13CTerrorPlayer14GetRunTopSpeedEv" + "windows" "\x55\x8B\xEC\x83\xEC\x2A\x56\x8B\xF1\x8B\x06\x8B\x90\x2A\x2A\x2A\x2A\xFF\xD2\x84\xC0\x74\x0D\xA1\x2A\x2A\x2A\x2A\xD9\x40\x2A\x5E" + /* 55 8B EC 83 EC ? 56 8B F1 8B 06 8B 90 ? ? ? ? FF D2 84 C0 74 0D A1 ? ? ? ? D9 40 ? 5E */ + } + + /* + * CTerrorPlayer::GetCrouchTopSpeed(void)const + * an xref from GetRunTopSpeed + */ + "CTerrorPlayer_GetCrouchTopSpeed" + { + "library" "server" + "linux" "@_ZNK13CTerrorPlayer17GetCrouchTopSpeedEv" + "windows" "\x56\x8B\xF1\x80\x2A\x2A\x2A\x2A\x2A\x2A\x74\x2A\x5E\xE9\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x83\xF8" + /* 56 8B F1 80 ? ? ? ? ? ? 74 ? 5E E9 ? ? ? ? E8 ? ? ? ? 83 F8 */ + } + + /* + * CTerrorPlayer::OnRevived(void) + * + * ->Search for string "revive_success", then open vtables window. Should be the 5th member. + * Left4Downtown2 patches this function, which will prevent Sourcemod from finding it + * That is why the first six bytes are wild cards (five bytes for detour + nop fill the remaining bytes of the instructions) + */ + "CTerrorPlayer_OnRevived" + { + "library" "server" + "linux" "@_ZN13CTerrorPlayer9OnRevivedEv" + "windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x53\x56\x8B\xF1\x8B\x06\x8B\x90\x2A\x2A\x2A\x2A\x57\xff\xd2\x84\xc0\x0f\x84\x2A\x2A\x2A\x2A\x8B\xCE" + /* ? ? ? ? ? ? 53 56 8B F1 8B 06 8B 90 ? ? ? ? 57 ff d2 84 c0 0f 84 ? ? ? ? 8B CE */ + } + + /* + * GetDifficulty(void) + */ + "GetDifficulty" + { + "library" "server" + "linux" "@_Z13GetDifficultyv" + "windows" "\xA1\x2A\x48\x7A\x10\xC3" + /* A1 ? 48 7A 10 C3 */ + } + + /* + * CTerrorGameRules::HasConfigurableDifficultySetting(void) + * + * - Look for string "hasdifficulty" + */ + "HasConfigurableDifficulty" + { + "library" "server" + "linux" "@_ZN16CTerrorGameRules32HasConfigurableDifficultySettingEv" + "windows" "\x8B\x0D\x2A\x2A\x2A\x2A\x85\xC9\x75\x1B\xE8\x2A\x2A\x2A\x2A\x84" + /* 8B 0D ? ? ? ? 85 C9 75 1B E8 ? ? ? ? 84 */ + } + + /* + * CTerrorGameRules::GetSurvivorSet(void) + * + * - string "survivor_set" + */ + "GetSurvivorSet" + { + "library" "server" + "linux" "@_ZN16CTerrorGameRules14GetSurvivorSetEv" + "windows" "\x55\x8B\xEC\x51\x8B\x0D\x2A\x2A\x2A\x2A\x8B\x01\x8B\x50\x2A\x53" + /* 55 8B EC 51 8B 0D ? ? ? ? 8B 01 8B 50 ? 53 */ + } + + /* + * CTerrorGameRules::FastGetSurvivorSet(void) + * + * - Should be 2 calls after "DistToMechanic" in CTerrorPlayer::ModifyOrAppendCriteria + */ + "FastGetSurvivorSet" + { + "library" "server" + "linux" "@_ZN16CTerrorGameRules18FastGetSurvivorSetEv" + "windows" "\xA1\x2A\x2A\x2A\x2A\x85\xC0\x75\x0A\xE8" + /* A1 ? ? ? ? 85 C0 75 0A E8 */ + } + + /* + * CDirectorVersusMode::GetMissionVersusBossSpawning(float&, float&, float&, float&) + * + * - string "versus_boss_spawning" hits in 2 functions: This short func and the much longer InitVersusBossSpawning + */ + + "GetMissionVersusBossSpawning" + { + "library" "server" + "linux" "@_ZN19CDirectorVersusMode28GetMissionVersusBossSpawningERfS0_S0_S0_" + "windows" "\x55\x8B\xEC\x6A\x00\xE8\x2A\x2A\x2A\x2A\x83\xC4\x04\x85" + /* 55 8B EC 6A 00 E8 ? ? ? ? 83 C4 04 85 */ + } + + /* + * CTerrorGameRules::GetMissionCurrentMap(KeyValues **) + * + * - Look for string "chapter" (unique on windows only) in CDirector:OnMapLoaded. + * - Function called right before that with 0 as arg. + * NOTE/WARNING: This function is incredibly non-unique!!!! Replace with a native implementation!! + */ + "GetMissionCurrentMap" + { + "library" "server" + "linux" "@_ZN16CTerrorGameRules20GetMissionCurrentMapEPP9KeyValues" + "windows" "\x55\x8B\xEC\x56\x57\x8B\x7D\x08\x85\xFF\x74\x06\xC7\x07\x00\x00\x00\x00\x8B\x0D\x2A\x2A\x2A\x2A\x8B\x01\x8B\x50\x28\xFF\xD2\x8B\x10\x8B\xC8\x8B\x42\x04\x6A\x00\xFF\xD0\x8B\xF0\x85\xF6\x75\x04\x5F\x5E\x5D\xC3\x8B\x0D\x2A\x2A\x2A\x2A\x8B\x11\x8B\x42\x08\x57\x56\xFF\xD0\x8B" + /* + * 68 byte signature. Fuck me. + * 55 8B EC 56 57 8B 7D 08 85 FF 74 06 C7 07 00 00 00 00 8B 0D ? ? ? ? 8B 01 8B 50 28 FF D2 8B 10 8B C8 8B 42 04 6A 00 FF D0 8B F0 85 F6 75 04 5F 5E 5D C3 8B 0D ? ? ? ? 8B 11 8B 42 08 57 56 FF D0 8B + */ + } + + /* + * CThrow::ActivateAbililty() + * Start a tank rock throw + * + * - "HulkZombie.Throw.Fail" has 2 refs in this function. Should be easy to find. + */ + "CThrowActivate" + { + "library" "server" + "linux" "@_ZN6CThrow15ActivateAbilityEv" + "windows" "\x55\x8B\xEC\x51\x53\x8B\xD9\x8B\x83\x2A\x2A\x2A\x2A\x83" + /* 55 8B EC 51 53 8B D9 8B 83 ? ? ? ? 83 */ + } + + /* + * CTerrorMeleeWeapon::StartMeleeSwing(CTerrorPlayer *, bool) + * + * find "melee attack failed - !IsWeaponVisible" in CTerrorWeapon::PrimaryAttack and look for a call (being passed ptr and float) followed by some sse xmm0 calls. + */ + "StartMeleeSwing" + { + "library" "server" + "linux" "@_ZN18CTerrorMeleeWeapon15StartMeleeSwingEP13CTerrorPlayerb" + "windows" "\x55\x8B\xEC\x53\x56\x8B\xF1\x8B\x86\x2A\x2A\x2A\x2A\x50\xB9" + /* 55 8B EC 53 56 8B F1 8B 86 ? ? ? ? 50 B9 */ + } + + /* + * CDirectorScriptedEventManager::SendInRescueVehicle(void) + * + * find by String "FinaleEscapeStarted" + */ + "SendInRescueVehicle" + { + "library" "server" + "linux" "@_ZN29CDirectorScriptedEventManager19SendInRescueVehicleEv" + "windows" "\x55\x8B\xEC\x83\xEC\x18\x56\x68\x2A\x2A\x2A\x2A\x8B\xF1" + /* 55 8B EC 83 EC 18 56 68 ? ? ? ? 8B F1 */ + } + + /* + * CDirectorScriptedEventManager__ChangeFinaleStage(int, char arg, int) + * or CDirectorScriptedEventManager::ChangeFinaleStage(CDirectorScriptedEventManager::FinaleStageType,char const*) + * + * find by String "CHANGEFINALESTAGEOVERRIDE: %s\n" + */ + "ChangeFinaleStage" + { + "library" "server" + "linux" "@_ZN29CDirectorScriptedEventManager17ChangeFinaleStageENS_18ScriptedEventStageEPKc" + "windows" "\x55\x8B\xEC\x81\xEC\x2A\x2A\x00\x00\xA1\x2A\x2A\x2A\x2A\x33\xC5\x89\x45\xFC\x53\x8B\x5D\x08\x56\x8B\x75\x0C\x57\x53" + /* 55 8B EC 81 EC ? ? 00 00 A1 ? ? ? ? 33 C5 89 45 FC 53 8B 5D 08 56 8B 75 0C 57 53 */ + } + + /* + * CDirectorVersusMode::EndVersusModeRound(bool) + * Updates scores using a bunch of CTerrorGameRules calls and triggers the fullscreen_vs_scoreboard viewport panel + * + * find by String "fullscreen_vs_scoreboard", and look for a func which also creates a "scores" kv and sets values for "t1", "t2", "c1", "c2", and "tiebreak" + */ + "EndVersusModeRound" + { + "library" "server" + "linux" "@_ZN19CDirectorVersusMode18EndVersusModeRoundEb" + "windows" "\x55\x8B\xEC\x83\xEC\x2A\x57\x8B\xF9\xE8\x2A\x2A\x2A\x2A\x84\xC0\x0F\x84" + /* 55 8B EC 83 EC ? 57 8B F9 E8 ? ? ? ? 84 C0 0F 84 */ + } + + /* + * int CBaseAnimating::SelectWeightedSequence(int Activity) + * + * - Called at the end of CTerrorPlayer::SelectWeightedSequence() (found via string "Hulk_RunAttack1_Gesture") + * NOTE - WARNING - This function should probably be hooked using vtable methods!!!!!!!! DEPRECATE + */ + "SelectWeightedSequence" + { + "library" "server" + "linux" "@_ZN14CBaseAnimating22SelectWeightedSequenceE8Activity" + "windows" "\x55\x8B\xEC\x56\x8B\xF1\x83\xBE\x2A\x2A\x2A\x2A\x00\x57\x8B\xBE" + /* 55 8B EC 56 8B F1 83 BE ? ? ? ? 00 57 8B BE */ + } + + /* + * InfoChangelevel::StartChangeLevel(Checkpoint const*) + * + * Used for finding ZombieManager on Windows + * - String "Would change level, but not going to!\n" is unique to this function + */ + "StartChangeLevel" + { + "library" "server" + "linux" "@_ZN15InfoChangelevel16StartChangeLevelEPK10Checkpoint" + "windows" "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\x83\x78\x30\x00\x56\x8B\xF1\x74" + /* 55 8B EC A1 ? ? ? ? 83 78 30 00 56 8B F1 74 */ + } + + /* + * SurvivorBot::UseHealingItems(Action *) + * Called by the game when deciding whether the bots should use any healing items + * unique string "Trying to heal a friend" + */ + "UseHealingItems" + { + "library" "server" + "linux" "@_ZN11SurvivorBot15UseHealingItemsEP6ActionIS_E" + "windows" "\x55\x8B\xEC\x83\xEC\x20\x53\x56\x8B\xD9\x57\x8D\x8B" + /* 55 8B EC 83 EC 20 53 56 8B D9 57 8D 8B */ + } + + /* + * SurvivorBot::FindScavengeItem(float) + * Called by the game when deciding what items a bot should attempt to pick up + * Despite name, has nothing to do with scavenge game mode + * SurvivorBot::ScavengeNearbyItems(Action*) has almost unique string "Scavenging something" + * FindScavengeItem(float) is called with 420.0 (0x43D20000) as its argument + */ + "FindScavengeItem" + { + "library" "server" + "linux" "@_ZNK11SurvivorBot16FindScavengeItemEf" + "windows" "\x55\x8B\xEC\x81\xEC\x2A\x2A\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x33\xC5\x89\x45\xFC\x53\x56\x57\x8B\xF9\x8B\x97\x2A\x2A\x2A\x2A\x8D\x85" + /* 55 8B EC 81 EC ? ? ? ? A1 ? ? ? ? 33 C5 89 45 FC 53 56 57 8B F9 8B 97 ? ? ? ? 8D 85 */ + } + + /* + * CTerrorWeapon::OnHit(CGameTrace &, Vector const&, bool) + */ + "CTerrorWeapon__OnHit" + { + "library" "server" + "linux" "@_ZN13CTerrorWeapon5OnHitER10CGameTraceRK6Vectorb" + "windows" "" + } + + /* + * CBasePlayer::WaterMove(void) + */ + "WaterMove" + { + "library" "server" + "linux" "@_ZN11CBasePlayer9WaterMoveEv" + "windows" "" + } + + /* + * KeyValues *CTerrorGameRules::GetMissionInfo(void) + */ + "CTerrorGameRules__GetMissionInfo" + { + "library" "server" + "linux" "@_ZN16CTerrorGameRules14GetMissionInfoEv" + "windows" "" + } + +/********************************************************************* +********************* ADDONS DISABLER ******************************** +*********************************************************************/ + /* + * CBaseServer::FillServerInfo(SVC_ServerInfo *) + */ + "CBaseServer__FillServerInfo" + { + "library" "engine" + "linux" "@_ZN11CBaseServer14FillServerInfoER14SVC_ServerInfo" + "windows" "" + } + + /* + * mov esi+[19h] + */ + "VanillaModeOffset" + { + "library" "engine" + "linux" "\xC6\x46\x1B\x4C\x88\x46\x19" + "windows" "" + } + +/********************************************************************* +****************** PLAYER SLOTS PATCHING ***************************** +*********************************************************************/ + + /* + * CTerrorGameRules::GetMaxHumanPlayers(void) + * We just override the return value to our own + * + * This method is called for max players when viewing server info + * Overriding this on Linux changes the server browser maxplayers + * + * On Windows overriding it doesn't fix the server browser, + * but it does break scavenge mode (like the map doesn't support scavenge) + * + * Find via string "playercontrolledzombies", unique in Linux, inlined a few times in Windows + * look for an inline that is very short and returns either 8 or 4 as a result + * Commented out since the note above suggests it breaks scavenge? + * Since it is inlined, its signature will look a LOT like CTerrorGameRules::HasPlayerControlledZombies() + * this sig is probably also excessively wild carded (lots of very short local jumps that are probably safe) + */ + "GetMaxHumanPlayers" + { + "library" "server" + "linux" "@_ZNK16CTerrorGameRules18GetMaxHumanPlayersEv" +// "windows" "\xF7\x05\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x74\x2A\xB8\x2A\x2A\x2A\x2A\xEB\x2A\xA1\x2A\x2A\x2A\x2A\x8B\x40\x2A\x85\xC0\x75\x2A\xB8\x2A\x2A\x2A\x2A\x8B\x2A\x2A\x2A\x2A\x2A\x8B\x11\x50\x8B\x2A\x2A\xFF\xD0\x85\xC0\x74\x2A\x6A\x00\x68\x2A\x2A\x2A\x2A\x8B\xC8\xE8\x2A\x2A\x2A\x2A\x85\xC0\xB8" + /* F7 05 ? ? ? ? ? ? ? ? 74 ? B8 ? ? ? ? EB ? A1 ? ? ? ? 8B 40 ? 85 C0 75 ? B8 ? ? ? ? 8B ? ? ? ? ? 8B 11 50 8B ? ? FF D0 85 C0 74 ? 6A 00 68 ? ? ? ? 8B C8 E8 ? ? ? ? 85 C0 B8 */ + } + + /* + * Total Number of Players Supported (Steam Group/Lobby) + * Currently disabled - SourceMod unable to look up other libraries. + * + "GetTotalNumPlayersSupported" + { + "library" "matchmaking_ds" + "linux" "@_ZN11CMatchTitle27GetTotalNumPlayersSupportedEv" + } + */ + + /* CServerGameClients::GetPlayerLimits(int& , int&, int&) + * Sig is still broken, cannot find in Windows + */ + "GetPlayerLimits" + { + "library" "server" + "linux" "@_ZNK18CServerGameClients15GetPlayerLimitsERiS0_S0_" +// "windows" "\x8B\x44\x24\x04\x8B\x4C\x24\x08\xC7\x00\x2A\x2A\x2A\x2A\xC7\x01\x2A\x2A\x2A\x2A\x8B\x10" + /* 8B 44 24 04 8B 4C 24 08 C7 00 ? ? ? ? C7 01 ? ? ? ? 8B 10 */ + } + + /* + * int CBaseServer::GetMasterServerPlayerCounts(int &, int &, int &) + * + * Used to override server browser maxplayers reporting (Windows) + * Search for string: "increased_maxplayers", call is just before the string + */ + "GetMasterServerPlayerCounts" + { + "library" "engine" + "linux" "@_ZN11CBaseServer27GetMasterServerPlayerCountsERiS0_S0_" + "windows" "\x55\x8B\xEC\x56\x8B\xF1\xE8\x2A\x2A\x2A\x2A\x8B\x4D\x2A\x89\x01\x8B\x0D\x2A\x2A\x2A\x2A\x85\xC9\x74" + /* windows: 55 8B EC 56 8B F1 E8 ? ? ? ? 8B 4D ? 89 01 8B 0D ? ? ? ? 85 C9 74 */ + } + + /* Not an actual function, + this is inside CBaseServer::ConnectClient (a jz instruction) + + use it to remove skippable code when sv_allow_lobby_connect 0 + */ + "ConnectClientLobbyCheck" + { + /* look for jz between "#Valve_Reject_Server_Full" and "#Valve_Reject_Bad_Password" in Windows + * On Linux, this points directy at the cmp for "#Valve_Reject_Server_Full" instead of the jz for the lobby + * For 2.1.2.5 this offset was ebx+17Ch on Linux and esi+180h on Windows */ + "library" "engine" + "linux" "\x3B\xB3\x2A\x2A\x2A\x2A\x0F\x8E\x2A\x2A\x2A\x2A\x8B\x03\xC7\x44\x24\x08\x2A\x2A\x2A\x2A\x89" + /* 3B B3 ? ? ? ? 0F 8E ? ? ? ? 8B 03 C7 44 24 08 ? ? ? ? 89 */ + + "windows" "\x74\x2A\x8B\x55\x2A\x8B\x06\x8B\x7A\x2A\x8B\x50" + /* windows: 74 ? 8B 55 ? 8B 06 8B 7A ? 8B 50 */ + } + + + /* Not an actual function, + This rejects players when there are all full human players + + jl just before string "Human player limit reached (%d/%d)" + + deprecated on linux: This function checks GetMaxHumanPlayers + on linux, so patching this to an unconditional jump + removes a check on maxplayers. + */ + "HumanPlayerLimitReached" + { + "library" "server" +// "linux" "\x7E\x2A\x8B\x2A\x2A\x89\x2A\x2A\x2A\x8B\x2A\x2A\x89\x2A\x2A\x2A\x8B\x2A\x2A\x89\x2A\x2A\x2A\x8B\x2A\x2A\x89\x2A\x2A\x2A\x8B\x2A\x2A\x89\x2A\x2A\x2A\x8B\x2A\x2A" + /* linux: 7E ? 8B ? ? 89 ? ? ? 8B ? ? 89 ? ? ? 8B ? ? 89 ? ? ? 8B ? ? 89 ? ? ? 8B ? ? 89 ? ? ? 8B ? ? */ + "windows" "\x7C\x2A\x8B\x4D\x2A\x8B\x55\x2A\x50\x57\x68" + /* windows: 7C ? 8B 4D ? 8B 55 ? 50 57 68 */ + } + +/********************************************************************* +****************** MISC USEFUL NATIVES ******************************* +*********************************************************************/ + + /* CTerrorGameRules::IsMissionFinalMap() + Uses campaign mission file to determine if the current map + is a Final(e) map. + Called from CDirectorVersusMode::EndVersusModeRound(), look near string "versus_match_finished" + */ + "IsMissionFinalMap" + { + "library" "server" + "linux" "@_ZN16CTerrorGameRules17IsMissionFinalMapEv" + "windows" "\x8B\x0D\x2A\x2A\x2A\x2A\x8B\x01\x8B\x50\x28\x56\xFF\xD2\x8B\x10\x8B\xC8\x8B\x42\x04\x6A\x00\xFF\xD0\x8B\xF0\x85\xF6\x75\x04\xB0" + /* 8B 0D ? ? ? ? 8B 01 8B 50 28 56 FF D2 8B 10 8B C8 8B 42 04 6A 00 FF D0 8B F0 85 F6 75 04 B0 */ + } + /* CDirector::ResetMobTimer() + Resets the Director's natural horde timer. Normally this + is called when a horde is spawned naturally or by boomer. + Small function, nearly hits another segment in the file. + + - Find it through only xref, which is setting up ScriptDesc structures: string "Trigger a mob as soon as possible when" + - If you go past the first call, you should hit unique bytes in sig making + */ + "ResetMobTimer" + { + "library" "server" + "linux" "@_ZN9CDirector13ResetMobTimerEv" + "windows" "\x55\x8B\xEC\x51\x56\x57\x8D\xB9\x2A\x2A\x2A\x2A\x8B\xCF\xE8\x2A\x2A\x2A\x2A\xD9" + /* 55 8B EC 51 56 57 8D B9 ? ? ? ? 8B CF E8 ? ? ? ? D9 */ + } + /* CGameRulesProxy::NotifyNetworkStateChanged() + This function is called before changing a variety of + pieces of networked data (data which is reflected in network + game states). + + - Find "Going to intermission...\n" in CGameRules::GoToIntermission + - Last call in the func + */ + "NotifyNetworkStateChanged" + { + "library" "server" + "linux" "@_ZN15CGameRulesProxy25NotifyNetworkStateChangedEv" + "windows" "\xA1\x2A\x2A\x2A\x2A\x85\xC0\x74\x2A\x80\x78" + /* A1 ? ? ? ? 85 C0 74 ? 80 78 */ + } + } + } +} \ No newline at end of file diff --git a/serverfiles/left4dead2/addons/sourcemod/plugins/abm.smx b/serverfiles/left4dead2/addons/sourcemod/plugins/abm.smx new file mode 100644 index 0000000..677602e Binary files /dev/null and b/serverfiles/left4dead2/addons/sourcemod/plugins/abm.smx differ diff --git a/serverfiles/left4dead2/addons/sourcemod/scripting/include/l4d2director.inc b/serverfiles/left4dead2/addons/sourcemod/scripting/include/l4d2director.inc new file mode 100644 index 0000000..0efcef5 --- /dev/null +++ b/serverfiles/left4dead2/addons/sourcemod/scripting/include/l4d2director.inc @@ -0,0 +1,85 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * Left 4 Downtown 2 SourceMod Extension + * Copyright (C) 2010 Michael "ProdigySim" Busby + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + + #if defined _l4d2director_included + #endinput +#endif +#define _l4d2director_included + +/** + * @brief Gets the number of tanks currently in play. + * @remarks This value is tracked by the director, and should be a good + * indicator that a tank is in play + * + * @return current tank count + */ +native L4D2_GetTankCount(); + +/** + * @brief Gets the campaign scores stored in the Versus Director + * @remarks These are the actual values used for campaign scores--not proxies + * + * @param scores Array to store the campaign scores in + * @noreturn + */ +native L4D2_GetVersusCampaignScores(scores[2]); + +/** + * @brief Sets the campaign scores stored in the Versus Director + * @remarks These are the actual values used for campaign scores--not proxies + * + * @param scores Array of campaign scores to set the director's values to. + * @noreturn + */ +native L4D2_SetVersusCampaignScores(const scores[2]); + +/** + * @brief Gets the flow percent for tank spawns for both versus rounds. + * @remarks These values are checked against as the survivors move through the + * map. Once they are passed, the tank spawns. Note that this is flow + * as a percent of the map's flow, not flow distance. + * + * @param tankFlows Array to store the Tank Spawn Flow percents in + * @noreturn + */ +native L4D2_GetVersusTankFlowPercent(Float:tankFlows[2]); + +/** + * @brief Sets the flow percent for tank spawns for both versus rounds. + * @remarks These values are checked against as the survivors move through the + * map. Once they are passed, the tank spawns. Note that this is flow + * as a percent of the map's flow, not flow distance. + * + * @param tankFlows Array of Tank Spawn Flow percents to store in director + * @noreturn + */ +native L4D2_SetVersusTankFlowPercent(const Float:tankFlows[2]); + diff --git a/serverfiles/left4dead2/addons/sourcemod/scripting/include/l4d2timers.inc b/serverfiles/left4dead2/addons/sourcemod/scripting/include/l4d2timers.inc new file mode 100644 index 0000000..34d07a0 --- /dev/null +++ b/serverfiles/left4dead2/addons/sourcemod/scripting/include/l4d2timers.inc @@ -0,0 +1,171 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * Left 4 Downtown 2 SourceMod Extension + * Copyright (C) 2010 Michael "ProdigySim" Busby + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + + #if defined _l4d2timers_included + #endinput +#endif +#define _l4d2timers_included + +enum L4D2CountdownTimer +{ + L4D2CT_MobSpawnTimer, + L4D2CT_SmokerSpawnTimer, + L4D2CT_BoomerSpawnTimer, + L4D2CT_HunterSpawnTimer, + L4D2CT_SpitterSpawnTimer, + L4D2CT_JockeySpawnTimer, + L4D2CT_ChargerSpawnTimer, + L4D2CT_VersusStartTimer, + L4D2CT_UpdateMarkersTimer +}; + +enum L4D2IntervalTimer +{ + L4D2IT_SmokerDeathTimer, + L4D2IT_BoomerDeathTimer, + L4D2IT_HunterDeathTimer, + L4D2IT_SpitterDeathTimer, + L4D2IT_JockeyDeathTimer, + L4D2IT_ChargerDeathTimer +}; + +/** + * @brief Resets a given CountdownTimer (start again with same duration) + * @remarks Equivalent to Start(timer, GetCountdownDuration(timer)) + * + * @param timer CountdownTimer to reset + * @noreturn + */ +native L4D2_CTimerReset(L4D2CountdownTimer:timer); + +/** + * @brief Starts a given CountdownTimer with a given duration + * @remarks This sets a new duration and sets up the end timestamp + * + * @param timer CountdownTimer to start + * @param duration Duration for the timer to use + * @noreturn + */ +native L4D2_CTimerStart(L4D2CountdownTimer:timer, Float:duration); + +/** + * @brief Invalidates a given CountdownTimer (Timer essentially does not run) + * @remarks Sets the timestamp to -1.0f + * + * @param timer CountdownTimer to Invalidate + * @noreturn + */ +native L4D2_CTimerInvalidate(L4D2CountdownTimer:timer); + +/** + * @brief Tells if a given CountdownTimer has started + * @remarks Checks to see if the end timestamp is greater than 0.0f + * + * @param timer CountdownTimer to check + * @return true if timer has started, false if timer is not started/invalid. + */ +native bool:L4D2_CTimerHasStarted(L4D2CountdownTimer:timer); + +/** + * @brief Tells if a given CountdownTimer is elapsed + * @remarks If a timer is "up," e.g duration has passed since Start(), this returns true; + * + * @param timer CountdownTimer to check + * @return true if timer has elapsed or timer invalid/not started, false otherwise + */ +native bool:L4D2_CTimerIsElapsed(L4D2CountdownTimer:timer); + +/** + * @brief Gets elapsed time of a given CountdownTimer, from the timed it was Start()ed + * @remarks Value is (Now() - timestamp) + duration + * + * @param timer CountdownTimer to get elapsed time of + * @return Float amount of time since timer started + */ +native Float:L4D2_CTimerGetElapsedTime(L4D2CountdownTimer:timer); + +/** + * @brief Gets remaining time on a given CountdownTimer + * @remarks Value is (timestamp - Now()) + * + * @param timer CountdownTimer to get remaining time of + * @return Float amount of time remaining on the timer + */ +native Float:L4D2_CTimerGetRemainingTime(L4D2CountdownTimer:timer); + +/** + * @brief Gets the duration of a given CountdownTimer + * @remarks Value is (timestamp > 0.0f ? duration : 0.0f) + * + * @param timer CountdownTimer to get duration of + * @return 0.0 for invalid/not started timers, timer duration otherwise. + */ +native Float:L4D2_CTimerGetCountdownDuration(L4D2CountdownTimer:timer); + +/************************************* + IntervalTimer Natives + ***********************************/ + +/** + * @brief Starts a given IntervalTimer + * @remarks Just sets timestamp = Now(), so counting starts from now + * + * @param timer IntervalTimer to start + * @noreturn + */ +native L4D2_ITimerStart(L4D2IntervalTimer:timer); + +/** + * @brief Invalidates a given IntervalTimer + * @remarks Just sets timestamp = -1.0f + * + * @param timer IntervalTimer to Invalidate + * @noreturn + */ +native L4D2_ITimerInvalidate(L4D2IntervalTimer:timer); + +/** + * @brief Tells whether a given IntervalTimer has started + * @remarks Checks to see if timestamp > 0.0f + * + * @param timer IntervalTimer to check + * @return true if timer is started, false if it is invalid/not started + */ +native bool:L4D2_ITimerHasStarted(L4D2IntervalTimer:timer); + +/** + * @brief Gets the elapsed time of a given IntervalTimer + * @remarks Value is Now() - Timestamp + * + * @param timer IntervalTimer to get elapsed time of + * @return Elapsed time if timer started and valid, 99999.9f otherwise + */ +native Float:L4D2_ITimerGetElapsedTime(L4D2IntervalTimer:timer); diff --git a/serverfiles/left4dead2/addons/sourcemod/scripting/include/l4d2weapons.inc b/serverfiles/left4dead2/addons/sourcemod/scripting/include/l4d2weapons.inc new file mode 100644 index 0000000..61c18f6 --- /dev/null +++ b/serverfiles/left4dead2/addons/sourcemod/scripting/include/l4d2weapons.inc @@ -0,0 +1,219 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * Left 4 Downtown 2 SourceMod Extension + * Copyright (C) 2010 Michael "ProdigySim" Busby + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + + #if defined _l4d2weapons_included + #endinput +#endif +#define _l4d2weapons_included + +enum L4D2IntWeaponAttributes +{ + L4D2IWA_Damage, + L4D2IWA_Bullets, + L4D2IWA_ClipSize +}; + +/* +A note regarding Clipsize: Any nonstandard value will NOT be in effect at weapon pickup, which means the client +has to reload once to achieve the modified value. To fix this, add a weapon pickup hook in your plugin (eg "player_use") +and use something like this with a small timer delay of 0.1 seconds or more (dont you love this engine) + + new weapon = GetPlayerWeaponSlot(client, 0); + if (weapon == INVALID_ENT_REFERENCE) return; + decl String:class[56]; + GetEdictClassname(weapon, class, sizeof(class)); + SetEntProp(weapon, Prop_Send, "m_iClip1", L4D2_GetIntWeaponAttribute(class, L4D2IWA_ClipSize)); +*/ + +enum L4D2FloatWeaponAttributes +{ + L4D2FWA_MaxPlayerSpeed, + L4D2FWA_SpreadPerShot, + L4D2FWA_MaxSpread, + L4D2FWA_SpreadDecay, + L4D2FWA_MinDuckingSpread, + L4D2FWA_MinStandingSpread, + L4D2FWA_MinInAirSpread, + L4D2FWA_MaxMovementSpread, + L4D2FWA_PenetrationNumLayers, + L4D2FWA_PenetrationPower, + L4D2FWA_PenetrationMaxDist, + L4D2FWA_CharPenetrationMaxDist, + L4D2FWA_Range, + L4D2FWA_RangeModifier, + L4D2FWA_CycleTime +}; + +enum L4D2BoolMeleeWeaponAttributes +{ + L4D2BMWA_Decapitates +}; + +enum L4D2IntMeleeWeaponAttributes +{ + L4D2IMWA_DamageFlags, + L4D2IMWA_RumbleEffect +}; + +enum L4D2FloatMeleeWeaponAttributes +{ + L4D2FMWA_Damage, + L4D2FMWA_RefireDelay, + L4D2FMWA_WeaponIdleTime +}; + + +/** + * @brief Checks for a given weapon string to exist in the WeaponInformationDatabase + * @remarks Throws an error if Database is unavailable + * + * @param weaponName Weapon to check up on + * @return True if weapon is found, false if not + */ +native bool:L4D2_IsValidWeapon(const String:weaponName[]); + +/** + * @brief Read an int-typed attribute for a given weapon from the WeaponInformationDatabase + * @remarks Throws an error if the weapon is not found or the attribute is incorrect + * + * @param weaponName Weapon to lookup attribute for + * @param attr Attribute to read from the weapon's info struct + * @return The value read. + */ +native L4D2_GetIntWeaponAttribute(const String:weaponName[], L4D2IntWeaponAttributes:attr); + +/** + * @brief Read a float-typed attribute for a given weapon from the WeaponInformationDatabase + * @remarks Throws an error if the weapon is not found or the attribute is incorrect + * + * @param weaponName Weapon to lookup attribute for + * @param attr Attribute to read from the weapon's info struct + * @return The value read. + */ +native Float:L4D2_GetFloatWeaponAttribute(const String:weaponName[], L4D2FloatWeaponAttributes:attr); + +/** + * @brief Set an int-typed attribute for a given weapon from the WeaponInformationDatabase to a given value + * @remarks Throws an error if the weapon is not found or the attribute is incorrect + * + * @param weaponName Weapon to lookup attribute for + * @param attr Attribute to alter in the weapon's info struct + * @param value Value to set the attribute to + * @noreturn + */ +native L4D2_SetIntWeaponAttribute(const String:weaponName[], L4D2IntWeaponAttributes:attr, value); + +/** + * @brief Set a float-typed attribute for a given weapon from the WeaponInformationDatabase to a given value + * @remarks Throws an error if the weapon is not found or the attribute is incorrect + * + * @param weaponName Weapon to lookup attribute for + * @param attr Attribute to alter in the weapon's info struct + * @param value Value to set the attribute to + * @noreturn + */ +native Float:L4D2_SetFloatWeaponAttribute(const String:weaponName[], L4D2FloatWeaponAttributes:attr, Float:value); + + + + + +/** + * @brief Retrieve the index for a given melee weapon from the Melee Weapon Database + * @remarks returns -1 if no match is found + * + * @param weaponName Weapon to lookup index id for + * @return The index id + */ +native L4D2_GetMeleeWeaponIndex(const String:weaponName[]); + +/** + * @brief Read an int-typed attribute for a given id from the Melee Weapon Database + * @remarks Throws an error if the id is not found or the attribute is incorrect + * + * @param id Melee id to lookup attribute for + * @param attr Attribute to read from the weapon's info struct + * @return The value read. + */ +native L4D2_GetIntMeleeAttribute(id, L4D2IntMeleeWeaponAttributes:attr); + +/** + * @brief Read a float-typed attribute for a given id from the Melee Weapon Database + * @remarks Throws an error if the id is not found or the attribute is incorrect + * + * @param id Melee id to lookup attribute for + * @param attr Attribute to read from the weapon's info struct + * @return The value read. + */ +native Float:L4D2_GetFloatMeleeAttribute(id, L4D2FloatMeleeWeaponAttributes:attr); + +/** + * @brief Read a bool-typed attribute for a given id from the Melee Weapon Database + * @remarks Throws an error if the id is not found or the attribute is incorrect + * + * @param id Melee id to lookup attribute for + * @param attr Attribute to read from the weapon's info struct + * @return The value read. + */ +native bool:L4D2_GetBoolMeleeAttribute(id, L4D2BoolMeleeWeaponAttributes:attr); + +/** + * @brief Set an int-typed attribute for a given id from the Melee Weapon Database to a given value + * @remarks Throws an error if the id is not found or the attribute is incorrect + * + * @param id Melee id to lookup attribute for + * @param attr Attribute to alter in the weapon's info struct + * @param value Value to set the attribute to + * @noreturn + */ +native L4D2_SetIntMeleeAttribute(id, L4D2IntMeleeWeaponAttributes:attr, value); + +/** + * @brief Set a float-typed attribute for a given id from the Melee Weapon Database to a given value + * @remarks Throws an error if the id is not found or the attribute is incorrect + * + * @param id Melee id to lookup attribute for + * @param attr Attribute to alter in the weapon's info struct + * @param value Value to set the attribute to + * @noreturn + */ +native Float:L4D2_SetFloatMeleeAttribute(id, L4D2FloatMeleeWeaponAttributes:attr, Float:value); + +/** + * @brief Set a bool-typed attribute for a given id from the Melee Weapon Database to a given value + * @remarks Throws an error if the id is not found or the attribute is incorrect + * + * @param id Melee id to lookup attribute for + * @param attr Attribute to alter in the weapon's info struct + * @param value Value to set the attribute to + * @noreturn + */ +native Float:L4D2_SetBoolMeleeAttribute(id, L4D2BoolMeleeWeaponAttributes:attr, bool:value); diff --git a/serverfiles/left4dead2/addons/sourcemod/scripting/include/left4downtown.inc b/serverfiles/left4dead2/addons/sourcemod/scripting/include/left4downtown.inc new file mode 100644 index 0000000..2fac8d1 --- /dev/null +++ b/serverfiles/left4dead2/addons/sourcemod/scripting/include/left4downtown.inc @@ -0,0 +1,579 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * Left 4 Downtown SourceMod Extension + * Copyright (C) 2009 Igor "Downtown1" Smirnov. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ +#if defined _l4do_included + #endinput +#endif +#define _l4do_included + +#include +#include +#include + +/** + * @brief Called whenever ZombieManager::SpawnTank(Vector&,QAngle&) is invoked + * @remarks Not invoked if z_spawn tank is used and it gives a ghosted/dead player tank + * + * @param vector Vector coordinate where tank is spawned + * @param qangle QAngle where tank will be facing + * @return Pl_Handled to block tank from spawning, Pl_Continue otherwise. + */ +forward Action:L4D_OnSpawnTank(const Float:vector[3], const Float:qangle[3]); + +/** + * @brief Called whenever ZombieManager::SpawnWitch(Vector&,QAngle&) is invoked + * + * @param vector Vector coordinate where witch is spawned + * @param qangle QAngle where witch will be facing + * @return Pl_Handled to block witch from spawning, Pl_Continue otherwise. + */ +forward Action:L4D_OnSpawnWitch(const Float:vector[3], const Float:qangle[3]); + +/** + * @brief Called whenever ZombieManager::SpawnWitchBride(Vector&,QAngle&) is invoked + * + * @param vector Vector coordinate where witch is spawned + * @param qangle QAngle where witch will be facing + * @return Pl_Handled to block witch from spawning, Pl_Continue otherwise. + */ +forward Action:L4D_OnSpawnWitchBride(const Float:vector[3], const Float:qangle[3]); + +/** + * @brief Called whenever ZombieManager::SpawnSpecial(ZombieClassType,Vector&,QAngle&) is invoked + * @remarks Only used for bot special spawns (not players) + * + * @param zombieClass Zombie class that will be spawned. + * @param vector Vector coordinate where special will be spawned + * @param qangle QAngle where spcial will be facing + * @return Pl_Handled to block special from spawning, + * Pl_Changed to change the zombie class type to spawn, Pl_Continue otherwise. + */ +forward Action:L4D_OnSpawnSpecial(&zombieClass, const Float:vector[3], const Float:qangle[3]); + +/** + * @brief Called whenever CTerrorGameRules::ClearTeamScores(bool) is invoked + * @remarks This resets the map score at the beginning of a map, and by checking + * the campaign scores on a small timer you can see if they were reset as well. + * + * @param newCampaign if true then this is a new campaign, if false a new chapter + * @return Pl_Handled to block scores from being cleared, Pl_Continue otherwise. + */ +forward Action:L4D_OnClearTeamScores(bool:newCampaign); + +/** + * @brief Called whenever CTerrorGameRules::SetCampaignScores(int,int) is invoked + * @remarks The campaign scores are updated after the 2nd round is completed + * + * @param scoreA score of logical team A + * @param scoreB score of logical team B + * @return Pl_Handled to block campaign scores from being set, Pl_Continue otherwise. + */ +forward Action:L4D_OnSetCampaignScores(&scoreA, &scoreB); + +/** + * @brief Called whenever CDirector::OnFirstSurvivorLeftSafeArea is invoked + * @remarks A versus round is started when survivors leave the safe room, or force started + * after 90 seconds regardless. + * + * @param client the survivor that left the safe area first + * + * @return Pl_Handled to block round from being started, Pl_Continue otherwise. + */ +forward Action:L4D_OnFirstSurvivorLeftSafeArea(client); + +/** + * @brief Called whenever CDirector::GetScriptValue(const char*, int) is invoked + * @remarks A script value is map specific + * + * @param key the script's key name + * @param retVal what to override the return value with + * + * @return Pl_Handled to override return value, Pl_Continue otherwise. + */ +forward Action:L4D_OnGetScriptValueInt(const String:key[], &retVal); + +/** + * @brief Called whenever CDirector::GetScriptValue(const char*, float) is invoked + * @remarks A script value is map specific + * + * @param key the script's key name + * @param retVal what to override the return value with + * + * @return Pl_Handled to override return value, Pl_Continue otherwise. + */ +forward Action:L4D_OnGetScriptValueFloat(const String:key[], &Float:retVal); + +/** + * @brief Called whenever CDirector::GetScriptValue(const char*, const char*, char*, int) is invoked + * @remarks A script value is map specific + * + * @param key the script's key name + * @param defaultVal default key return, usually empty + * @param retVal returned String + * + * @return Pl_Handled to override return value, Pl_Continue otherwise. + */ +forward Action:L4D_OnGetScriptValueString(const String:key[], const String:defaultVal[], String:retVal[128]); + +/** + * @brief Called whenever CTerrorPlayer::OnEnterGhostState(CTerrorPlayer*) is invoked + * @remarks This happens when a player enters ghost mode (or in finales auto-materialized) + * + * @param client the client that has entered ghost mode + */ +forward L4D_OnEnterGhostState(client); + +/** + * @brief Called whenever CDirector::TryOfferingTankBot is invoked + * @remarks Is used for displaying the "X gets Tank" window and transferring Tank control + * + * @return Pl_Handled to block window from showing and to keep Tank Bot, Pl_Continue otherwise + */ +forward Action:L4D_OnTryOfferingTankBot(tank_index, &bool:enterStasis); + +/** + * @brief Called whenever CDirector::OnMobRushStart(void) is invoked + * @remarks called on random hordes, mini- and finale hordes, and boomer hordes, causes Zombies to attack + * Not called on "z_spawn mob", hook the console command and check arguments to catch plugin mobs + * This function is used to reset the Director's natural horde timer + * + * @return Pl_Handled to block, Pl_Continue otherwise + */ +forward Action:L4D_OnMobRushStart(); + +/** + * @brief Called whenever ZombieManager::SpawnITMob(int) is invoked + * @remarks called on boomer hordes, increases Zombie Spawn Queue + * + * @param amount Amount of Zombies to add to Queue + * + * @return Pl_Handled to block, Pl_Continue otherwise + */ +forward Action:L4D_OnSpawnITMob(&amount); + +/** + * @brief Called whenever ZombieManager::SpawnMob(int) is invoked + * @remarks called on natural hordes & z_spawn mob, increases Zombie Spawn + * Queue, triggers player OnMobSpawned (vocalizations), sets horde + * direction, and plays horde music. + * + * @param amount Amount of Zombies to add to Queue + * + * @return Pl_Handled to block, Pl_Continue otherwise + */ +forward Action:L4D_OnSpawnMob(&amount); + +/** + * @brief Called whenever CTerrorPlayer::OnShovedBySurvivor(CTerrorPlayer, Vector&) is invoked + * @remarks L4D2 only uses this on Special Infected + * + * @param client the client that did the shoving + * @param victim the client that was shoved (CAUTION: retrieved from function pointer, dont meddle with it) + * @param vector Vector Angle of Shoveforce + * + * @return Pl_Handled to block melee effect (staggering), Pl_Continue otherwise. + */ +forward Action:L4D_OnShovedBySurvivor(client, victim, const Float:vector[3]); + +/** + * @brief Called whenever CTerrorPlayer::GetCrouchTopSpeed() is invoked + * + * @param target the client that its being called on (not changible) + * @param retVal what to override the return value with + * + * @return Pl_Handled to override return value, Pl_Continue otherwise. + */ +forward Action:L4D_OnGetCrouchTopSpeed(target, &Float:retVal); + +/** + * @brief Called whenever CTerrorPlayer::GetRunTopSpeed() is invoked + * + * @param target the client that its being called on (not changible) + * @param retVal what to override the return value with + * + * @return Pl_Handled to override return value, Pl_Continue otherwise. + */ +forward Action:L4D_OnGetRunTopSpeed(target, &Float:retVal); + +/** + * @brief Called whenever CTerrorPlayer::GetWalkTopSpeed() is invoked + * + * @param target the client that its being called on (not changible) + * @param retVal what to override the return value with + * + * @return Pl_Handled to override return value, Pl_Continue otherwise. + */ +forward Action:L4D_OnGetWalkTopSpeed(target, &Float:retVal); + +/** + * @brief Called whenever CTerrorGameRules::HasConfigurableDifficultySetting() is invoked + * @remarks used to deny/allow difficulty changes in different game modes + * + * @param retVal what to override the return value with. 1 to allow difficulty configuration, 0 to deny. + * + * @return Pl_Handled to override return value, Pl_Continue otherwise. + */ +forward Action:L4D_OnHasConfigurableDifficulty(&retVal); + +/** + * @brief Called whenever CTerrorGameRules::GetSurvivorSet(void) is invoked + * + * @param retVal what to override the return value with + * + * @return Pl_Handled to override return value, Pl_Continue otherwise. + */ +forward Action:L4D_OnGetSurvivorSet(&retVal); + +/** + * @brief Called whenever CTerrorGameRules::FastGetSurvivorSet(void) is invoked + * + * @param retVal what to override the return value with + * + * @return Pl_Handled to override return value, Pl_Continue otherwise. + */ +forward Action:L4D_OnFastGetSurvivorSet(&retVal); + +/** + * @brief Called whenever CDirectorVersusMode::GetMissionVersusBossSpawning() is invoked + * @remarks Passed values are from the map's Mission Keyvalues. If those keyvalues don't exist, they are from cvar and other globals + * + * @param spawn_pos_min Minimum spawn position (percent of flow distance) for bosses + * @param spawn_pos_max Maximum spawn position (perfect of flow distance) for bosses + * @param tank_chance Chance for a tank to spawn on this map + * @param witch_chance Chance for a witch to spawn on this map + * + * @return Pl_Handled to block reading map data, Pl_Changed to use overwritten values from plugin, Pl_Continue to continue to read from mission data. + */ +forward Action:L4D_OnGetMissionVSBossSpawning(&Float:spawn_pos_min, &Float:spawn_pos_max, &Float:tank_chance, &Float:witch_chance); + +/** + * @brief Called whenever CThrow::ActivateAbility(void) is invoked + * @remarks Called when a tank throws a rock. Blocking this call will + * keep the tank from throwing a rock. + * + * @param ability ability_throw entity index + * + * @return Pl_Handled to block, Pl_Continue otherwise + */ +forward Action:L4D_OnCThrowActivate(ability); + +/** + * @brief Called whenever InfectedShoved::OnShoved(Infected *, CBaseEntity *) is invoked + * @remarks Called when common Infected are about to get shoved + * + * @return Pl_Handled to block, Pl_Continue otherwise + */ +forward Action:L4D_OnInfectedShoved(infected, entity); + +/** + * @brief Called whenever CTerrorMeleeWeapon::StartMeleeSwing(CTerrorPlayer *, bool) is invoked + * @remarks Called when a player uses his melee Weapons primary attack. This is before the game + * reads the melee weapon data (model etc) and decides if he CAN attack at all. + * + * @return Pl_Handled to block, Pl_Continue otherwise + */ +forward Action:L4D_OnStartMeleeSwing(client, bool:boolean); + +/** + * @brief Called whenever CDirectorScriptedEventManager::SendInRescueVehicle(void) is invoked + * @remarks Called when the last Finale stage is reached and the Rescue Means becomes 'available'. + * Take note this forward WILL fire upon using the native of the same function. + * + * @return Pl_Handled to block, Pl_Continue otherwise + */ +forward Action:L4D2_OnSendInRescueVehicle(); + +/** + * @brief Called whenever CDirectorScriptedEventManager::ChangeFinaleStage is invoked + * + * @param FinaleStageType integer value + * @remarks some values for FinaleStageType: 1 - Finale Started; 6 - Rescue Vehicle Ready; 7 - Zombie Hordes; 8 - Tank; 10 - Combat Respite (nothing spawns) + * @remarks SendInRescueVehicle does not depend on Finale Stage being 6, that only signals endless Hordes/Tanks + * + * @return Pl_Handled to block, Pl_Continue otherwise + */ +forward Action:L4D2_OnChangeFinaleStage(&finaleType, const String:arg[]); + +/** + * @brief Called whenever CDirectorVersusMode::EndVersusModeRound(bool) is invoked + * + * @param countSurvivors True if the survival multiplier count needs to be nonzero. I guess. + * @remarks Not sure what bool does exactly yet. Just monitor it. If true, survivors will be counted for multiplier. If false, survival multiplier will be set to 0. + * @remarks A lot of Score calculations happen on this function, and the round-end scoreboard comes up doing this. Don't block unless you're sure you can reproduce this logic. + * + * @return Pl_Handled to block, Pl_Continue otherwise + */ +forward Action:L4D2_OnEndVersusModeRound(bool:countSurvivors); + +/** + * @brief Called when CBaseAnimating::SelectWeightedSequence(int Activity) is invoked with tank attack activity + * @remarks Called whenever a tank uses his primary (punch) or secondary (throw) attack + * + * @param client the client that is playing as tank + * @param sequence current selected sequence for attack, option to override the return value with it + * @remarks sequences(punches): 40(uppercut), 43(right hook), 45(left hook), 46 and 47 (pounding the ground) + * @remarks sequences(throws): 48(undercut), 49(1handed overhand), 50(throw from the hip), 51(2handed overhand) + * + * @return Pl_Handled to override return value, Pl_Continue otherwise. + */ +forward Action:L4D2_OnSelectTankAttack(client, &sequence); + +/** + * @brief Called when CTerrorPlayer::OnRevived(void) is invoked + * @remarks Called post-revive so all data values are post-revive status. + * + * @param client the client that has been revived + * + * @noreturn Pl_Handled to override return value, Pl_Continue otherwise. + */ +forward Action:L4D2_OnRevived(client); + +/** + * @brief Get the current campaign scores stored in the Director + * @remarks The campaign scores are updated after L4D_OnSetCampaignScores + * + * @deprecated This will set the scores to -1 for both sides on L4D2, + * this function is no longer supported. + * + * @param scoreA score of logical team A + * @param scoreB score of logical team B + * @return 1 always + */ +#pragma deprecated Use GetTeamScore and OnClearTeamScores instead +native L4D_GetCampaignScores(&scoreA, &scoreB); + +/** + * @brief Get the team scores for the current map + * @remarks The campaign scores are not set until the end of round 2, + * use L4D_GetCampaignScores to get them earlier. + * + * @deprecated This function can be called through SDKTools using CTerrorGameRules, + * and so you should switch off to using SDKTools instead of this native. + * + * @param logical_team 0 for A, 1 for B + * @param campaign_score true to get campaign score instead of map score + * @return the logical team's map score + * or -1 if the team hasn't played the round yet, + * or the team's campaign score if campaign_score = true + */ +native L4D_GetTeamScore(logical_team, campaign_score=false); + +/** + * @brief Restarts the setup timer (when in scavenge mode) + * @remarks If game has already started, the setup timer will show, + * but it still won't go back into setup. + */ +native L4D_ScavengeBeginRoundSetupTime(); + +/** + * @brief Restarts the round, switching the map if necessary + * @remarks Set the map to the current map to restart the round + * + * @param map the mapname it should go to after the round restarts + * @return 1 always + */ +native L4D_RestartScenarioFromVote(const String:map[]); + +/** + * @brief Removes lobby reservation from a server + * @remarks Sets the reservation cookie to 0, + * it is safe to call this even if it's unreserved. + */ +native L4D_LobbyUnreserve(); + +/** + * @brief Checks if the server is currently reserved for a lobby + * @remarks Server is automatically unreserved if it hibernates or + * if all players leave. + * + * @deprecated This will always return false on L4D2 or on Linux. + * + * @return true if reserved, false if not reserved + */ +#pragma deprecated This will always return false on L4D2 or on Linux. +native bool:L4D_LobbyIsReserved(); + +/** + * @brief Gets the max versus completion score for the map + * @remarks Requires GameRules to be initialized--map must be loaded + * Seems to be updated before OnMapStart + * + * + * @return The map's max completion distance (map distance score) + */ +native L4D_GetVersusMaxCompletionScore(); + +/** + * @brief Sets the max versus completion score for the map + * @remarks Requires GameRules to be initialized--map must be loaded + * Seems to be updated before OnMapStart and checked on round_start + * + * @param score The versus max completion score to set for the round + */ +native L4D_SetVersusMaxCompletionScore(score); + +/** + * @brief Tells if the Mission (map) is the final map of the campaign + * + * @return true if the map is the last map of the campaign (finale) + */ +native bool:L4D_IsMissionFinalMap(); + +/** + * @brief Resets the natural mob (horde) timer + * @remarks Requires the Director to be available--map must be started + * + * @noreturn + */ +native L4D_ResetMobTimer(); + +/** + * @brief Notifies the CGameRulesProxy that the game state has been changed + * @remarks Use this function before changing networked members of GameRules, + * like with L4D_SetVersusMaxCompletionScore() + * + * @noreturn + */ +native L4D_NotifyNetworkStateChanged(); + +/** + * @brief Trigger's a target player's stagger behavior + * @remarks Works on any CTerrorPlayer--survivor or infected. + * + * @param target Player to stagger + * @param source_ent Source of the stagger (another player, etc) + * @param source_vector Source location of the stagger. If NULL_VECTOR, origins of source_ent is used. + * @noreturn + */ +native L4D_StaggerPlayer(target, source_ent, Float:source_vector[3]); + +/** + * @brief Get the time remaining before the next director horde. + * @remarks This timer is used for scripted event hordes and natural timed hordes + * + * @return Time remaining before next director horde + */ +#pragma deprecated Use L4D2_CTimerGetRemainingTime(L4D2CT_MobSpawnTimer) +native Float:L4D_GetMobSpawnTimerRemaining(); + +/** + * @brief Get the duration the horde timer was set to after the last horde + * @remarks This timer is used for scripted event hordes and natural timed hordes + * + * @return Total time from last horde to next horde. + */ +#pragma deprecated Use L4D2_CTimerGetCountdownDuration(L4D2CT_MobSpawnTimer) +native Float:L4D_GetMobSpawnTimerDuration(); + +/** + * @brief Get the remaining spawn time for an SI + * @remarks This is meant for Special infected in ghost mode in versus. + * + * @return Time (seconds) until the SI will spawn. + */ +native Float:L4D_GetPlayerSpawnTime(player); + +/** + * @brief Calls CDirectorScriptedEventManager::SendInRescueVehicle(void) + * + * @remarks will fire the forward of the same function + * + * @noreturn + */ +native L4D2_SendInRescueVehicle(); + +/** + * @brief Calls CDirectorScriptedEventManager::ChangeFinaleStage(CDirectorScriptedEventManager::FinaleStageType,char const*) + * + * @param FinaleStageType integer value + * @remarks some values for FinaleStageType: 1 - Finale Started; 6 - Rescue Vehicle Ready; 7 - Zombie Hordes; 8 - Tank; 10 - Combat Respite (nothing spawns) + * @remarks + * @remarks will fire the forward of the same function + * + * @noreturn + */ +native L4D2_ChangeFinaleStage(finaleType, const String:arg[]); + +/** + * @brief Calls ZombieManager::SpawnTank(Vector&,QAngle&) + * + * @param vector Vector coordinate where the tank will be spawned + * @param qangle QAngle where the tank will be facing + * @return Entity index of the spawned tank + */ +native L4D2_SpawnTank(const Float:vector[3], const Float:qangle[3]); + +/** + * @brief Calls ZombieManager::SpawnSpecial(ZombieClassType,Vector&,QAngle&) + * @remarks Only used for bot special spawns (not players) + * + * @param vector Vector coordinate where the SI will be spawned + * @param qangle QAngle where the SI will be facing + * @return Entity index of the spawned SI + */ +native L4D2_SpawnSpecial(zombieClass, const Float:vector[3], const Float:qangle[3]); + +/** + * @brief Calls ZombieManager::SpawnWitch(Vector&,QAngle&) + * + * @param vector Vector coordinate where the witch will be spawned + * @param qangle QAngle where the witch will be facing + * @return Entity index of the spawned witch + */ +native L4D2_SpawnWitch(const Float:vector[3], const Float:qangle[3]); + +/** + * @brief Calls ZombieManager::SpawnWitchBride(Vector&,QAngle&) + * + * @param vector Vector coordinate where the witch bride will be spawned + * @param qangle QAngle where the witch bride will be facing + * @return Entity index of the spawned witch bride + */ +native L4D2_SpawnWitchBride(const Float:vector[3], const Float:qangle[3]); + +/* +Makes the extension required by the plugins, undefine REQUIRE_EXTENSIONS +if you want to use it optionally before including this .inc file +*/ +public Extension:__ext_left4downtown = +{ + name = "Left 4 Downtown", + file = "left4downtown.ext", +#if defined AUTOLOAD_EXTENSIONS + autoload = 1, +#else + autoload = 0, +#endif +#if defined REQUIRE_EXTENSIONS + required = 1, +#else + required = 0, +#endif +}; diff --git a/serverfiles/left4dead2/cfg/l4d2server.cfg b/serverfiles/left4dead2/cfg/l4d2server.cfg index e6c9997..2e31fd4 100644 --- a/serverfiles/left4dead2/cfg/l4d2server.cfg +++ b/serverfiles/left4dead2/cfg/l4d2server.cfg @@ -58,7 +58,37 @@ sm_cvar l4d_multislots_kickafk 0 sv_gametypes scavenge,coop,versus,survival,realism,teamversus,teamscavenge,mutation1,mutation2,mutation3,mutation4,mutation5,mutation6,mutation7,mutation8,mutation9,mutation10,mutation11,mutation12,mutation13,mutation14,mutation15,mutation16,mutation17,mutation18,mutation19,mutation20,chargertraining,tankassault,tankbrawl,gungame,uncommonground,uncommongroundsv +// Left 4 Downtown 2: https://forums.alliedmods.net/showthread.php?t=134032 +l4d_maxplayers 32 +sm_cvar l4d_maxplayers 32 +// ABM: A MultiSlots / SuperVersus Alternative +// https://forums.alliedmods.net/showthread.php?p=2477820 +// https://gitlab.com/vbgunz/ABM +abm_autohard 1 +abm_automodel 1 +abm_consumable adrenaline +abm_extraplayers 0 +abm_healitem "" +abm_identityfix 1 +abm_joinmenu 1 +abm_keepdead 0 +abm_loglevel 0 +abm_minplayers 4 +abm_offertakeover 1 +abm_primaryweapon shotgun_chrome +abm_secondaryweapon baseball_bat +abm_spawninterval 36 +abm_stripkick 0 +abm_tankchunkhp 2500 +abm_teamlimit 16 +abm_throwable "" +abm_unlocksi 0 +abm_zoey 5 +#abm_respawndelay 1.0 + + +// ------------------------------------------------------------------- //--> Download at http://forums.alliedmods.net/showthread.php?t=91132 //l4d_maxplayers 32 //sm_cvar l4d_maxplayers 32