From 336aee32254a433015141c4248c35570d9a87af9 Mon Sep 17 00:00:00 2001 From: Connor <34824423+EasterLee@users.noreply.github.com> Date: Sat, 25 Nov 2023 18:10:44 -0500 Subject: [PATCH 01/13] basic knockback --- cfg/cs2fixes/cs2fixes.cfg | 3 ++ src/cs2_sdk/entity/ccsplayerpawn.h | 9 +++++- src/detours.cpp | 13 ++++++++ src/events.cpp | 2 +- src/zombiereborn.cpp | 49 ++++++++++++++++++++++++------ src/zombiereborn.h | 3 ++ 6 files changed, 67 insertions(+), 12 deletions(-) diff --git a/cfg/cs2fixes/cs2fixes.cfg b/cfg/cs2fixes/cs2fixes.cfg index 33ee692b..e1187441 100644 --- a/cfg/cs2fixes/cs2fixes.cfg +++ b/cfg/cs2fixes/cs2fixes.cfg @@ -33,3 +33,6 @@ cs2f_rtv_endround 0 // Whether to immediately end the round when RTV succeed // Ztele settings zr_ztele_max_distance 150.0 // Maximum distance players are allowed to move after starting ztele zr_ztele_allow_humans 0 // Whether to allow humans to use ztele + +// General ZR ettings +zr_knockback_scale 5.0 // Global knockback scale \ No newline at end of file diff --git a/src/cs2_sdk/entity/ccsplayerpawn.h b/src/cs2_sdk/entity/ccsplayerpawn.h index 84c3aa7b..5fffd7ce 100644 --- a/src/cs2_sdk/entity/ccsplayerpawn.h +++ b/src/cs2_sdk/entity/ccsplayerpawn.h @@ -21,7 +21,14 @@ #include "cbaseplayerpawn.h" -class CCSPlayerPawn : public CBasePlayerPawn +class CCSPlayerPawnBase : public CBasePlayerPawn +{ +public: + DECLARE_SCHEMA_CLASS(CCSPlayerPawnBase); + SCHEMA_FIELD(QAngle, m_angEyeAngles) +}; + +class CCSPlayerPawn : public CCSPlayerPawnBase { public: DECLARE_SCHEMA_CLASS(CCSPlayerPawn); diff --git a/src/detours.cpp b/src/detours.cpp index 588def47..1b3610df 100644 --- a/src/detours.cpp +++ b/src/detours.cpp @@ -35,6 +35,9 @@ #include "playermanager.h" #include "igameevents.h" #include "gameconfig.h" +#ifdef _ZOMBIEREBORN +#include "zombiereborn.h" +#endif //_ZOMBIEREBORN #define VPROF_ENABLED #include "tier0/vprof.h" @@ -143,6 +146,16 @@ void FASTCALL Detour_CBaseEntity_TakeDamageOld(Z_CBaseEntity *pThis, CTakeDamage return; } + + //grenade and molotov knockback + CBaseEntity *pAttacker = inputInfo->m_hAttacker.Get(); + CCSPlayerController* pAttackerController = CCSPlayerController::FromPawn((CCSPlayerPawn*)pAttacker); + if (pAttackerController && pThis->IsPawn() && pAttackerController->m_iTeamNum == CS_TEAM_CT && pThis->m_iTeamNum == CS_TEAM_T) + { + if (V_strncmp(pszInflictorClass, "hegrenade", 9) || V_strncmp(pszInflictorClass, "inferno", 7)) + ApplyKnockbackExplosion((Z_CBaseEntity*)pInflictor, (CCSPlayerPawn*)pThis, (int)inputInfo->m_flDamage); + } + #endif //_ZOMBIEREBORN // Prevent molly on self if (g_bBlockMolotoveSelfDmg && inputInfo->m_hAttacker == pThis && !V_strncmp(pszInflictorClass, "inferno", 7)) diff --git a/src/events.cpp b/src/events.cpp index 2e0a2e32..3d695757 100644 --- a/src/events.cpp +++ b/src/events.cpp @@ -180,7 +180,7 @@ CON_COMMAND_F(cs2f_topdefender_enable, "Whether to use TopDefender", FCVAR_SPONL GAME_EVENT_F(player_hurt) { #ifdef _ZOMBIEREBORN - //ZR_OnPlayerHurt(pEvent); + ZR_OnPlayerHurt(pEvent); #endif //_ZOMBIEREBORN if (!g_bEnableTopDefender) return; diff --git a/src/zombiereborn.cpp b/src/zombiereborn.cpp index 2db85b82..233aa339 100644 --- a/src/zombiereborn.cpp +++ b/src/zombiereborn.cpp @@ -70,7 +70,7 @@ void ZR_OnRoundPrestart(IGameEvent* pEvent) void ZR_OnRoundStart(IGameEvent* pEvent) { - ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "The game is \x05Humans vs. Zombies\x01, the goal for zombies is to infect all humans by knifing them."); + ClientPrintAll(HUD_PRINTTALK, ZR_PREFIX "The game is \x05Humans vs. Zombies\x01, the goal for zombies is to infect all humans by knifing them."); new CTimer(1.0f, false, []() { @@ -95,18 +95,47 @@ void ZR_OnPlayerSpawn(IGameEvent* pEvent) pController->SwitchTeam(CS_TEAM_T); } -void ZR_OnPlayerHurt(IGameEvent* pEvent) +// CONVAR_TODO +float g_flKnockbackScale = 5.0f; +CON_COMMAND_F(zr_knockback_scale, "Global knockback scale", FCVAR_LINKED_CONCOMMAND | FCVAR_SPONLY) { - // Infection/Knockback to be done in TakeDamageOld detour + if (args.ArgC() < 2) + Msg("%s %f\n", args[0], g_flKnockbackScale); + else + g_flKnockbackScale = V_StringToFloat32(args[1], 5.0f); +} - //CCSPlayerController* pAttacker = (CCSPlayerController*)pEvent->GetPlayerController("attacker"); - //CCSPlayerController* pVictim = (CCSPlayerController*)pEvent->GetPlayerController("userid"); - //const char* szWeapon = pEvent->GetString("weapon"); - //int iDmgHealth = pEvent->GetInt("dmg_health"); - //int iHealth = pEvent->GetInt("health"); +// Still need to implement weapon config +void ApplyKnockback(CCSPlayerPawn *pHuman, CCSPlayerPawn *pVictim, int iDamage, const char *szWeapon) +{ + Vector vecKnockback; + AngleVectors(pHuman->m_angEyeAngles(), &vecKnockback); + vecKnockback *= (iDamage * g_flKnockbackScale); + //Message("%f %f %f\n",vecKnockback.x, vecKnockback.y, vecKnockback.z); + pVictim->m_vecBaseVelocity = pVictim->m_vecBaseVelocity() + vecKnockback; +} - //if (szWeapon == "" || !pAttacker || !pVictim) - // return; +void ApplyKnockbackExplosion(Z_CBaseEntity *pProjectile, CCSPlayerPawn *pVictim, int iDamage) +{ + Vector vecDisplacement = pVictim->GetAbsOrigin() - pProjectile->GetAbsOrigin(); + vecDisplacement.z += 36; + VectorNormalize(vecDisplacement); + Vector vecKnockback = vecDisplacement; + vecKnockback *= (iDamage * g_flKnockbackScale); + pVictim->m_vecBaseVelocity = pVictim->m_vecBaseVelocity() + vecKnockback; +} + +void ZR_OnPlayerHurt(IGameEvent* pEvent) +{ + CCSPlayerController *pAttacker = (CCSPlayerController*)pEvent->GetPlayerController("attacker"); + CCSPlayerController *pVictim = (CCSPlayerController*)pEvent->GetPlayerController("userid"); + const char* szWeapon = pEvent->GetString("weapon"); + int iDmgHealth = pEvent->GetInt("dmg_health"); + //grenade and molotov knockbacks are handled by TakeDamage detours + if (!pAttacker || !pVictim || strcmp(szWeapon, "") == 0 || strcmp(szWeapon, "inferno") == 0 || strcmp(szWeapon, "hegrenade") == 0) + return; + if (pAttacker->m_iTeamNum() == CS_TEAM_CT && pVictim->m_iTeamNum() == CS_TEAM_T) + ApplyKnockback((CCSPlayerPawn*)pAttacker->GetPawn(), (CCSPlayerPawn*)pVictim->GetPawn(), iDmgHealth, szWeapon); //if (pAttacker->m_iTeamNum == CS_TEAM_CT && pVictim->m_iTeamNum == CS_TEAM_T) // Message("lol"); diff --git a/src/zombiereborn.h b/src/zombiereborn.h index 9b295796..5485d4ae 100644 --- a/src/zombiereborn.h +++ b/src/zombiereborn.h @@ -19,6 +19,7 @@ #pragma once #ifdef _ZOMBIEREBORN +#define ZR_PREFIX " \4[Zombie:Reborn]\1 " //extern bool g_ZR_ZOMBIE_SPAWN_READY; @@ -30,6 +31,7 @@ enum class EZRRoundState }; extern EZRRoundState g_ZRRoundState; +extern float g_flKnockbackScale; void ZR_OnStartupServer(); void ZR_OnRoundPrestart(IGameEvent* pEvent); @@ -37,5 +39,6 @@ void ZR_OnRoundStart(IGameEvent* pEvent); void ZR_OnPlayerSpawn(IGameEvent* pEvent); void ZR_OnPlayerHurt(IGameEvent* pEvent); void ZR_OnPlayerDeath(IGameEvent* pEvent); +void ApplyKnockbackExplosion(Z_CBaseEntity *pProjectile, CCSPlayerPawn *pVictim, int iDamage); #endif //_ZOMBIEREBORN \ No newline at end of file From 85334ccd1fee8a9ee7a27f9a287c66b813ce9bd2 Mon Sep 17 00:00:00 2001 From: Connor <34824423+EasterLee@users.noreply.github.com> Date: Sun, 26 Nov 2023 20:36:11 -0500 Subject: [PATCH 02/13] Update zombiereborn.cpp --- src/zombiereborn.cpp | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/zombiereborn.cpp b/src/zombiereborn.cpp index 24a19650..c1e6253e 100644 --- a/src/zombiereborn.cpp +++ b/src/zombiereborn.cpp @@ -133,26 +133,6 @@ CON_COMMAND_F(zr_knockback_scale, "Global knockback scale", FCVAR_LINKED_CONCOMM g_flKnockbackScale = V_StringToFloat32(args[1], 5.0f); } -// Still need to implement weapon config -void ApplyKnockback(CCSPlayerPawn *pHuman, CCSPlayerPawn *pVictim, int iDamage, const char *szWeapon) -{ - Vector vecKnockback; - AngleVectors(pHuman->m_angEyeAngles(), &vecKnockback); - vecKnockback *= (iDamage * g_flKnockbackScale); - //Message("%f %f %f\n",vecKnockback.x, vecKnockback.y, vecKnockback.z); - pVictim->m_vecBaseVelocity = pVictim->m_vecBaseVelocity() + vecKnockback; -} - -void ApplyKnockbackExplosion(Z_CBaseEntity *pProjectile, CCSPlayerPawn *pVictim, int iDamage) -{ - Vector vecDisplacement = pVictim->GetAbsOrigin() - pProjectile->GetAbsOrigin(); - vecDisplacement.z += 36; - VectorNormalize(vecDisplacement); - Vector vecKnockback = vecDisplacement; - vecKnockback *= (iDamage * g_flKnockbackScale); - pVictim->m_vecBaseVelocity = pVictim->m_vecBaseVelocity() + vecKnockback; -} - void ZR_OnPlayerHurt(IGameEvent* pEvent) { CCSPlayerController *pAttacker = (CCSPlayerController*)pEvent->GetPlayerController("attacker"); From 055e063867a5ef069518749bf0f54c19b675c868 Mon Sep 17 00:00:00 2001 From: Connor <34824423+EasterLee@users.noreply.github.com> Date: Sun, 26 Nov 2023 20:41:16 -0500 Subject: [PATCH 03/13] Update zombiereborn.cpp --- src/zombiereborn.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/zombiereborn.cpp b/src/zombiereborn.cpp index c1e6253e..a41188ed 100644 --- a/src/zombiereborn.cpp +++ b/src/zombiereborn.cpp @@ -123,16 +123,6 @@ void ApplyKnockbackExplosion(Z_CBaseEntity *pProjectile, CCSPlayerPawn *pVictim, pVictim->m_vecBaseVelocity = pVictim->m_vecBaseVelocity() + vecKnockback; } -// CONVAR_TODO -float g_flKnockbackScale = 5.0f; -CON_COMMAND_F(zr_knockback_scale, "Global knockback scale", FCVAR_LINKED_CONCOMMAND | FCVAR_SPONLY) -{ - if (args.ArgC() < 2) - Msg("%s %f\n", args[0], g_flKnockbackScale); - else - g_flKnockbackScale = V_StringToFloat32(args[1], 5.0f); -} - void ZR_OnPlayerHurt(IGameEvent* pEvent) { CCSPlayerController *pAttacker = (CCSPlayerController*)pEvent->GetPlayerController("attacker"); From 68058e3e59bdccf9e88c73bc869711a6e36c1530 Mon Sep 17 00:00:00 2001 From: Connor <34824423+EasterLee@users.noreply.github.com> Date: Mon, 27 Nov 2023 14:59:23 -0500 Subject: [PATCH 04/13] Update zombiereborn.cpp --- src/zombiereborn.cpp | 79 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/src/zombiereborn.cpp b/src/zombiereborn.cpp index 5f210c68..70841d1b 100644 --- a/src/zombiereborn.cpp +++ b/src/zombiereborn.cpp @@ -30,6 +30,7 @@ extern CEntitySystem* g_pEntitySystem; extern IVEngineServer2* g_pEngineServer2; extern CGlobalVars* gpGlobals; extern CCSGameRules* g_pGameRules; +extern IGameEventManager2* g_gameEventManager; EZRRoundState g_ZRRoundState = EZRRoundState::ROUND_START; bool g_bEnableZR = false; @@ -130,15 +131,93 @@ void ApplyKnockbackExplosion(Z_CBaseEntity *pProjectile, CCSPlayerPawn *pVictim, pVictim->m_vecBaseVelocity = pVictim->m_vecBaseVelocity() + vecKnockback; } +void FakePlayerDeath(CCSPlayerController *pAttacker, CCSPlayerController *pVictim, const char *szWeapon) +{ + IGameEvent *pEvent = g_gameEventManager->CreateEvent("player_death"); + + if (!pEvent) + return; + //SetPlayer functions are swapped, need to remove the cast once fixed + pEvent->SetPlayer("userid", (CEntityInstance*)pVictim->GetPlayerSlot()); + pEvent->SetPlayer("attacker", (CEntityInstance*)pAttacker->GetPlayerSlot()); + pEvent->SetString("weapon", szWeapon); + + Message("\n--------------------------------\n" + "userid: %i\n" + "userid_pawn: %i\n" + "attacker: %i\n" + "attacker_pawn: %i\n" + "weapon: %s\n" + "--------------------------------\n", + pEvent->GetInt("userid"), + pEvent->GetInt("userid_pawn"), + pEvent->GetInt("attacker"), + pEvent->GetInt("attacker_pawn"), + pEvent->GetString("weapon")); + + g_gameEventManager->FireEvent(pEvent, false); + +} + +void Infect(CCSPlayerController *pAttacker, CCSPlayerController *pVictim) +{ + FakePlayerDeath(pAttacker, pVictim, "knife"); + pVictim->SwitchTeam(CS_TEAM_T); +} + + +void InfectMotherZombie(CCSPlayerController *pVictim) +{ + FakePlayerDeath(pVictim, pVictim, "prop_exploding_barrel"); + pVictim->SwitchTeam(CS_TEAM_T); +} + +CON_COMMAND_CHAT(infect, "infect a player") +{ + if (args.ArgC() < 2) + { + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Usage: !infect "); + return; + } + + int iCommandPlayer = player ? player->GetPlayerSlot() : -1; + int iNumClients = 0; + int pSlots[MAXPLAYERS]; + + ETargetType nType = g_playerManager->TargetPlayerString(iCommandPlayer, args[1], iNumClients, pSlots); + + if (!iNumClients) + { + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX"Target not found."); + return; + } + + if (!player) + return; + + for (int i = 0; i < iNumClients; i++) + { + CCSPlayerController* pTarget = CCSPlayerController::FromSlot(pSlots[i]); + + if (!pTarget) + continue; + + Infect(player, pTarget); + } +} + void ZR_OnPlayerHurt(IGameEvent* pEvent) { CCSPlayerController *pAttacker = (CCSPlayerController*)pEvent->GetPlayerController("attacker"); CCSPlayerController *pVictim = (CCSPlayerController*)pEvent->GetPlayerController("userid"); const char* szWeapon = pEvent->GetString("weapon"); int iDmgHealth = pEvent->GetInt("dmg_health"); + + //grenade and molotov knockbacks are handled by TakeDamage detours if (!pAttacker || !pVictim || strcmp(szWeapon, "") == 0 || strcmp(szWeapon, "inferno") == 0 || strcmp(szWeapon, "hegrenade") == 0) return; + if (pAttacker->m_iTeamNum() == CS_TEAM_CT && pVictim->m_iTeamNum() == CS_TEAM_T) ApplyKnockback((CCSPlayerPawn*)pAttacker->GetPawn(), (CCSPlayerPawn*)pVictim->GetPawn(), iDmgHealth, szWeapon); From 4276101fa66f5ddd5839010dd389a3a5420a2806 Mon Sep 17 00:00:00 2001 From: Connor <34824423+EasterLee@users.noreply.github.com> Date: Mon, 27 Nov 2023 19:58:48 -0500 Subject: [PATCH 05/13] move detour --- src/detours.cpp | 42 +++-------------------------------------- src/zombiereborn.cpp | 45 +++++++++++++++++++++++++++++++++----------- 2 files changed, 37 insertions(+), 50 deletions(-) diff --git a/src/detours.cpp b/src/detours.cpp index c7016ffc..19933ecc 100644 --- a/src/detours.cpp +++ b/src/detours.cpp @@ -112,47 +112,11 @@ void FASTCALL Detour_CBaseEntity_TakeDamageOld(Z_CBaseEntity *pThis, CTakeDamage inputInfo->m_bitsDamageType = DamageTypes_t::DMG_GENERIC; if (g_bEnableZR) - { - CCSPlayerController* pInflictorController = CCSPlayerController::FromPawn((CCSPlayerPawn*)pInflictor); - - if (pInflictorController && pThis->IsPawn() && pInflictorController->m_iTeamNum == CS_TEAM_T && pThis->m_iTeamNum == CS_TEAM_CT) - { - Message("Infection!\n"); - CCSPlayerController* pVictimController = CCSPlayerController::FromPawn((CCSPlayerPawn*)pThis); - - Vector vecPosition = pThis->GetAbsOrigin(); - QAngle angRotation = pThis->GetAbsRotation(); - - inputInfo->m_flDamage = 1000.0f; - CBaseEntity_TakeDamageOld(pThis, inputInfo); - - // using ChangeTeam here to also immediately respawn the player - pVictimController->ChangeTeam(CS_TEAM_T); - - CHandle handle = pThis->GetHandle(); - new CTimer(1.0f, false, [handle, vecPosition, angRotation] - { - Z_CBaseEntity* pPawn = handle.Get(); - - if (!pPawn || !pPawn->IsAlive()) - return -1.0f; - - pPawn->SetAbsOrigin(vecPosition); - pPawn->SetAbsRotation(angRotation); - - return -1.0f; - }); - - return; - } - - //grenade and molotov knockback CBaseEntity* pAttacker = inputInfo->m_hAttacker.Get(); - CCSPlayerController* pAttackerController = CCSPlayerController::FromPawn((CCSPlayerPawn*)pAttacker); - if (pAttackerController && pThis->IsPawn() && pAttackerController->m_iTeamNum == CS_TEAM_CT && pThis->m_iTeamNum == CS_TEAM_T) + if (pAttacker && pThis && pAttacker->IsPawn() && pThis->IsPawn()) { - if (V_strncmp(pszInflictorClass, "hegrenade", 9) || V_strncmp(pszInflictorClass, "inferno", 7)) - ApplyKnockbackExplosion((Z_CBaseEntity*)pInflictor, (CCSPlayerPawn*)pThis, (int)inputInfo->m_flDamage); + if (ZR_OnTakeDamageDetour((CCSPlayerPawn*)pAttacker, (CCSPlayerPawn*)pThis, inputInfo)) + return; } } diff --git a/src/zombiereborn.cpp b/src/zombiereborn.cpp index 9e071235..fe3bc40a 100644 --- a/src/zombiereborn.cpp +++ b/src/zombiereborn.cpp @@ -132,15 +132,15 @@ void ApplyKnockbackExplosion(Z_CBaseEntity *pProjectile, CCSPlayerPawn *pVictim, pVictim->m_vecBaseVelocity = pVictim->m_vecBaseVelocity() + vecKnockback; } -void FakePlayerDeath(CCSPlayerController *pAttacker, CCSPlayerController *pVictim, const char *szWeapon) +void FakePlayerDeath(CCSPlayerController *pAttackerController, CCSPlayerController *pVictimController, const char *szWeapon) { IGameEvent *pEvent = g_gameEventManager->CreateEvent("player_death"); if (!pEvent) return; //SetPlayer functions are swapped, need to remove the cast once fixed - pEvent->SetPlayer("userid", (CEntityInstance*)pVictim->GetPlayerSlot()); - pEvent->SetPlayer("attacker", (CEntityInstance*)pAttacker->GetPlayerSlot()); + pEvent->SetPlayer("userid", (CEntityInstance*)pVictimController->GetPlayerSlot()); + pEvent->SetPlayer("attacker", (CEntityInstance*)pAttackerController->GetPlayerSlot()); pEvent->SetString("weapon", szWeapon); Message("\n--------------------------------\n" @@ -160,19 +160,42 @@ void FakePlayerDeath(CCSPlayerController *pAttacker, CCSPlayerController *pVicti } -void Infect(CCSPlayerController *pAttacker, CCSPlayerController *pVictim) +void Infect(CCSPlayerController *pAttackerController, CCSPlayerController *pVictimController) { FakePlayerDeath(pAttacker, pVictim, "knife"); pVictim->SwitchTeam(CS_TEAM_T); } -void InfectMotherZombie(CCSPlayerController *pVictim) +void InfectMotherZombie(CCSPlayerController *pVictimController) { FakePlayerDeath(pVictim, pVictim, "prop_exploding_barrel"); pVictim->SwitchTeam(CS_TEAM_T); } + +bool ZR_OnTakeDamageDetour(CCSPlayerPawn *pAttackerPawn, CCSPlayerPawn *pVictimPawn, CTakeDamageInfo *pInfo) +{ + CCSPlayerController *pAttackerController = CCSPlayerController::FromPawn(pAttackerPawn); + CCSPlayerController *pVictimController = CCSPlayerController::FromPawn(pVictimPawn); + + if (pAttackerPawn->m_iTeamNum() == CS_TEAM_T && pVictimPawn->m_iTeamNum() == CS_TEAM_CT) + { + Infect(pAttackerController, pVictimController); + return true; // nullify the damage + } + + //grenade and molotov knockback + if (pAttackerPawn->m_iTeamNum() == CS_TEAM_CT && pVictimPawn->m_iTeamNum() == CS_TEAM_T) + { + CBaseEntity *pInflictor = inputInfo->m_hInflictor.Get(); + const char *pszInflictorClass = pInflictor ? pInflictor->GetClassname() : ""; + if (V_strncmp(pszInflictorClass, "hegrenade", 9) || V_strncmp(pszInflictorClass, "inferno", 7)) + ApplyKnockbackExplosion((Z_CBaseEntity*)pInflictor, (CCSPlayerPawn*)pVictimPawn, (int)inputInfo->m_flDamage); + } + return false; +} + CON_COMMAND_CHAT(infect, "infect a player") { if (args.ArgC() < 2) @@ -198,7 +221,7 @@ CON_COMMAND_CHAT(infect, "infect a player") for (int i = 0; i < iNumClients; i++) { - CCSPlayerController* pTarget = CCSPlayerController::FromSlot(pSlots[i]); + CCSPlayerController *pTarget = CCSPlayerController::FromSlot(pSlots[i]); if (!pTarget) continue; @@ -209,18 +232,18 @@ CON_COMMAND_CHAT(infect, "infect a player") void ZR_OnPlayerHurt(IGameEvent* pEvent) { - CCSPlayerController *pAttacker = (CCSPlayerController*)pEvent->GetPlayerController("attacker"); - CCSPlayerController *pVictim = (CCSPlayerController*)pEvent->GetPlayerController("userid"); + CCSPlayerController *pAttackerController = (CCSPlayerController*)pEvent->GetPlayerController("attacker"); + CCSPlayerController *pVictimController = (CCSPlayerController*)pEvent->GetPlayerController("userid"); const char* szWeapon = pEvent->GetString("weapon"); int iDmgHealth = pEvent->GetInt("dmg_health"); //grenade and molotov knockbacks are handled by TakeDamage detours - if (!pAttacker || !pVictim || strcmp(szWeapon, "") == 0 || strcmp(szWeapon, "inferno") == 0 || strcmp(szWeapon, "hegrenade") == 0) + if (!pAttackerController || !pVictimController || strcmp(szWeapon, "") == 0 || strcmp(szWeapon, "inferno") == 0 || strcmp(szWeapon, "hegrenade") == 0) return; - if (pAttacker->m_iTeamNum() == CS_TEAM_CT && pVictim->m_iTeamNum() == CS_TEAM_T) - ApplyKnockback((CCSPlayerPawn*)pAttacker->GetPawn(), (CCSPlayerPawn*)pVictim->GetPawn(), iDmgHealth, szWeapon); + if (pAttackerController->m_iTeamNum() == CS_TEAM_CT && pVictimController->m_iTeamNum() == CS_TEAM_T) + ApplyKnockback((CCSPlayerPawn*)pAttackerController->GetPawn(), (CCSPlayerPawn*)pVictimController->GetPawn(), iDmgHealth, szWeapon); //if (pAttacker->m_iTeamNum == CS_TEAM_CT && pVictim->m_iTeamNum == CS_TEAM_T) // Message("lol"); From 97a407ae2acd0a11658c09deff7e6e5107d16168 Mon Sep 17 00:00:00 2001 From: Connor <34824423+EasterLee@users.noreply.github.com> Date: Mon, 27 Nov 2023 23:04:12 -0500 Subject: [PATCH 06/13] add infection --- src/cs2_sdk/entity/cbaseentity.h | 1 + src/detours.cpp | 3 +- src/zombiereborn.cpp | 77 ++++++++++++-------------------- src/zombiereborn.h | 2 +- 4 files changed, 32 insertions(+), 51 deletions(-) diff --git a/src/cs2_sdk/entity/cbaseentity.h b/src/cs2_sdk/entity/cbaseentity.h index 64427eeb..9418a785 100644 --- a/src/cs2_sdk/entity/cbaseentity.h +++ b/src/cs2_sdk/entity/cbaseentity.h @@ -103,6 +103,7 @@ class Z_CBaseEntity : public CBaseEntity SCHEMA_FIELD(float, m_lastNetworkChange) SCHEMA_FIELD_POINTER(CNetworkTransmitComponent, m_NetworkTransmitComponent) SCHEMA_FIELD(int, m_iHealth) + SCHEMA_FIELD(int, m_iMaxHealth) SCHEMA_FIELD(int, m_iTeamNum) SCHEMA_FIELD(Vector, m_vecAbsVelocity) SCHEMA_FIELD(Vector, m_vecBaseVelocity) diff --git a/src/detours.cpp b/src/detours.cpp index 19933ecc..4bc69906 100644 --- a/src/detours.cpp +++ b/src/detours.cpp @@ -112,7 +112,8 @@ void FASTCALL Detour_CBaseEntity_TakeDamageOld(Z_CBaseEntity *pThis, CTakeDamage inputInfo->m_bitsDamageType = DamageTypes_t::DMG_GENERIC; if (g_bEnableZR) - CBaseEntity* pAttacker = inputInfo->m_hAttacker.Get(); + { + Z_CBaseEntity *pAttacker = (Z_CBaseEntity*)inputInfo->m_hAttacker.Get(); if (pAttacker && pThis && pAttacker->IsPawn() && pThis->IsPawn()) { if (ZR_OnTakeDamageDetour((CCSPlayerPawn*)pAttacker, (CCSPlayerPawn*)pThis, inputInfo)) diff --git a/src/zombiereborn.cpp b/src/zombiereborn.cpp index fe3bc40a..483fe6ed 100644 --- a/src/zombiereborn.cpp +++ b/src/zombiereborn.cpp @@ -32,6 +32,8 @@ extern CGlobalVars* gpGlobals; extern CCSGameRules* g_pGameRules; extern IGameEventManager2* g_gameEventManager; +void ZR_Infect(CCSPlayerController *pAttackerController, CCSPlayerController *pVictimController, bool bBroadcast); + EZRRoundState g_ZRRoundState = EZRRoundState::ROUND_START; bool g_bEnableZR = false; @@ -98,8 +100,8 @@ void ZR_OnPlayerSpawn(IGameEvent* pEvent) { CCSPlayerController* pController = (CCSPlayerController*)pEvent->GetPlayerController("userid"); - if (g_ZRRoundState == EZRRoundState::POST_INFECTION && pController->m_iTeamNum == CS_TEAM_CT) - pController->SwitchTeam(CS_TEAM_T); + if (pController && g_ZRRoundState == EZRRoundState::POST_INFECTION && pController->m_iTeamNum == CS_TEAM_CT) + ZR_Infect(pController, pController, false); //set health and probably model doesn't work here } // CONVAR_TODO @@ -113,7 +115,7 @@ CON_COMMAND_F(zr_knockback_scale, "Global knockback scale", FCVAR_LINKED_CONCOMM } // Still need to implement weapon config -void ApplyKnockback(CCSPlayerPawn *pHuman, CCSPlayerPawn *pVictim, int iDamage, const char *szWeapon) +void ZR_ApplyKnockback(CCSPlayerPawn *pHuman, CCSPlayerPawn *pVictim, int iDamage, const char *szWeapon) { Vector vecKnockback; AngleVectors(pHuman->m_angEyeAngles(), &vecKnockback); @@ -122,7 +124,7 @@ void ApplyKnockback(CCSPlayerPawn *pHuman, CCSPlayerPawn *pVictim, int iDamage, pVictim->m_vecBaseVelocity = pVictim->m_vecBaseVelocity() + vecKnockback; } -void ApplyKnockbackExplosion(Z_CBaseEntity *pProjectile, CCSPlayerPawn *pVictim, int iDamage) +void ZR_ApplyKnockbackExplosion(Z_CBaseEntity *pProjectile, CCSPlayerPawn *pVictim, int iDamage) { Vector vecDisplacement = pVictim->GetAbsOrigin() - pProjectile->GetAbsOrigin(); vecDisplacement.z += 36; @@ -132,7 +134,7 @@ void ApplyKnockbackExplosion(Z_CBaseEntity *pProjectile, CCSPlayerPawn *pVictim, pVictim->m_vecBaseVelocity = pVictim->m_vecBaseVelocity() + vecKnockback; } -void FakePlayerDeath(CCSPlayerController *pAttackerController, CCSPlayerController *pVictimController, const char *szWeapon) +void ZR_FakePlayerDeath(CCSPlayerController *pAttackerController, CCSPlayerController *pVictimController, const char *szWeapon) { IGameEvent *pEvent = g_gameEventManager->CreateEvent("player_death"); @@ -160,17 +162,28 @@ void FakePlayerDeath(CCSPlayerController *pAttackerController, CCSPlayerControll } -void Infect(CCSPlayerController *pAttackerController, CCSPlayerController *pVictimController) +void ZR_Infect(CCSPlayerController *pAttackerController, CCSPlayerController *pVictimController, bool bBroadcast) { - FakePlayerDeath(pAttacker, pVictim, "knife"); - pVictim->SwitchTeam(CS_TEAM_T); + if (bBroadcast) + ZR_FakePlayerDeath(pAttackerController, pVictimController, "knife"); // or any other killicon + pVictimController->SwitchTeam(CS_TEAM_T); + + CCSPlayerPawn *pVictimPawn = (CCSPlayerPawn*)pVictimController->GetPawn(); + if (!pVictimPawn) + return; + //set model/health/etc here + + pVictimPawn->m_iMaxHealth = 10000; + pVictimPawn->m_iHealth = 10000; } -void InfectMotherZombie(CCSPlayerController *pVictimController) +void ZR_InfectMotherZombie(CCSPlayerController *pVictimController) { - FakePlayerDeath(pVictim, pVictim, "prop_exploding_barrel"); - pVictim->SwitchTeam(CS_TEAM_T); + ZR_FakePlayerDeath(pVictimController, pVictimController, "prop_exploding_barrel"); // or any other killicon + pVictimController->SwitchTeam(CS_TEAM_T); + + //set model/health/etc here } @@ -181,55 +194,21 @@ bool ZR_OnTakeDamageDetour(CCSPlayerPawn *pAttackerPawn, CCSPlayerPawn *pVictimP if (pAttackerPawn->m_iTeamNum() == CS_TEAM_T && pVictimPawn->m_iTeamNum() == CS_TEAM_CT) { - Infect(pAttackerController, pVictimController); + ZR_Infect(pAttackerController, pVictimController, true); return true; // nullify the damage } //grenade and molotov knockback if (pAttackerPawn->m_iTeamNum() == CS_TEAM_CT && pVictimPawn->m_iTeamNum() == CS_TEAM_T) { - CBaseEntity *pInflictor = inputInfo->m_hInflictor.Get(); + CBaseEntity *pInflictor = pInfo->m_hInflictor.Get(); const char *pszInflictorClass = pInflictor ? pInflictor->GetClassname() : ""; if (V_strncmp(pszInflictorClass, "hegrenade", 9) || V_strncmp(pszInflictorClass, "inferno", 7)) - ApplyKnockbackExplosion((Z_CBaseEntity*)pInflictor, (CCSPlayerPawn*)pVictimPawn, (int)inputInfo->m_flDamage); + ZR_ApplyKnockbackExplosion((Z_CBaseEntity*)pInflictor, (CCSPlayerPawn*)pVictimPawn, (int)pInfo->m_flDamage); } return false; } -CON_COMMAND_CHAT(infect, "infect a player") -{ - if (args.ArgC() < 2) - { - ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Usage: !infect "); - return; - } - - int iCommandPlayer = player ? player->GetPlayerSlot() : -1; - int iNumClients = 0; - int pSlots[MAXPLAYERS]; - - ETargetType nType = g_playerManager->TargetPlayerString(iCommandPlayer, args[1], iNumClients, pSlots); - - if (!iNumClients) - { - ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX"Target not found."); - return; - } - - if (!player) - return; - - for (int i = 0; i < iNumClients; i++) - { - CCSPlayerController *pTarget = CCSPlayerController::FromSlot(pSlots[i]); - - if (!pTarget) - continue; - - Infect(player, pTarget); - } -} - void ZR_OnPlayerHurt(IGameEvent* pEvent) { CCSPlayerController *pAttackerController = (CCSPlayerController*)pEvent->GetPlayerController("attacker"); @@ -243,7 +222,7 @@ void ZR_OnPlayerHurt(IGameEvent* pEvent) return; if (pAttackerController->m_iTeamNum() == CS_TEAM_CT && pVictimController->m_iTeamNum() == CS_TEAM_T) - ApplyKnockback((CCSPlayerPawn*)pAttackerController->GetPawn(), (CCSPlayerPawn*)pVictimController->GetPawn(), iDmgHealth, szWeapon); + ZR_ApplyKnockback((CCSPlayerPawn*)pAttackerController->GetPawn(), (CCSPlayerPawn*)pVictimController->GetPawn(), iDmgHealth, szWeapon); //if (pAttacker->m_iTeamNum == CS_TEAM_CT && pVictim->m_iTeamNum == CS_TEAM_T) // Message("lol"); diff --git a/src/zombiereborn.h b/src/zombiereborn.h index 16b65e90..b206a433 100644 --- a/src/zombiereborn.h +++ b/src/zombiereborn.h @@ -39,4 +39,4 @@ void ZR_OnRoundStart(IGameEvent* pEvent); void ZR_OnPlayerSpawn(IGameEvent* pEvent); void ZR_OnPlayerHurt(IGameEvent* pEvent); void ZR_OnPlayerDeath(IGameEvent* pEvent); -void ApplyKnockbackExplosion(Z_CBaseEntity *pProjectile, CCSPlayerPawn *pVictim, int iDamage); \ No newline at end of file +bool ZR_OnTakeDamageDetour(CCSPlayerPawn *pAttackerPawn, CCSPlayerPawn *pVictimPawn, CTakeDamageInfo *pInfo); \ No newline at end of file From c87c5910707dc22496499a873e8c33c262cf23a0 Mon Sep 17 00:00:00 2001 From: Connor <34824423+EasterLee@users.noreply.github.com> Date: Tue, 28 Nov 2023 18:22:17 -0500 Subject: [PATCH 07/13] pawn+controller respawn gamedata --- gamedata/cs2fixes.games.txt | 11 +++++++++++ src/addresses.h | 1 + src/cs2_sdk/entity/ccsplayercontroller.h | 6 ++++++ src/cs2_sdk/entity/ccsplayerpawn.h | 6 ++++++ 4 files changed, 24 insertions(+) diff --git a/gamedata/cs2fixes.games.txt b/gamedata/cs2fixes.games.txt index 7cb9ccfb..dc93f641 100644 --- a/gamedata/cs2fixes.games.txt +++ b/gamedata/cs2fixes.games.txt @@ -256,6 +256,12 @@ "windows" "\x40\x56\x57\x48\x83\xEC\x58\x48\x8B\x41\x10" "linux" "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x41\x54\x49\x89\xFC\x53\x48\x83\xEC\x38\x4C\x8D\x2D\x2A\x2A\x2A\x2A\x49\x8B\x7D\x00\x48\x85\xFF\x0F\x84\x2A\x2A\x2A\x2A" } + "CCSPlayerPawn_Respawn" + { + "library" "server" + "windows" "\x40\x53\x48\x83\xEC\x20\x8B\x91\x38\x0B\x00\x00\x48\x8B\xD9" + "linux" "\x8B\x8F\x40\x0E\x00\x00\x83\xF9\xFF\x0F\x84\xD9\x01" + } } "Offsets" { @@ -309,6 +315,11 @@ "windows" "27" "linux" "28" } + "CCSPlayerController_Respawn" + { + "windows" "241" + "linux" "243" + } } "Patches" { diff --git a/src/addresses.h b/src/addresses.h index f9904068..e62e21f6 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -55,6 +55,7 @@ namespace addresses inline void(FASTCALL *ClientPrint)(CBasePlayerController *player, int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4); inline void(FASTCALL *SetGroundEntity)(Z_CBaseEntity *ent, Z_CBaseEntity *ground); inline void(FASTCALL *CCSPlayerController_SwitchTeam)(CCSPlayerController *pController, uint32 team); + inline void(FASTCALL *CCSPlayerPawn_Respawn)(CCSPlayerPawn *pPawn); inline void(FASTCALL *UTIL_Remove)(CEntityInstance*); inline void(FASTCALL *CEntitySystem_AddEntityIOEvent)(CEntitySystem *pEntitySystem, CEntityInstance *pTarget, const char *pszInput, diff --git a/src/cs2_sdk/entity/ccsplayercontroller.h b/src/cs2_sdk/entity/ccsplayercontroller.h index c314be96..0c79927d 100644 --- a/src/cs2_sdk/entity/ccsplayercontroller.h +++ b/src/cs2_sdk/entity/ccsplayercontroller.h @@ -68,4 +68,10 @@ class CCSPlayerController : public CBasePlayerController addresses::CCSPlayerController_SwitchTeam(this, iTeam); } } + + void Respawn() + { + static int offset = g_GameConfig->GetOffset("CCSPlayerController_Respawn"); + CALL_VIRTUAL(void, offset, this); + } }; \ No newline at end of file diff --git a/src/cs2_sdk/entity/ccsplayerpawn.h b/src/cs2_sdk/entity/ccsplayerpawn.h index 5fffd7ce..aab336ff 100644 --- a/src/cs2_sdk/entity/ccsplayerpawn.h +++ b/src/cs2_sdk/entity/ccsplayerpawn.h @@ -34,4 +34,10 @@ class CCSPlayerPawn : public CCSPlayerPawnBase DECLARE_SCHEMA_CLASS(CCSPlayerPawn); SCHEMA_FIELD(CCSPlayer_ActionTrackingServices*, m_pActionTrackingServices) + + + void Respawn() + { + addresses::CCSPlayerPawn_Respawn(this); + } }; \ No newline at end of file From 6b22bf0b26b0d71803362fa6e1efdc0911d8bc7a Mon Sep 17 00:00:00 2001 From: Connor <34824423+EasterLee@users.noreply.github.com> Date: Tue, 28 Nov 2023 18:36:58 -0500 Subject: [PATCH 08/13] add resolve_sig --- src/addresses.cpp | 1 + src/addresses.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/addresses.cpp b/src/addresses.cpp index 1343908a..23eddc25 100644 --- a/src/addresses.cpp +++ b/src/addresses.cpp @@ -55,6 +55,7 @@ bool addresses::Initialize(CGameConfig *g_GameConfig) RESOLVE_SIG(g_GameConfig, "ClientPrint", addresses::ClientPrint); RESOLVE_SIG(g_GameConfig, "SetGroundEntity", addresses::SetGroundEntity); RESOLVE_SIG(g_GameConfig, "CCSPlayerController_SwitchTeam", addresses::CCSPlayerController_SwitchTeam); + RESOLVE_SIG(g_GameConfig, "CCSPlayerPawn_Respawn", addresses::CCSPlayerController_SwitchTeam); RESOLVE_SIG(g_GameConfig, "UTIL_Remove", addresses::UTIL_Remove); RESOLVE_SIG(g_GameConfig, "CEntitySystem_AddEntityIOEvent", addresses::CEntitySystem_AddEntityIOEvent); RESOLVE_SIG(g_GameConfig, "CEntityInstance_AcceptInput", addresses::CEntityInstance_AcceptInput); diff --git a/src/addresses.h b/src/addresses.h index e62e21f6..6fe4e744 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -39,6 +39,7 @@ namespace modules class CEntityInstance; class CBasePlayerController; class CCSPlayerController; +class CCSPlayerPawn; class Z_CBaseEntity; class CGameConfig; class CEntitySystem; From 7749fe2d5060552c3321b4dd9d60a37b4af8cc95 Mon Sep 17 00:00:00 2001 From: Connor <34824423+EasterLee@users.noreply.github.com> Date: Tue, 28 Nov 2023 23:19:20 -0500 Subject: [PATCH 09/13] fix address --- src/addresses.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/addresses.cpp b/src/addresses.cpp index 23eddc25..a20a226e 100644 --- a/src/addresses.cpp +++ b/src/addresses.cpp @@ -55,7 +55,7 @@ bool addresses::Initialize(CGameConfig *g_GameConfig) RESOLVE_SIG(g_GameConfig, "ClientPrint", addresses::ClientPrint); RESOLVE_SIG(g_GameConfig, "SetGroundEntity", addresses::SetGroundEntity); RESOLVE_SIG(g_GameConfig, "CCSPlayerController_SwitchTeam", addresses::CCSPlayerController_SwitchTeam); - RESOLVE_SIG(g_GameConfig, "CCSPlayerPawn_Respawn", addresses::CCSPlayerController_SwitchTeam); + RESOLVE_SIG(g_GameConfig, "CCSPlayerPawn_Respawn", addresses::CCSPlayerPawn_Respawn); RESOLVE_SIG(g_GameConfig, "UTIL_Remove", addresses::UTIL_Remove); RESOLVE_SIG(g_GameConfig, "CEntitySystem_AddEntityIOEvent", addresses::CEntitySystem_AddEntityIOEvent); RESOLVE_SIG(g_GameConfig, "CEntityInstance_AcceptInput", addresses::CEntityInstance_AcceptInput); From 1c9c55a4989d0ce1662d31b339bdd73865db0c3e Mon Sep 17 00:00:00 2001 From: Connor <34824423+EasterLee@users.noreply.github.com> Date: Wed, 29 Nov 2023 20:00:52 -0500 Subject: [PATCH 10/13] add zspawn command --- src/zombiereborn.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/zombiereborn.cpp b/src/zombiereborn.cpp index 483fe6ed..e6881005 100644 --- a/src/zombiereborn.cpp +++ b/src/zombiereborn.cpp @@ -45,6 +45,35 @@ CON_COMMAND_F(zr_enable, "Whether to enable ZR features", FCVAR_LINKED_CONCOMMAN g_bEnableZR = V_StringToBool(args[1], false); } +CON_COMMAND_CHAT(zspawn, "respawn yourself") +{ + // Silently return so the command is completely hidden + if (!g_bEnableZR) + return; + + if (!player) + { + ClientPrint(player, HUD_PRINTCONSOLE, CHAT_PREFIX "You cannot use this command from the server console."); + return; + } + + CCSPlayerPawn *pPawn = (CCSPlayerPawn*)player->GetPawn(); + if (!pPawn) + { + ClientPrint(player, HUD_PRINTCONSOLE, CHAT_PREFIX "Invalid Pawn."); + return; + } + ClientPrint(player, HUD_PRINTCONSOLE, CHAT_PREFIX "Classname: %s", pPawn->GetClassname()); + if (pPawn->IsAlive()) + { + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX"You must be dead to respawn!"); + return; + } + + player->Respawn(); + pPawn->Respawn(); +} + void SetUpAllHumanClasses() { for (int i = 0; i < gpGlobals->maxClients; i++) From a25e43e265e5443c1ee525b5804f69f71c210f56 Mon Sep 17 00:00:00 2001 From: Connor <34824423+EasterLee@users.noreply.github.com> Date: Fri, 1 Dec 2023 16:32:24 -0500 Subject: [PATCH 11/13] mother zombie infection --- cfg/cs2fixes/cs2fixes.cfg | 7 +- src/events.cpp | 6 ++ src/zombiereborn.cpp | 186 +++++++++++++++++++++++++++----------- src/zombiereborn.h | 18 +++- 4 files changed, 164 insertions(+), 53 deletions(-) diff --git a/cfg/cs2fixes/cs2fixes.cfg b/cfg/cs2fixes/cs2fixes.cfg index 579b05d1..a623a612 100644 --- a/cfg/cs2fixes/cs2fixes.cfg +++ b/cfg/cs2fixes/cs2fixes.cfg @@ -33,4 +33,9 @@ cs2f_rtv_endround 0 // Whether to immediately end the round when RTV succeed zr_enable 0 // Whether to enable ZR features zr_knockback_scale 5.0 // Global knockback scale zr_ztele_max_distance 150.0 // Maximum distance players are allowed to move after starting ztele -zr_ztele_allow_humans 0 // Whether to allow humans to use ztele \ No newline at end of file +zr_ztele_allow_humans 0 // Whether to allow humans to use ztele +zr_infect_spawn_type 1 //Type of Mother Zombies Spawn [0 = MZ spawn where they stand, 1 = MZ get teleported back to spawn on being picked] +zr_infect_spawn_time_min 15 //Minimum time in which Mother Zombies should be picked, after round start +zr_infect_spawn_time_max 15 //Maximum time in which Mother Zombies should be picked, after round start +zr_infect_spawn_mz_ratio 7 //Ratio of all Players to Mother Zombies to be spawned at round start +zr_infect_spawn_mz_min_count 2 //Minimum amount of Mother Zombies to be spawned at round start \ No newline at end of file diff --git a/src/events.cpp b/src/events.cpp index b0feceb6..0d58e592 100644 --- a/src/events.cpp +++ b/src/events.cpp @@ -261,4 +261,10 @@ GAME_EVENT_F(round_end) pPlayer->SetTotalDamage(0); } +} + +GAME_EVENT_F(round_freeze_end) +{ + if (g_bEnableZR) + ZR_OnRoundFreezeEnd(pEvent); } \ No newline at end of file diff --git a/src/zombiereborn.cpp b/src/zombiereborn.cpp index 5c895546..d32614f4 100644 --- a/src/zombiereborn.cpp +++ b/src/zombiereborn.cpp @@ -18,6 +18,7 @@ */ #include "commands.h" +#include "utils/entity.h" #include "playermanager.h" #include "ctimer.h" #include "eventlistener.h" @@ -36,34 +37,29 @@ extern IGameEventManager2* g_gameEventManager; void ZR_Infect(CCSPlayerController *pAttackerController, CCSPlayerController *pVictimController, bool bBroadcast); EZRRoundState g_ZRRoundState = EZRRoundState::ROUND_START; +static int g_iRoundNum = 0; +static int g_iInfectionCountDown = 0; // CONVAR_TODO bool g_bEnableZR = false; static float g_flMaxZteleDistance = 150.0f; static bool g_bZteleHuman = false; - -CON_COMMAND_F(zr_enable, "Whether to enable ZR features", FCVAR_LINKED_CONCOMMAND | FCVAR_SPONLY) -{ - if (args.ArgC() < 2) - Msg("%s %i\n", args[0], g_bEnableZR); - else - g_bEnableZR = V_StringToBool(args[1], false); -} - -CON_COMMAND_F(zr_ztele_max_distance, "Maximum distance players are allowed to move after starting ztele", FCVAR_LINKED_CONCOMMAND | FCVAR_SPONLY) -{ - if (args.ArgC() < 2) - Msg("%s %f\n", args[0], g_flMaxZteleDistance); - else - g_flMaxZteleDistance = V_StringToFloat32(args[1], 150.0f); -} -CON_COMMAND_F(zr_ztele_allow_humans, "Whether to allow humans to use ztele", FCVAR_LINKED_CONCOMMAND | FCVAR_SPONLY) -{ - if (args.ArgC() < 2) - Msg("%s %i\n", args[0], g_bZteleHuman); - else - g_bZteleHuman = V_StringToBool(args[1], false); -} +static float g_flKnockbackScale = 5.0f; +static int g_flInfectSpawnType = EZRSpawnType::RESPAWN; +static int g_flInfectSpawnTimeMin = 15; +static int g_flInfectSpawnTimeMax = 15; +static int g_flInfectSpawnMZRatio = 7; +static int g_flInfectSpawnMinCount = 2; + +CON_ZR_CVAR(zr_enable, "Whether to enable ZR features", g_bEnableZR, Bool, false) +CON_ZR_CVAR(zr_ztele_max_distance, "Maximum distance players are allowed to move after starting ztele", g_flMaxZteleDistance, Float32, 150.0f) +CON_ZR_CVAR(zr_ztele_allow_humans, "Whether to allow humans to use ztele", g_bZteleHuman, Bool, false) +CON_ZR_CVAR(zr_knockback_scale, "Global knockback scale", g_flKnockbackScale, Float32, 5.0f) +CON_ZR_CVAR(zr_infect_spawn_type, "Type of Mother Zombies Spawn [0 = MZ spawn where they stand, 1 = MZ get teleported back to spawn on being picked]", g_flInfectSpawnType, Int32, EZRSpawnType::RESPAWN) +CON_ZR_CVAR(zr_infect_spawn_time_min, "Minimum time in which Mother Zombies should be picked, after round start", g_flInfectSpawnTimeMin, Int32, 15) +CON_ZR_CVAR(zr_infect_spawn_time_max, "Maximum time in which Mother Zombies should be picked, after round start", g_flInfectSpawnTimeMax, Int32, 15) +CON_ZR_CVAR(zr_infect_spawn_mz_ratio, "Ratio of all Players to Mother Zombies to be spawned at round start", g_flInfectSpawnMZRatio, Int32, 7) +CON_ZR_CVAR(zr_infect_spawn_mz_min_count, "Minimum amount of Mother Zombies to be spawned at round start", g_flInfectSpawnMinCount, Int32, 2) CON_COMMAND_CHAT(zspawn, "respawn yourself") { @@ -126,18 +122,13 @@ void ZR_OnStartupServer() void ZR_OnRoundPrestart(IGameEvent* pEvent) { g_ZRRoundState = EZRRoundState::ROUND_START; + g_iRoundNum++; } void ZR_OnRoundStart(IGameEvent* pEvent) { ClientPrintAll(HUD_PRINTTALK, ZR_PREFIX "The game is \x05Humans vs. Zombies\x01, the goal for zombies is to infect all humans by knifing them."); - new CTimer(1.0f, false, []() - { - g_ZRRoundState = EZRRoundState::POST_INFECTION; - return 1.0f; - }); - // SetUpAllHumanClasses(); // SetupRespawnToggler(); // SetupAmmoReplenish(); @@ -150,17 +141,21 @@ void ZR_OnPlayerSpawn(IGameEvent* pEvent) CCSPlayerController* pController = (CCSPlayerController*)pEvent->GetPlayerController("userid"); if (pController && g_ZRRoundState == EZRRoundState::POST_INFECTION && pController->m_iTeamNum == CS_TEAM_CT) - ZR_Infect(pController, pController, false); //set health and probably model doesn't work here -} + { + // infect player on the next frame + int iRoundNum = g_iRoundNum; + CHandle handle = pController->GetHandle(); + new CTimer(0.05f, false, [iRoundNum, handle]() + { + CCSPlayerController* pController = (CCSPlayerController*)handle.Get(); + if (iRoundNum != g_iRoundNum || !pController) + return -1.0f; -// CONVAR_TODO -float g_flKnockbackScale = 5.0f; -CON_COMMAND_F(zr_knockback_scale, "Global knockback scale", FCVAR_LINKED_CONCOMMAND | FCVAR_SPONLY) -{ - if (args.ArgC() < 2) - Msg("%s %f\n", args[0], g_flKnockbackScale); - else - g_flKnockbackScale = V_StringToFloat32(args[1], 5.0f); + ZR_Infect(pController, pController, false); + + return -1.0f; + }); + } } // Still need to implement weapon config @@ -189,7 +184,7 @@ void ZR_FakePlayerDeath(CCSPlayerController *pAttackerController, CCSPlayerContr if (!pEvent) return; - //SetPlayer functions are swapped, need to remove the cast once fixed + // SetPlayer functions are swapped, need to remove the cast once fixed pEvent->SetPlayer("userid", (CEntityInstance*)pVictimController->GetPlayerSlot()); pEvent->SetPlayer("attacker", (CEntityInstance*)pAttackerController->GetPlayerSlot()); pEvent->SetString("weapon", szWeapon); @@ -220,7 +215,7 @@ void ZR_Infect(CCSPlayerController *pAttackerController, CCSPlayerController *pV CCSPlayerPawn *pVictimPawn = (CCSPlayerPawn*)pVictimController->GetPawn(); if (!pVictimPawn) return; - //set model/health/etc here + // set model/health/etc here pVictimPawn->m_iMaxHealth = 10000; pVictimPawn->m_iHealth = 10000; @@ -229,12 +224,103 @@ void ZR_Infect(CCSPlayerController *pAttackerController, CCSPlayerController *pV void ZR_InfectMotherZombie(CCSPlayerController *pVictimController) { - ZR_FakePlayerDeath(pVictimController, pVictimController, "prop_exploding_barrel"); // or any other killicon pVictimController->SwitchTeam(CS_TEAM_T); + CCSPlayerPawn *pVictimPawn = (CCSPlayerPawn*)pVictimController->GetPawn(); + if (!pVictimPawn) + return; //set model/health/etc here + + // set model/health/etc here + + pVictimPawn->m_iMaxHealth = 10000; + pVictimPawn->m_iHealth = 10000; +} + +void ZR_InitialInfection() +{ + // grab player count and mz infection candidates + CUtlVector pCandidateControllers; + int iPlayerCount = 0; + for (int i = 0; i < gpGlobals->maxClients; i++) + { + CCSPlayerController* pController = CCSPlayerController::FromSlot(i); + if (!pController) + continue; + iPlayerCount++; + if (pController->m_iTeamNum() != CS_TEAM_CT) + continue; + + CCSPlayerController* pPawn = (CCSPlayerController*)pController->GetPawn(); + if (!pPawn || !pPawn->IsAlive()) + continue; + + pCandidateControllers.AddToTail(pController); + } + + // calculate the num of mz to infect + int iMZToInfect = iPlayerCount / g_flInfectSpawnMZRatio; + iMZToInfect = g_flInfectSpawnMinCount > iMZToInfect ? g_flInfectSpawnMinCount : iMZToInfect; + + // get spawn points + CUtlVector spawns; + if (g_flInfectSpawnType == EZRSpawnType::RESPAWN) + { + SpawnPoint* spawn = nullptr; + while (nullptr != (spawn = (SpawnPoint*)UTIL_FindEntityByClassname(spawn, "info_player_*"))) + { + if (spawn->m_bEnabled()) + spawns.AddToTail(spawn); + } + } + + // infect + while (pCandidateControllers.Count() > 0 && iMZToInfect > 0) + { + int randomindex = rand() % pCandidateControllers.Count(); + ZR_InfectMotherZombie(pCandidateControllers[randomindex]); + + CCSPlayerController* pPawn = (CCSPlayerController*)pCandidateControllers[randomindex]->GetPawn(); + if (pPawn && spawns.Count()) + { + int randomindex = rand() % spawns.Count(); + pPawn->SetAbsOrigin(spawns[randomindex]->GetAbsOrigin()); + pPawn->SetAbsRotation(spawns[randomindex]->GetAbsRotation()); + } + + pCandidateControllers.FastRemove(randomindex); + iMZToInfect--; + } + ClientPrintAll(HUD_PRINTCENTER, "First infection has started!"); + ClientPrintAll(HUD_PRINTTALK, ZR_PREFIX "First infection has started! Good luck, survivors!"); + g_ZRRoundState = EZRRoundState::POST_INFECTION; } +void ZR_StartInitialCountdown() +{ + int iRoundNum = g_iRoundNum; + g_iInfectionCountDown = g_flInfectSpawnTimeMin + (rand() % (g_flInfectSpawnTimeMax - g_flInfectSpawnTimeMin + 1)); + new CTimer(1.0f, false, [iRoundNum]() + { + if (iRoundNum != g_iRoundNum) + return -1.0f; + if (g_iInfectionCountDown <= 0) + { + ZR_InitialInfection(); + return -1.0f; + } + + if (g_iInfectionCountDown <= 15) + { + ClientPrintAll(HUD_PRINTCENTER, "First infection in \7%i second(s)\1!", g_iInfectionCountDown); + if (g_iInfectionCountDown % 5 == 0) + ClientPrintAll(HUD_PRINTTALK, ZR_PREFIX "First infection in \7%i second\1!", g_iInfectionCountDown); + } + g_iInfectionCountDown--; + + return 1.0f; + }); +} bool ZR_Detour_TakeDamageOld(CCSPlayerPawn *pVictimPawn, CTakeDamageInfo *pInfo) { @@ -252,7 +338,7 @@ bool ZR_Detour_TakeDamageOld(CCSPlayerPawn *pVictimPawn, CTakeDamageInfo *pInfo) return true; // nullify the damage } - //grenade and molotov knockback + // grenade and molotov knockback if (pAttackerPawn->m_iTeamNum() == CS_TEAM_CT && pVictimPawn->m_iTeamNum() == CS_TEAM_T) { CBaseEntity *pInflictor = pInfo->m_hInflictor.Get(); @@ -271,19 +357,12 @@ void ZR_OnPlayerHurt(IGameEvent* pEvent) int iDmgHealth = pEvent->GetInt("dmg_health"); - //grenade and molotov knockbacks are handled by TakeDamage detours + // grenade and molotov knockbacks are handled by TakeDamage detours if (!pAttackerController || !pVictimController || strcmp(szWeapon, "") == 0 || strcmp(szWeapon, "inferno") == 0 || strcmp(szWeapon, "hegrenade") == 0) return; if (pAttackerController->m_iTeamNum() == CS_TEAM_CT && pVictimController->m_iTeamNum() == CS_TEAM_T) ZR_ApplyKnockback((CCSPlayerPawn*)pAttackerController->GetPawn(), (CCSPlayerPawn*)pVictimController->GetPawn(), iDmgHealth, szWeapon); - - //if (pAttacker->m_iTeamNum == CS_TEAM_CT && pVictim->m_iTeamNum == CS_TEAM_T) - // Message("lol"); - // //Knockback_Apply(pAttacker, pVictim, iDmgHealth, szWeapon); - //else if (szWeapon == "knife" && pAttacker->m_iTeamNum == CS_TEAM_T && pVictim->m_iTeamNum == CS_TEAM_CT) - // Message("lol"); - // //Infect(pAttacker, pVictim, true, iHealth == 0); } void ZR_OnPlayerDeath(IGameEvent* pEvent) @@ -299,6 +378,11 @@ void ZR_OnPlayerDeath(IGameEvent* pEvent) }*/ } +void ZR_OnRoundFreezeEnd(IGameEvent* pEvent) +{ + ZR_StartInitialCountdown(); +} + CON_COMMAND_CHAT(ztele, "teleport to spawn") { // Silently return so the command is completely hidden diff --git a/src/zombiereborn.h b/src/zombiereborn.h index 1093aec3..a83337a0 100644 --- a/src/zombiereborn.h +++ b/src/zombiereborn.h @@ -29,9 +29,14 @@ enum class EZRRoundState ROUND_END, }; +enum EZRSpawnType +{ + IN_PLACE, + RESPAWN, +}; + extern bool g_bEnableZR; extern EZRRoundState g_ZRRoundState; -extern float g_flKnockbackScale; void ZR_OnStartupServer(); void ZR_OnRoundPrestart(IGameEvent* pEvent); @@ -39,4 +44,15 @@ void ZR_OnRoundStart(IGameEvent* pEvent); void ZR_OnPlayerSpawn(IGameEvent* pEvent); void ZR_OnPlayerHurt(IGameEvent* pEvent); void ZR_OnPlayerDeath(IGameEvent* pEvent); +void ZR_OnRoundFreezeEnd(IGameEvent* pEvent); bool ZR_Detour_TakeDamageOld(CCSPlayerPawn *pVictimPawn, CTakeDamageInfo *pInfo); + +// need to replace with actual cvar someday +#define CON_ZR_CVAR(name, description, variable_name, variable_type, variable_default) \ + CON_COMMAND_F(name, description, FCVAR_LINKED_CONCOMMAND | FCVAR_SPONLY) \ + { \ + if (args.ArgC() < 2) \ + Msg("%s %i\n", args[0], variable_name); \ + else \ + variable_name = V_StringTo##variable_type(args[1], variable_default); \ + } From 3de7e1ab548d27e7eb6d2253fca304ccdf20ac93 Mon Sep 17 00:00:00 2001 From: Connor <34824423+EasterLee@users.noreply.github.com> Date: Sat, 2 Dec 2023 17:36:17 -0500 Subject: [PATCH 12/13] setmodel + win condition --- gamedata/cs2fixes.games.txt | 13 ++++ src/addresses.cpp | 2 + src/addresses.h | 4 ++ src/cs2_sdk/entity/cbaseplayerpawn.h | 4 ++ src/cs2_sdk/entity/cgamerules.h | 5 ++ src/events.cpp | 6 ++ src/zombiereborn.cpp | 103 +++++++++++++++++++++------ 7 files changed, 115 insertions(+), 22 deletions(-) diff --git a/gamedata/cs2fixes.games.txt b/gamedata/cs2fixes.games.txt index dc93f641..a8b21a64 100644 --- a/gamedata/cs2fixes.games.txt +++ b/gamedata/cs2fixes.games.txt @@ -262,6 +262,19 @@ "windows" "\x40\x53\x48\x83\xEC\x20\x8B\x91\x38\x0B\x00\x00\x48\x8B\xD9" "linux" "\x8B\x8F\x40\x0E\x00\x00\x83\xF9\xFF\x0F\x84\xD9\x01" } + // Search "Changes's player's model", look for a function containing 'models/%s.vmdl'. Below V_snprintf is the one + "CBasePlayerPawn_SetModel" + { + "library" "server" + "windows" "\x48\x89\x5C\x24\x2A\x48\x89\x7C\x24\x2A\x55\x48\x8B\xEC\x48\x83\xEC\x50\x48\x8B\xF9" + "linux" "\x55\x48\x89\xF2\x48\x89\xE5\x41\x54\x49\x89\xFC\x48\x8D\x7D\xE0\x48\x83\xEC\x18\x48\x8D\x05\x3D\xD7\xBF\x00" + } + "CGameRules_TerminateRound" + { + "library" "server" + "windows" "\x48\x8B\xC4\x4C\x89\x48\x20\x55\x56" + "linux" "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x49\x89\xFD\x41\x54\x53\x48\x81\xEC\xE8\x01\x00\x00" + } } "Offsets" { diff --git a/src/addresses.cpp b/src/addresses.cpp index a20a226e..c432552c 100644 --- a/src/addresses.cpp +++ b/src/addresses.cpp @@ -56,11 +56,13 @@ bool addresses::Initialize(CGameConfig *g_GameConfig) RESOLVE_SIG(g_GameConfig, "SetGroundEntity", addresses::SetGroundEntity); RESOLVE_SIG(g_GameConfig, "CCSPlayerController_SwitchTeam", addresses::CCSPlayerController_SwitchTeam); RESOLVE_SIG(g_GameConfig, "CCSPlayerPawn_Respawn", addresses::CCSPlayerPawn_Respawn); + RESOLVE_SIG(g_GameConfig, "CBasePlayerPawn_SetModel", addresses::CBasePlayerPawn_SetModel); RESOLVE_SIG(g_GameConfig, "UTIL_Remove", addresses::UTIL_Remove); RESOLVE_SIG(g_GameConfig, "CEntitySystem_AddEntityIOEvent", addresses::CEntitySystem_AddEntityIOEvent); RESOLVE_SIG(g_GameConfig, "CEntityInstance_AcceptInput", addresses::CEntityInstance_AcceptInput); RESOLVE_SIG(g_GameConfig, "CGameEntitySystem_FindEntityByClassName", addresses::CGameEntitySystem_FindEntityByClassName); RESOLVE_SIG(g_GameConfig, "CGameEntitySystem_FindEntityByName", addresses::CGameEntitySystem_FindEntityByName); + RESOLVE_SIG(g_GameConfig, "CGameRules_TerminateRound", addresses::CGameRules_TerminateRound); return true; } diff --git a/src/addresses.h b/src/addresses.h index 6fe4e744..6deda34e 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -38,6 +38,7 @@ namespace modules class CEntityInstance; class CBasePlayerController; +class CBasePlayerPawn; class CCSPlayerController; class CCSPlayerPawn; class Z_CBaseEntity; @@ -45,6 +46,7 @@ class CGameConfig; class CEntitySystem; class IEntityFindFilter; struct variant_string_t; +class CGameRules; namespace addresses { @@ -57,6 +59,7 @@ namespace addresses inline void(FASTCALL *SetGroundEntity)(Z_CBaseEntity *ent, Z_CBaseEntity *ground); inline void(FASTCALL *CCSPlayerController_SwitchTeam)(CCSPlayerController *pController, uint32 team); inline void(FASTCALL *CCSPlayerPawn_Respawn)(CCSPlayerPawn *pPawn); + inline void(FASTCALL *CBasePlayerPawn_SetModel)(CBasePlayerPawn *pPawn, const char *szModel); inline void(FASTCALL *UTIL_Remove)(CEntityInstance*); inline void(FASTCALL *CEntitySystem_AddEntityIOEvent)(CEntitySystem *pEntitySystem, CEntityInstance *pTarget, const char *pszInput, @@ -70,4 +73,5 @@ namespace addresses inline Z_CBaseEntity *(FASTCALL *CGameEntitySystem_FindEntityByName)(CEntitySystem *pEntitySystem, CEntityInstance *pStartEntity, const char *szName, CEntityInstance *pSearchingEntity, CEntityInstance *pActivator, CEntityInstance *pCaller, IEntityFindFilter *pFilter); + inline void(FASTCALL *CGameRules_TerminateRound)(CGameRules* pGameRules, float delay, unsigned int reason, int64 a4, unsigned int a5); } diff --git a/src/cs2_sdk/entity/cbaseplayerpawn.h b/src/cs2_sdk/entity/cbaseplayerpawn.h index 9c01b858..495eae20 100644 --- a/src/cs2_sdk/entity/cbaseplayerpawn.h +++ b/src/cs2_sdk/entity/cbaseplayerpawn.h @@ -46,6 +46,10 @@ class CBasePlayerPawn : public CBaseModelEntity static int offset = g_GameConfig->GetOffset("CBasePlayerPawn_CommitSuicide"); CALL_VIRTUAL(void, offset, this, bExplode, bForce); } + void SetModel(const char *szModel) + { + addresses::CBasePlayerPawn_SetModel(this, szModel); + } CBasePlayerController *GetController() { return m_hController.Get(); } }; \ No newline at end of file diff --git a/src/cs2_sdk/entity/cgamerules.h b/src/cs2_sdk/entity/cgamerules.h index aedbc4ab..6d0b5e1e 100644 --- a/src/cs2_sdk/entity/cgamerules.h +++ b/src/cs2_sdk/entity/cgamerules.h @@ -26,6 +26,11 @@ class CGameRules { public: DECLARE_SCHEMA_CLASS(CGameRules) + + void TerminateRound(float delay, unsigned int reason) + { + addresses::CGameRules_TerminateRound(this, delay, reason, 0, 0); + } }; class CCSGameRules : public CGameRules diff --git a/src/events.cpp b/src/events.cpp index 0d58e592..8bb21f16 100644 --- a/src/events.cpp +++ b/src/events.cpp @@ -267,4 +267,10 @@ GAME_EVENT_F(round_freeze_end) { if (g_bEnableZR) ZR_OnRoundFreezeEnd(pEvent); +} + +GAME_EVENT_F(player_death) +{ + if (g_bEnableZR) + ZR_OnPlayerDeath(pEvent); } \ No newline at end of file diff --git a/src/zombiereborn.cpp b/src/zombiereborn.cpp index d32614f4..c3da675e 100644 --- a/src/zombiereborn.cpp +++ b/src/zombiereborn.cpp @@ -35,6 +35,7 @@ extern CCSGameRules* g_pGameRules; extern IGameEventManager2* g_gameEventManager; void ZR_Infect(CCSPlayerController *pAttackerController, CCSPlayerController *pVictimController, bool bBroadcast); +void ZR_CheckWinConditions(bool bCheckCT); EZRRoundState g_ZRRoundState = EZRRoundState::ROUND_START; static int g_iRoundNum = 0; @@ -90,6 +91,35 @@ CON_COMMAND_CHAT(zspawn, "respawn yourself") pPawn->Respawn(); } +CON_COMMAND_CHAT(setmodel, "set your model") +{ + if (!player) + { + ClientPrint(player, HUD_PRINTCONSOLE, CHAT_PREFIX "You cannot use this command from the server console."); + return; + } + + CCSPlayerPawn *pPawn = (CCSPlayerPawn*)player->GetPawn(); + if (!pPawn) + { + ClientPrint(player, HUD_PRINTCONSOLE, CHAT_PREFIX "Invalid Pawn."); + return; + } + ClientPrint(player, HUD_PRINTCONSOLE, CHAT_PREFIX "Classname: %s", pPawn->GetClassname()); + if (!pPawn->IsAlive()) + { + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX"You must be alive to change model!"); + return; + } + + pPawn->SetModel(args[1]); +} + +CON_COMMAND_CHAT(endround, "end the round") +{ + g_pGameRules->TerminateRound(V_StringToFloat32(args[1], 5.0f), V_StringToUint32(args[2], 10u)); +} + void SetUpAllHumanClasses() { for (int i = 0; i < gpGlobals->maxClients; i++) @@ -113,8 +143,8 @@ void ZR_OnStartupServer() g_pEngineServer2->ServerCommand("mp_give_player_c4 0"); g_pEngineServer2->ServerCommand("mp_friendlyfire 0"); // Legacy Lua respawn stuff, do not use these, we should handle respawning ourselves now that we can - //g_pEngineServer2->ServerCommand("mp_respawn_on_death_t 1"); - //g_pEngineServer2->ServerCommand("mp_respawn_on_death_ct 1"); + g_pEngineServer2->ServerCommand("mp_respawn_on_death_t 1"); + g_pEngineServer2->ServerCommand("mp_respawn_on_death_ct 1"); //g_pEngineServer2->ServerCommand("bot_quota_mode fill"); //g_pEngineServer2->ServerCommand("mp_ignore_round_win_conditions 1"); } @@ -140,9 +170,9 @@ void ZR_OnPlayerSpawn(IGameEvent* pEvent) { CCSPlayerController* pController = (CCSPlayerController*)pEvent->GetPlayerController("userid"); - if (pController && g_ZRRoundState == EZRRoundState::POST_INFECTION && pController->m_iTeamNum == CS_TEAM_CT) + if (pController && g_ZRRoundState == EZRRoundState::POST_INFECTION) { - // infect player on the next frame + // delay infection a bit int iRoundNum = g_iRoundNum; CHandle handle = pController->GetHandle(); new CTimer(0.05f, false, [iRoundNum, handle]() @@ -151,7 +181,7 @@ void ZR_OnPlayerSpawn(IGameEvent* pEvent) if (iRoundNum != g_iRoundNum || !pController) return -1.0f; - ZR_Infect(pController, pController, false); + ZR_Infect(pController, pController, true); return -1.0f; }); @@ -178,7 +208,7 @@ void ZR_ApplyKnockbackExplosion(Z_CBaseEntity *pProjectile, CCSPlayerPawn *pVict pVictim->m_vecBaseVelocity = pVictim->m_vecBaseVelocity() + vecKnockback; } -void ZR_FakePlayerDeath(CCSPlayerController *pAttackerController, CCSPlayerController *pVictimController, const char *szWeapon) +void ZR_FakePlayerDeath(CCSPlayerController *pAttackerController, CCSPlayerController *pVictimController, const char *szWeapon, bool bDontBroadcast) { IGameEvent *pEvent = g_gameEventManager->CreateEvent("player_death"); @@ -202,23 +232,29 @@ void ZR_FakePlayerDeath(CCSPlayerController *pAttackerController, CCSPlayerContr pEvent->GetInt("attacker_pawn"), pEvent->GetString("weapon")); - g_gameEventManager->FireEvent(pEvent, false); + g_gameEventManager->FireEvent(pEvent, bDontBroadcast); } -void ZR_Infect(CCSPlayerController *pAttackerController, CCSPlayerController *pVictimController, bool bBroadcast) +void ZR_Infect(CCSPlayerController *pAttackerController, CCSPlayerController *pVictimController, bool bDontBroadcast) { - if (bBroadcast) - ZR_FakePlayerDeath(pAttackerController, pVictimController, "knife"); // or any other killicon - pVictimController->SwitchTeam(CS_TEAM_T); + if (pVictimController->m_iTeamNum() == CS_TEAM_CT) + pVictimController->SwitchTeam(CS_TEAM_T); + + ZR_FakePlayerDeath(pAttackerController, pVictimController, "knife", bDontBroadcast); // or any other killicon + + ZR_CheckWinConditions(true); CCSPlayerPawn *pVictimPawn = (CCSPlayerPawn*)pVictimController->GetPawn(); if (!pVictimPawn) return; // set model/health/etc here + //hardcode everything for now pVictimPawn->m_iMaxHealth = 10000; pVictimPawn->m_iHealth = 10000; + + pVictimPawn->SetModel("characters/models/tm_phoenix/tm_phoenix.vmdl"); } @@ -229,12 +265,13 @@ void ZR_InfectMotherZombie(CCSPlayerController *pVictimController) CCSPlayerPawn *pVictimPawn = (CCSPlayerPawn*)pVictimController->GetPawn(); if (!pVictimPawn) return; - //set model/health/etc here - // set model/health/etc here + //hardcode everything for now pVictimPawn->m_iMaxHealth = 10000; pVictimPawn->m_iHealth = 10000; + + pVictimPawn->SetModel("characters/models/tm_phoenix/tm_phoenix.vmdl"); } void ZR_InitialInfection() @@ -334,7 +371,7 @@ bool ZR_Detour_TakeDamageOld(CCSPlayerPawn *pVictimPawn, CTakeDamageInfo *pInfo) if (pAttackerPawn->m_iTeamNum() == CS_TEAM_T && pVictimPawn->m_iTeamNum() == CS_TEAM_CT) { - ZR_Infect(pAttackerController, pVictimController, true); + ZR_Infect(pAttackerController, pVictimController, false); return true; // nullify the damage } @@ -367,15 +404,17 @@ void ZR_OnPlayerHurt(IGameEvent* pEvent) void ZR_OnPlayerDeath(IGameEvent* pEvent) { - // To T TeamSwitch happening in ZR_OnPlayerSpawn - - /*ZEPlayer* pPlayer = g_playerManager->GetPlayerFromUserId(pEvent->GetInt("userid")); + if (g_ZRRoundState == EZRRoundState::ROUND_START) + return; - if (pPlayer && !pPlayer->IsInfected()) - { - CCSPlayerController* pController = (CCSPlayerController*)pEvent->GetPlayerController("userid"); - pController->SwitchTeam(CS_TEAM_T); - }*/ + CCSPlayerController *pVictimController = (CCSPlayerController*)pEvent->GetPlayerController("userid"); + if (!pVictimController) + return; + CCSPlayerPawn *pVictimPawn = (CCSPlayerPawn*)pVictimController->GetPawn(); + if (!pVictimPawn) + return; + + ZR_CheckWinConditions(pVictimPawn->m_iTeamNum() == CS_TEAM_CT); } void ZR_OnRoundFreezeEnd(IGameEvent* pEvent) @@ -383,6 +422,26 @@ void ZR_OnRoundFreezeEnd(IGameEvent* pEvent) ZR_StartInitialCountdown(); } +void ZR_CheckWinConditions(bool bCheckCT) +{ + int iTeamNum = bCheckCT ? CS_TEAM_CT : CS_TEAM_T; + + // loop through each player, return early if both team has alive player + CCSPlayerPawn* pPawn = nullptr; + while (nullptr != (pPawn = (CCSPlayerPawn*)UTIL_FindEntityByClassname(pPawn, "player"))) + { + if (!pPawn->IsAlive()) + continue; + + if (pPawn->m_iTeamNum() == iTeamNum) + return; + } + + // didn't return early, all players on one or both teams are dead. + // 8: CT win; 9: T wins; 10: draw + g_pGameRules->TerminateRound(5.0, bCheckCT ? 9u : 8u); +} + CON_COMMAND_CHAT(ztele, "teleport to spawn") { // Silently return so the command is completely hidden From c4d4515a1d8c12668f890366741e94eb977566bd Mon Sep 17 00:00:00 2001 From: Connor <34824423+EasterLee@users.noreply.github.com> Date: Sun, 3 Dec 2023 14:06:21 -0500 Subject: [PATCH 13/13] bug fix --- gamedata/cs2fixes.games.txt | 2 +- src/addresses.cpp | 2 +- src/addresses.h | 4 +-- src/cs2_sdk/entity/cbasemodelentity.h | 5 ++++ src/cs2_sdk/entity/cbaseplayerpawn.h | 4 --- src/cs2_sdk/entity/cgamerules.h | 39 +++++++++++++++++++++++---- src/zombiereborn.cpp | 25 ++++++++--------- 7 files changed, 56 insertions(+), 25 deletions(-) diff --git a/gamedata/cs2fixes.games.txt b/gamedata/cs2fixes.games.txt index a8b21a64..d1a7ea08 100644 --- a/gamedata/cs2fixes.games.txt +++ b/gamedata/cs2fixes.games.txt @@ -263,7 +263,7 @@ "linux" "\x8B\x8F\x40\x0E\x00\x00\x83\xF9\xFF\x0F\x84\xD9\x01" } // Search "Changes's player's model", look for a function containing 'models/%s.vmdl'. Below V_snprintf is the one - "CBasePlayerPawn_SetModel" + "CBaseModelEntity_SetModel" { "library" "server" "windows" "\x48\x89\x5C\x24\x2A\x48\x89\x7C\x24\x2A\x55\x48\x8B\xEC\x48\x83\xEC\x50\x48\x8B\xF9" diff --git a/src/addresses.cpp b/src/addresses.cpp index c432552c..a1e2cd68 100644 --- a/src/addresses.cpp +++ b/src/addresses.cpp @@ -56,7 +56,7 @@ bool addresses::Initialize(CGameConfig *g_GameConfig) RESOLVE_SIG(g_GameConfig, "SetGroundEntity", addresses::SetGroundEntity); RESOLVE_SIG(g_GameConfig, "CCSPlayerController_SwitchTeam", addresses::CCSPlayerController_SwitchTeam); RESOLVE_SIG(g_GameConfig, "CCSPlayerPawn_Respawn", addresses::CCSPlayerPawn_Respawn); - RESOLVE_SIG(g_GameConfig, "CBasePlayerPawn_SetModel", addresses::CBasePlayerPawn_SetModel); + RESOLVE_SIG(g_GameConfig, "CBaseModelEntity_SetModel", addresses::CBaseModelEntity_SetModel); RESOLVE_SIG(g_GameConfig, "UTIL_Remove", addresses::UTIL_Remove); RESOLVE_SIG(g_GameConfig, "CEntitySystem_AddEntityIOEvent", addresses::CEntitySystem_AddEntityIOEvent); RESOLVE_SIG(g_GameConfig, "CEntityInstance_AcceptInput", addresses::CEntityInstance_AcceptInput); diff --git a/src/addresses.h b/src/addresses.h index 6deda34e..748e39a5 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -38,9 +38,9 @@ namespace modules class CEntityInstance; class CBasePlayerController; -class CBasePlayerPawn; class CCSPlayerController; class CCSPlayerPawn; +class CBaseModelEntity; class Z_CBaseEntity; class CGameConfig; class CEntitySystem; @@ -59,7 +59,7 @@ namespace addresses inline void(FASTCALL *SetGroundEntity)(Z_CBaseEntity *ent, Z_CBaseEntity *ground); inline void(FASTCALL *CCSPlayerController_SwitchTeam)(CCSPlayerController *pController, uint32 team); inline void(FASTCALL *CCSPlayerPawn_Respawn)(CCSPlayerPawn *pPawn); - inline void(FASTCALL *CBasePlayerPawn_SetModel)(CBasePlayerPawn *pPawn, const char *szModel); + inline void(FASTCALL *CBaseModelEntity_SetModel)(CBaseModelEntity *pModel, const char *szModel); inline void(FASTCALL *UTIL_Remove)(CEntityInstance*); inline void(FASTCALL *CEntitySystem_AddEntityIOEvent)(CEntitySystem *pEntitySystem, CEntityInstance *pTarget, const char *pszInput, diff --git a/src/cs2_sdk/entity/cbasemodelentity.h b/src/cs2_sdk/entity/cbasemodelentity.h index 28a34e8a..ad95f788 100644 --- a/src/cs2_sdk/entity/cbasemodelentity.h +++ b/src/cs2_sdk/entity/cbasemodelentity.h @@ -29,4 +29,9 @@ class CBaseModelEntity : public Z_CBaseEntity SCHEMA_FIELD(CCollisionProperty , m_Collision) SCHEMA_FIELD(CGlowProperty, m_Glow) + + void SetModel(const char *szModel) + { + addresses::CBaseModelEntity_SetModel(this, szModel); + } }; \ No newline at end of file diff --git a/src/cs2_sdk/entity/cbaseplayerpawn.h b/src/cs2_sdk/entity/cbaseplayerpawn.h index 495eae20..9c01b858 100644 --- a/src/cs2_sdk/entity/cbaseplayerpawn.h +++ b/src/cs2_sdk/entity/cbaseplayerpawn.h @@ -46,10 +46,6 @@ class CBasePlayerPawn : public CBaseModelEntity static int offset = g_GameConfig->GetOffset("CBasePlayerPawn_CommitSuicide"); CALL_VIRTUAL(void, offset, this, bExplode, bForce); } - void SetModel(const char *szModel) - { - addresses::CBasePlayerPawn_SetModel(this, szModel); - } CBasePlayerController *GetController() { return m_hController.Get(); } }; \ No newline at end of file diff --git a/src/cs2_sdk/entity/cgamerules.h b/src/cs2_sdk/entity/cgamerules.h index 6d0b5e1e..e949405e 100644 --- a/src/cs2_sdk/entity/cgamerules.h +++ b/src/cs2_sdk/entity/cgamerules.h @@ -27,10 +27,6 @@ class CGameRules public: DECLARE_SCHEMA_CLASS(CGameRules) - void TerminateRound(float delay, unsigned int reason) - { - addresses::CGameRules_TerminateRound(this, delay, reason, 0, 0); - } }; class CCSGameRules : public CGameRules @@ -43,6 +39,11 @@ class CCSGameRules : public CGameRules SCHEMA_FIELD(int, m_totalRoundsPlayed) SCHEMA_FIELD(GameTime_t, m_fRoundStartTime) SCHEMA_FIELD(GameTime_t, m_flRestartRoundTime) + + void TerminateRound(float delay, unsigned int reason) + { + addresses::CGameRules_TerminateRound(this, delay, reason, 0, 0); + } }; class CCSGameRulesProxy : public Z_CBaseEntity @@ -50,5 +51,33 @@ class CCSGameRulesProxy : public Z_CBaseEntity public: DECLARE_SCHEMA_CLASS(CCSGameRulesProxy) - SCHEMA_FIELD(CCSGameRules*, m_pGameRules) + SCHEMA_FIELD(CCSGameRules *, m_pGameRules) +}; + +enum CSRoundEndReason +{ + TargetBombed = 1, /**< Target Successfully Bombed! */ + + VIPEscaped, /**< The VIP has escaped! - Doesn't exist on CS:GO */ + VIPKilled, /**< VIP has been assassinated! - Doesn't exist on CS:GO */ + + TerroristsEscaped, /**< The terrorists have escaped! */ + CTStoppedEscape, /**< The CTs have prevented most of the terrorists from escaping! */ + TerroristsStopped, /**< Escaping terrorists have all been neutralized! */ + BombDefused, /**< The bomb has been defused! */ + CTWin, /**< Counter-Terrorists Win! */ + TerroristWin, /**< Terrorists Win! */ + Draw, /**< Round Draw! */ + HostagesRescued, /**< All Hostages have been rescued! */ + TargetSaved, /**< Target has been saved! */ + HostagesNotRescued, /**< Hostages have not been rescued! */ + TerroristsNotEscaped, /**< Terrorists have not escaped! */ + VIPNotEscaped, /**< VIP has not escaped! - Doesn't exist on CS:GO */ + GameStart, /**< Game Commencing! */ + TerroristsSurrender, /**< Terrorists Surrender */ + CTSurrender, /**< CTs Surrender */ + TerroristsPlanted, /**< Terrorists Planted the bomb */ + CTsReachedHostage, /**< CTs Reached the hostage */ + SurvivalWin, + SurvivalDraw }; \ No newline at end of file diff --git a/src/zombiereborn.cpp b/src/zombiereborn.cpp index c3da675e..dfd49c2c 100644 --- a/src/zombiereborn.cpp +++ b/src/zombiereborn.cpp @@ -278,14 +278,10 @@ void ZR_InitialInfection() { // grab player count and mz infection candidates CUtlVector pCandidateControllers; - int iPlayerCount = 0; for (int i = 0; i < gpGlobals->maxClients; i++) { CCSPlayerController* pController = CCSPlayerController::FromSlot(i); - if (!pController) - continue; - iPlayerCount++; - if (pController->m_iTeamNum() != CS_TEAM_CT) + if (!pController || pController->m_iTeamNum() != CS_TEAM_CT) continue; CCSPlayerController* pPawn = (CCSPlayerController*)pController->GetPawn(); @@ -296,7 +292,7 @@ void ZR_InitialInfection() } // calculate the num of mz to infect - int iMZToInfect = iPlayerCount / g_flInfectSpawnMZRatio; + int iMZToInfect = pCandidateControllers.Count() / g_flInfectSpawnMZRatio; iMZToInfect = g_flInfectSpawnMinCount > iMZToInfect ? g_flInfectSpawnMinCount : iMZToInfect; // get spawn points @@ -347,7 +343,7 @@ void ZR_StartInitialCountdown() return -1.0f; } - if (g_iInfectionCountDown <= 15) + if (g_iInfectionCountDown <= 60) { ClientPrintAll(HUD_PRINTCENTER, "First infection in \7%i second(s)\1!", g_iInfectionCountDown); if (g_iInfectionCountDown % 5 == 0) @@ -368,8 +364,8 @@ bool ZR_Detour_TakeDamageOld(CCSPlayerPawn *pVictimPawn, CTakeDamageInfo *pInfo) CCSPlayerController *pAttackerController = CCSPlayerController::FromPawn(pAttackerPawn); CCSPlayerController *pVictimController = CCSPlayerController::FromPawn(pVictimPawn); - - if (pAttackerPawn->m_iTeamNum() == CS_TEAM_T && pVictimPawn->m_iTeamNum() == CS_TEAM_CT) + const char *pszAbilityClass = pInfo->m_hAbility.Get() ? pInfo->m_hAbility.Get()->GetClassname() : ""; + if (pAttackerPawn->m_iTeamNum() == CS_TEAM_T && pVictimPawn->m_iTeamNum() == CS_TEAM_CT && !V_strncmp(pszAbilityClass, "weapon_knife", 12)) { ZR_Infect(pAttackerController, pVictimController, false); return true; // nullify the damage @@ -380,7 +376,7 @@ bool ZR_Detour_TakeDamageOld(CCSPlayerPawn *pVictimPawn, CTakeDamageInfo *pInfo) { CBaseEntity *pInflictor = pInfo->m_hInflictor.Get(); const char *pszInflictorClass = pInflictor ? pInflictor->GetClassname() : ""; - if (V_strncmp(pszInflictorClass, "hegrenade", 9) || V_strncmp(pszInflictorClass, "inferno", 7)) + if (!V_strncmp(pszInflictorClass, "hegrenade_projectile", 9) || !V_strncmp(pszInflictorClass, "inferno", 7)) ZR_ApplyKnockbackExplosion((Z_CBaseEntity*)pInflictor, (CCSPlayerPawn*)pVictimPawn, (int)pInfo->m_flDamage); } return false; @@ -395,7 +391,7 @@ void ZR_OnPlayerHurt(IGameEvent* pEvent) // grenade and molotov knockbacks are handled by TakeDamage detours - if (!pAttackerController || !pVictimController || strcmp(szWeapon, "") == 0 || strcmp(szWeapon, "inferno") == 0 || strcmp(szWeapon, "hegrenade") == 0) + if (!pAttackerController || !pVictimController || !V_strncmp(szWeapon, "inferno", 7) || !V_strncmp(szWeapon, "hegrenade", 9)) return; if (pAttackerController->m_iTeamNum() == CS_TEAM_CT && pVictimController->m_iTeamNum() == CS_TEAM_T) @@ -422,8 +418,12 @@ void ZR_OnRoundFreezeEnd(IGameEvent* pEvent) ZR_StartInitialCountdown(); } +// check whether players on a team are all dead void ZR_CheckWinConditions(bool bCheckCT) { + if (g_ZRRoundState == EZRRoundState::ROUND_END) + return; + int iTeamNum = bCheckCT ? CS_TEAM_CT : CS_TEAM_T; // loop through each player, return early if both team has alive player @@ -439,7 +439,8 @@ void ZR_CheckWinConditions(bool bCheckCT) // didn't return early, all players on one or both teams are dead. // 8: CT win; 9: T wins; 10: draw - g_pGameRules->TerminateRound(5.0, bCheckCT ? 9u : 8u); + g_pGameRules->TerminateRound(5.0, bCheckCT ? CSRoundEndReason::TerroristWin : CSRoundEndReason::CTWin); + g_ZRRoundState = EZRRoundState::ROUND_END; } CON_COMMAND_CHAT(ztele, "teleport to spawn")