diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 78a8b7d3f..ca1c0f7df 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ on: jobs: windows: name: 'Windows' - runs-on: windows-latest + runs-on: windows-2019 env: solution: 'msvc/ReGameDLL.sln' diff --git a/regamedll/dlls/API/CSPlayer.cpp b/regamedll/dlls/API/CSPlayer.cpp index 6b11725fe..145c5d85e 100644 --- a/regamedll/dlls/API/CSPlayer.cpp +++ b/regamedll/dlls/API/CSPlayer.cpp @@ -258,7 +258,7 @@ EXT_FUNC CBaseEntity *CCSPlayer::GiveNamedItemEx(const char *pszName) if (FStrEq(pszName, "weapon_c4")) { pPlayer->m_bHasC4 = true; - pPlayer->SetBombIcon(); + pPlayer->SetBombIcon(((pPlayer->m_signals.GetState() & SIGNAL_BOMB) && (CSGameRules()->CanPlantBomb(pPlayer) & GR_CANPLANTBOMB_DELAY_OVER))); if (pPlayer->m_iTeam == TERRORIST) { pPlayer->pev->body = 1; @@ -531,8 +531,8 @@ void CCSPlayer::Reset() m_szModel[0] = '\0'; m_bForceShowMenu = false; - m_flRespawnPending = - m_flSpawnProtectionEndTime = 0.0f; + m_flRespawnPending = 0.0f; + m_flSpawnProtectionEndTime = 0.0f; m_vecOldvAngle = g_vecZero; m_iWeaponInfiniteAmmo = 0; @@ -541,6 +541,8 @@ void CCSPlayer::Reset() m_bGameForcingRespawn = false; m_bAutoBunnyHopping = false; m_bMegaBunnyJumping = false; + m_iCanPlantC4Anywhere = -1; + m_flPlantC4Delay = -1.0; } void CCSPlayer::OnSpawn() diff --git a/regamedll/dlls/game.cpp b/regamedll/dlls/game.cpp index 14dc2d11e..cc50e4fae 100644 --- a/regamedll/dlls/game.cpp +++ b/regamedll/dlls/game.cpp @@ -162,6 +162,7 @@ cvar_t allchat = { "sv_allchat", "0", 0, 0.0f, nullptr cvar_t sv_autobunnyhopping = { "sv_autobunnyhopping", "0", 0, 0.0f, nullptr }; cvar_t sv_enablebunnyhopping = { "sv_enablebunnyhopping", "0", 0, 0.0f, nullptr }; cvar_t plant_c4_anywhere = { "mp_plant_c4_anywhere", "0", 0, 0.0f, nullptr }; +cvar_t plant_c4_delay = { "mp_plant_c4_delay", "0", 0, 0.0f, nullptr }; void GameDLL_Version_f() { @@ -393,6 +394,7 @@ void EXT_FUNC GameDLLInit() CVAR_REGISTER(&sv_autobunnyhopping); CVAR_REGISTER(&sv_enablebunnyhopping); CVAR_REGISTER(&plant_c4_anywhere); + CVAR_REGISTER(&plant_c4_delay); // print version CONSOLE_ECHO("ReGameDLL version: " APP_VERSION "\n"); diff --git a/regamedll/dlls/game.h b/regamedll/dlls/game.h index 5c75387b7..43b4e2436 100644 --- a/regamedll/dlls/game.h +++ b/regamedll/dlls/game.h @@ -188,6 +188,7 @@ extern cvar_t allchat; extern cvar_t sv_autobunnyhopping; extern cvar_t sv_enablebunnyhopping; extern cvar_t plant_c4_anywhere; +extern cvar_t plant_c4_delay; #endif diff --git a/regamedll/dlls/gamerules.h b/regamedll/dlls/gamerules.h index ed0111a50..c326d8ce3 100644 --- a/regamedll/dlls/gamerules.h +++ b/regamedll/dlls/gamerules.h @@ -202,7 +202,6 @@ enum SCENARIO_BLOCK_PRISON_ESCAPE_TIME = BIT(8), // flag "i" SCENARIO_BLOCK_BOMB_TIME = BIT(9), // flag "j" SCENARIO_BLOCK_HOSTAGE_RESCUE_TIME = BIT(10), // flag "k" - }; // Player relationship return codes @@ -215,6 +214,14 @@ enum GR_NEUTRAL, }; +// Custom enum (used with custom function "CHalfLifeMultiplay::CanPlantBomb"). +enum +{ + GR_CANPLANTBOMB_NO = 0, + GR_CANPLANTBOMB_ANYWHERE = BIT(0), + GR_CANPLANTBOMB_DELAY_OVER = BIT(1), +}; + class CItem; class CGameRules @@ -683,7 +690,8 @@ class CHalfLifeMultiplay: public CGameRules // has a style of gameplay when aren't any teams bool IsFreeForAll() const; - bool CanPlayerBuy(CBasePlayer *pPlayer) const; + EXPORT bool CanPlayerBuy(CBasePlayer *pPlayer); + EXPORT int CanPlantBomb(CBasePlayer *pPlayer, float *pflPlantC4Delay = nullptr); VFUNC bool HasRoundTimeExpired(); VFUNC bool IsBombPlanted(); diff --git a/regamedll/dlls/multiplay_gamerules.cpp b/regamedll/dlls/multiplay_gamerules.cpp index 7824ef516..43d681764 100644 --- a/regamedll/dlls/multiplay_gamerules.cpp +++ b/regamedll/dlls/multiplay_gamerules.cpp @@ -5141,20 +5141,70 @@ void CHalfLifeMultiplay::ChangePlayerTeam(CBasePlayer *pPlayer, const char *pTea } } -bool CHalfLifeMultiplay::CanPlayerBuy(CBasePlayer *pPlayer) const +bool CHalfLifeMultiplay::CanPlayerBuy(CBasePlayer *pPlayer) { - if (pPlayer->m_iTeam == CT && m_bCTCantBuy) - { + if((m_bCTCantBuy && m_bTCantBuy) + || (pPlayer->m_iTeam == CT && m_bCTCantBuy) + || (pPlayer->m_iTeam == TERRORIST && m_bTCantBuy)) return false; + + return true; +} + +// Check if the C4 can be planted (only by rules). +// Note: Implement team check here when a player is passed in order to easily allow tricking, if needed (but facultative). +int CHalfLifeMultiplay::CanPlantBomb(CBasePlayer *pPlayer, float *pflPlantC4Delay) +{ + if(pflPlantC4Delay) + { + *pflPlantC4Delay = 0.0f; } - else if (pPlayer->m_iTeam == TERRORIST && m_bTCantBuy) + + if(pPlayer && pPlayer->IsPlayer() && !(pPlayer->m_iTeam == TERRORIST || pPlayer->m_iTeam == CT)) + return GR_CANPLANTBOMB_NO; + +#ifdef REGAMEDLL_ADD + int iResultFlags = GR_CANPLANTBOMB_NO; + int iCanPlantC4Anywhere = -1; + float flPlantC4Delay = -1.0; + + #ifdef REGAMEDLL_API + if(pPlayer && pPlayer->IsPlayer()) { - return false; + iCanPlantC4Anywhere = pPlayer->CSPlayer()->m_iCanPlantC4Anywhere; + flPlantC4Delay = pPlayer->CSPlayer()->m_flPlantC4Delay; } - else if (m_bCTCantBuy && m_bTCantBuy) + #endif + + if(iCanPlantC4Anywhere <= -1) { - return false; + iCanPlantC4Anywhere = plant_c4_anywhere.value; } - return true; + if(flPlantC4Delay <= -1.0) + { + flPlantC4Delay = plant_c4_delay.value; + } + flPlantC4Delay = Q_max(flPlantC4Delay, 0.0f); + + if(pflPlantC4Delay) + { + *pflPlantC4Delay = flPlantC4Delay; + } + + if(iCanPlantC4Anywhere >= 1) + { + iResultFlags |= GR_CANPLANTBOMB_ANYWHERE; + } + + if(flPlantC4Delay <= (gpGlobals->time - CSGameRules()->m_fRoundStartTime)) + { + iResultFlags |= GR_CANPLANTBOMB_DELAY_OVER; + } + + return iResultFlags; +#else + return GR_CANPLANTBOMB_DELAY_OVER; +#endif } + diff --git a/regamedll/dlls/observer.cpp b/regamedll/dlls/observer.cpp index 336b7b3cc..5dd4372c2 100644 --- a/regamedll/dlls/observer.cpp +++ b/regamedll/dlls/observer.cpp @@ -355,7 +355,11 @@ void CBasePlayer::Observer_CheckProperties() if (target->m_bHasC4) { +#ifdef REGAMEDLL_ADD + if ((target->m_signals.GetState() & SIGNAL_BOMB) && (CSGameRules()->CanPlantBomb(target) & GR_CANPLANTBOMB_DELAY_OVER)) +#else if (target->m_signals.GetState() & SIGNAL_BOMB) +#endif targetBombState = STATUSICON_FLASH; else targetBombState = STATUSICON_SHOW; diff --git a/regamedll/dlls/player.cpp b/regamedll/dlls/player.cpp index c48545051..b2dfcd5a3 100644 --- a/regamedll/dlls/player.cpp +++ b/regamedll/dlls/player.cpp @@ -6622,25 +6622,22 @@ void CBasePlayer::HandleSignals() { if (CSGameRules()->IsMultiplayer()) { - #ifdef REGAMEDLL_ADD if (buytime.value != 0.0f) #endif { #ifdef REGAMEDLL_ADD - if (buy_anywhere.value) + if (buy_anywhere.value >= 1) { - if (pev->deadflag == DEAD_NO && (m_iTeam == TERRORIST || m_iTeam == CT) - && !(m_signals.GetSignal() & SIGNAL_BUY) - // Restricted by map rules - && CSGameRules()->CanPlayerBuy(this) - ) + if (IsAlive() && (m_iTeam == TERRORIST || m_iTeam == CT) + && !(m_signals.GetSignal() & SIGNAL_BUY) + // Restricted by map rules + && CSGameRules()->CanPlayerBuy(this)) { // 0 = default. 1 = both teams. 2 = Terrorists. 3 = Counter-Terrorists. if (buy_anywhere.value == 1 - || (buy_anywhere.value == 2 && m_iTeam == TERRORIST) - || (buy_anywhere.value == 3 && m_iTeam == CT) - ) + || (buy_anywhere.value == 2 && m_iTeam == TERRORIST) + || (buy_anywhere.value >= 3 && m_iTeam == CT)) { m_signals.Signal(SIGNAL_BUY); } @@ -6654,24 +6651,32 @@ void CBasePlayer::HandleSignals() } #ifdef REGAMEDLL_ADD - if (m_bHasC4 && (plant_c4_anywhere.value || CSPlayer()->m_bPlantC4Anywhere)) + if (IsAlive() && m_bHasC4) { - if (IsAlive() && (m_iTeam == TERRORIST || m_iTeam == CT) - && !(m_signals.GetSignal() & SIGNAL_BOMB)) + int iCanPlantBomb = CSGameRules()->CanPlantBomb(this); + + if (iCanPlantBomb & GR_CANPLANTBOMB_ANYWHERE) { m_signals.Signal(SIGNAL_BOMB); } + + if (iCanPlantBomb & GR_CANPLANTBOMB_DELAY_OVER) + { + m_signals.Signal(SIGNAL_BOMB_DELAY_OVER); + } } -#endif + if (!(m_signals.GetSignal() & SIGNAL_BOMB) && !CSGameRules()->m_bMapHasBombZone) +#else if (!CSGameRules()->m_bMapHasBombZone) +#endif OLD_CheckBombTarget(this); if (!CSGameRules()->m_bMapHasRescueZone) OLD_CheckRescueZone(this); } - int state = m_signals.GetSignal(); + int state = m_signals.GetSignal(); int changed = m_signals.GetState() ^ state; m_signals.Update(); @@ -6685,11 +6690,24 @@ void CBasePlayer::HandleSignals() } if (changed & SIGNAL_BOMB) { +#ifdef REGAMEDLL_ADD + if ((state & SIGNAL_BOMB) && (m_signals.GetState() & SIGNAL_BOMB_DELAY_OVER)) +#else if (state & SIGNAL_BOMB) +#endif BombTargetFlash_Set(this); else BombTargetFlash_Clear(this); } +#ifdef REGAMEDLL_ADD + else if ((changed & SIGNAL_BOMB_DELAY_OVER) && (m_signals.GetState() & SIGNAL_BOMB)) + { + if (state & SIGNAL_BOMB_DELAY_OVER) + BombTargetFlash_Set(this); + else + BombTargetFlash_Clear(this); + } +#endif if (changed & SIGNAL_RESCUE) { if (state & SIGNAL_RESCUE) @@ -10053,7 +10071,11 @@ bool EXT_FUNC CBasePlayer::__API_HOOK(MakeBomber)() } m_bHasC4 = true; +#ifdef REGAMEDLL_FIXES + SetBombIcon(((m_signals.GetState() & SIGNAL_BOMB) && (CSGameRules()->CanPlantBomb(this) & GR_CANPLANTBOMB_DELAY_OVER))); +#else SetBombIcon(); +#endif pev->body = 1; m_flDisplayHistory |= DHF_BOMB_RETRIEVED; diff --git a/regamedll/dlls/unisignals.h b/regamedll/dlls/unisignals.h index 445c85afa..fefb52d73 100644 --- a/regamedll/dlls/unisignals.h +++ b/regamedll/dlls/unisignals.h @@ -28,11 +28,15 @@ #pragma once +// Default CS's signals. #define SIGNAL_BUY BIT(0) #define SIGNAL_BOMB BIT(1) #define SIGNAL_RESCUE BIT(2) #define SIGNAL_ESCAPE BIT(3) #define SIGNAL_VIPSAFETY BIT(4) +// ReGameDLL_CS's specific signals. +// Note: Jump to +5 in order to predict possible new flags that could be added by a legit update of the game (by VALVe). +#define SIGNAL_BOMB_DELAY_OVER BIT(10) // Note: Used to specify the player has his plant C4 delay over or not (to blink/unblink the C4 icon when value changed and if player is on site). class CUnifiedSignals { diff --git a/regamedll/dlls/wpn_shared/wpn_c4.cpp b/regamedll/dlls/wpn_shared/wpn_c4.cpp index 63736adef..e32bd7e0a 100644 --- a/regamedll/dlls/wpn_shared/wpn_c4.cpp +++ b/regamedll/dlls/wpn_shared/wpn_c4.cpp @@ -120,7 +120,14 @@ void CC4::PrimaryAttack() } #endif +#ifdef REGAMEDLL_ADD + float flPlantC4Delay = 0.0f; + int iCanPlantBomb = CSGameRules()->CanPlantBomb(m_pPlayer, &flPlantC4Delay); + + bool bPlaceBomb = (onGround && inBombZone && (iCanPlantBomb & GR_CANPLANTBOMB_DELAY_OVER)); +#else bool bPlaceBomb = (onGround && inBombZone); +#endif if (!m_bStartedArming) { @@ -131,6 +138,21 @@ void CC4::PrimaryAttack() return; } +#ifdef REGAMEDLL_ADD + if (!(iCanPlantBomb & GR_CANPLANTBOMB_DELAY_OVER) && flPlantC4Delay > 0.0f) + { + int iRemainingTime = Q_max((int)(flPlantC4Delay - (gpGlobals->time - CSGameRules()->m_fRoundStartTime)), 1); + + if (!(iCanPlantBomb & GR_CANPLANTBOMB_ANYWHERE)) + ClientPrint(m_pPlayer->pev, HUD_PRINTCENTER, UTIL_VarArgs("Wait %s %s before planting the C4 on the site!", UTIL_dtos1(iRemainingTime), (iRemainingTime == 1) ? "second" : "seconds")); + else + ClientPrint(m_pPlayer->pev, HUD_PRINTCENTER, UTIL_VarArgs("Wait %s %s before planting the C4 anywhere!", UTIL_dtos1(iRemainingTime), (iRemainingTime == 1) ? "second" : "seconds")); + + m_flNextPrimaryAttack = GetNextAttackDelay(1.0); + return; + } +#endif + if (!onGround) { ClientPrint(m_pPlayer->pev, HUD_PRINTCENTER, "#C4_Plant_Must_Be_On_Ground"); @@ -168,8 +190,9 @@ void CC4::PrimaryAttack() m_fArmedTime = 0; Broadcast("BOMBPL"); +#ifndef REGAMEDLL_FIXES m_pPlayer->m_bHasC4 = false; - +#endif if (pev->speed != 0 && CSGameRules()) { CSGameRules()->m_iC4Timer = int(pev->speed); @@ -217,18 +240,27 @@ void CC4::PrimaryAttack() // Play the plant sound. EMIT_SOUND(edict(), CHAN_WEAPON, "weapons/c4_plant.wav", VOL_NORM, ATTN_NORM); - +#ifndef REGAMEDLL_FIXES // hide the backpack in Terrorist's models. m_pPlayer->pev->body = 0; - +#endif // release the player from being frozen m_pPlayer->ResetMaxSpeed(); +#ifndef REGAMEDLL_FIXES // No more c4! m_pPlayer->SetBombIcon(FALSE); +#endif if (--m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) { +#ifdef REGAMEDLL_FIXES + m_pPlayer->m_bHasC4 = false; + // hide the backpack in Terrorist's models. + m_pPlayer->pev->body = 0; + // No more c4! + m_pPlayer->SetBombIcon(FALSE); +#endif RetireWeapon(); return; } @@ -248,7 +280,11 @@ void CC4::PrimaryAttack() } else { - if (inBombZone) + if (inBombZone +#ifdef REGAMEDLL_ADD + && (iCanPlantBomb & GR_CANPLANTBOMB_DELAY_OVER) +#endif + ) ClientPrint(m_pPlayer->pev, HUD_PRINTCENTER, "#C4_Plant_Must_Be_On_Ground"); else ClientPrint(m_pPlayer->pev, HUD_PRINTCENTER, "#C4_Arming_Cancelled"); diff --git a/regamedll/public/regamedll/API/CSPlayer.h b/regamedll/public/regamedll/API/CSPlayer.h index 8410d95f7..5ff63fee7 100644 --- a/regamedll/public/regamedll/API/CSPlayer.h +++ b/regamedll/public/regamedll/API/CSPlayer.h @@ -49,7 +49,8 @@ class CCSPlayer: public CCSMonster { m_bGameForcingRespawn(false), m_bAutoBunnyHopping(false), m_bMegaBunnyJumping(false), - m_bPlantC4Anywhere(false) + m_iCanPlantC4Anywhere(-1), + m_flPlantC4Delay(-1.0) { m_szModel[0] = '\0'; } @@ -130,7 +131,8 @@ class CCSPlayer: public CCSMonster { bool m_bGameForcingRespawn; bool m_bAutoBunnyHopping; bool m_bMegaBunnyJumping; - bool m_bPlantC4Anywhere; + int m_iCanPlantC4Anywhere; + float m_flPlantC4Delay; }; // Inlines diff --git a/regamedll/public/regamedll/regamedll_api.h b/regamedll/public/regamedll/regamedll_api.h index ba7a8517c..79aec7c5c 100644 --- a/regamedll/public/regamedll/regamedll_api.h +++ b/regamedll/public/regamedll/regamedll_api.h @@ -38,7 +38,7 @@ #include #define REGAMEDLL_API_VERSION_MAJOR 5 -#define REGAMEDLL_API_VERSION_MINOR 21 +#define REGAMEDLL_API_VERSION_MINOR 22 // CBasePlayer::Spawn hook typedef IHookChainClass IReGameHook_CBasePlayer_Spawn; diff --git a/regamedll/version/version.h b/regamedll/version/version.h index ba22bb751..b65ba1ab2 100644 --- a/regamedll/version/version.h +++ b/regamedll/version/version.h @@ -6,5 +6,5 @@ #pragma once #define VERSION_MAJOR 5 -#define VERSION_MINOR 21 +#define VERSION_MINOR 22 #define VERSION_MAINTENANCE 0