From 8ddda261feaf6a559c2a19d9dcf7451ae62e7ed3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Mu=C3=B1oz?= Date: Mon, 10 Jul 2023 08:45:24 -0400 Subject: [PATCH] New CVars: `mp_weapondrop` and `mp_ammodrop` and fixes (#840) * First implementation * Update player.cpp * Apply suggestions from code review Co-authored-by: Sergey Shorokhov * Improve readability * Improve readability x2 Co-authored-by: Sergey Shorokhov * Tabulation tip * Compile error resolved * Add mp_weapondrop 3: drop all weapons --------- Co-authored-by: Sergey Shorokhov --- README.md | 2 + dist/game.cfg | 18 +++ regamedll/dlls/game.cpp | 4 + regamedll/dlls/game.h | 2 + regamedll/dlls/gamerules.h | 4 + regamedll/dlls/multiplay_gamerules.cpp | 20 ++- regamedll/dlls/player.cpp | 165 ++++++++++++++++++------- 7 files changed, 166 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index bf7408da..6713f49a 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,8 @@ This means that plugins that do binary code analysis (Orpheu for example) probab | mp_round_restart_delay | 5 | - | - | Number of seconds to delay before restarting a round after a win. | | mp_hegrenade_penetration | 0 | 0 | 1 | Disable grenade damage through walls.
`0` disabled
`1` enabled | | mp_nadedrops | 0 | 0 | 2 | Drop a grenade after player death.
`0` disabled
`1` drop first available grenade
`2` drop all grenades | +| mp_weapondrop | 1 | 0 | 3 | Drop player weapon after death.
`0` do not drop weapons after death
`1` drop best/heaviest weapon after death
`2` drop active weapon after death
`3` drop all weapons after death (primary and secondary) | +| mp_ammodrop | 1 | 0 | 2 | Drop ammo on weapon boxes on death or manual drop.
`0` always keep ammo on player
`1` drop all ammo only after death
`2` drop all ammo whenever player drops a weapon | | mp_roundrespawn_time | 20 | 0 | - | Player cannot respawn until next round if more than N seconds has elapsed since the beginning round.
`-1` means no time limit
| | mp_auto_reload_weapons | 0 | 0 | 1 | Automatically reload each weapon on player spawn.
`0` disabled
`1` enabled | | mp_refill_bpammo_weapons | 0 | 0 | 2 | Refill amount of backpack ammo up to the max.
`0` disabled
`1` refill backpack ammo on player spawn
`2` refill backpack ammo on player spawn and on the purchase of the item | diff --git a/dist/game.cfg b/dist/game.cfg index efebcba8..25ba9877 100644 --- a/dist/game.cfg +++ b/dist/game.cfg @@ -78,6 +78,24 @@ mp_hegrenade_penetration "0" // Default value: "0" mp_nadedrops "0" +// Drop player weapon after death +// 0 - do not drop weapons after death +// 1 - drop best/heaviest weapon after death (default behaviour) +// 2 - drop active weapon after death +// 3 - drop all weapons after death (primary and secondary) +// NOTE: Grenades are dropped separately depending on mp_nadedrops value +// +// Default value: "1" +mp_weapondrop "1" + +// Drop ammo on weapon boxes on death or manual drop +// 0 - always keep ammo on player +// 1 - drop all ammo only after death (default behaviour) +// 2 - drop all ammo whenever player drops a weapon (NOTE: Other weapons may remain without ammo due to same ammo sharing) +// +// Default value: "1" +mp_ammodrop "1" + // Player cannot respawn until next round // if more than N seconds has elapsed since the beginning round // -1 - means no time limit diff --git a/regamedll/dlls/game.cpp b/regamedll/dlls/game.cpp index 11e35513..2e0ef12b 100644 --- a/regamedll/dlls/game.cpp +++ b/regamedll/dlls/game.cpp @@ -109,6 +109,8 @@ cvar_t maxmoney = { "mp_maxmoney", "16000", FCVAR_SERVER, 0.0f, nul cvar_t round_infinite = { "mp_round_infinite", "0", FCVAR_SERVER, 0.0f, nullptr }; cvar_t hegrenade_penetration = { "mp_hegrenade_penetration", "0", 0, 0.0f, nullptr }; cvar_t nadedrops = { "mp_nadedrops", "0", 0, 0.0f, nullptr }; +cvar_t weapondrop = { "mp_weapondrop", "1", 0, 1.0f, nullptr }; +cvar_t ammodrop = { "mp_ammodrop", "1", 0, 1.0f, nullptr }; cvar_t roundrespawn_time = { "mp_roundrespawn_time", "20", 0, 20.0f, nullptr }; cvar_t auto_reload_weapons = { "mp_auto_reload_weapons", "0", 0, 0.0f, nullptr }; cvar_t refill_bpammo_weapons = { "mp_refill_bpammo_weapons", "0", 0, 0.0f, nullptr }; // Useful for mods like DeathMatch, GunGame, ZombieMod etc @@ -351,6 +353,8 @@ void EXT_FUNC GameDLLInit() CVAR_REGISTER(&round_infinite); CVAR_REGISTER(&hegrenade_penetration); CVAR_REGISTER(&nadedrops); + CVAR_REGISTER(&weapondrop); + CVAR_REGISTER(&ammodrop); CVAR_REGISTER(&roundrespawn_time); CVAR_REGISTER(&auto_reload_weapons); CVAR_REGISTER(&refill_bpammo_weapons); diff --git a/regamedll/dlls/game.h b/regamedll/dlls/game.h index a9b9158b..ed2ae509 100644 --- a/regamedll/dlls/game.h +++ b/regamedll/dlls/game.h @@ -138,6 +138,8 @@ extern cvar_t maxmoney; extern cvar_t round_infinite; extern cvar_t hegrenade_penetration; extern cvar_t nadedrops; +extern cvar_t weapondrop; +extern cvar_t ammodrop; extern cvar_t roundrespawn_time; extern cvar_t auto_reload_weapons; extern cvar_t refill_bpammo_weapons; diff --git a/regamedll/dlls/gamerules.h b/regamedll/dlls/gamerules.h index 5eee3a6d..d6975df0 100644 --- a/regamedll/dlls/gamerules.h +++ b/regamedll/dlls/gamerules.h @@ -186,6 +186,10 @@ enum GR_PLR_DROP_AMMO_ALL, GR_PLR_DROP_AMMO_ACTIVE, GR_PLR_DROP_AMMO_NO, + +#ifdef REGAMEDLL_ADD + GR_PLR_DROP_GUN_BEST, +#endif }; // custom enum diff --git a/regamedll/dlls/multiplay_gamerules.cpp b/regamedll/dlls/multiplay_gamerules.cpp index c40af8fb..baf91658 100644 --- a/regamedll/dlls/multiplay_gamerules.cpp +++ b/regamedll/dlls/multiplay_gamerules.cpp @@ -4332,11 +4332,29 @@ LINK_HOOK_CLASS_CUSTOM_CHAIN(int, CHalfLifeMultiplay, CSGameRules, DeadPlayerWea int EXT_FUNC CHalfLifeMultiplay::__API_HOOK(DeadPlayerWeapons)(CBasePlayer *pPlayer) { - return GR_PLR_DROP_GUN_ACTIVE; +#ifdef REGAMEDLL_ADD + switch ((int)weapondrop.value) + { + case 3: + return GR_PLR_DROP_GUN_ALL; + case 2: + break; + case 1: + return GR_PLR_DROP_GUN_BEST; + default: + return GR_PLR_DROP_GUN_NO; + } +#endif + return GR_PLR_DROP_GUN_ACTIVE; // keep original value in return } int CHalfLifeMultiplay::DeadPlayerAmmo(CBasePlayer *pPlayer) { +#ifdef REGAMEDLL_ADD + if (ammodrop.value == 0.0f) + return GR_PLR_DROP_AMMO_NO; +#endif + return GR_PLR_DROP_AMMO_ACTIVE; } diff --git a/regamedll/dlls/player.cpp b/regamedll/dlls/player.cpp index 794ee80b..cfc27492 100644 --- a/regamedll/dlls/player.cpp +++ b/regamedll/dlls/player.cpp @@ -1297,7 +1297,14 @@ CWeaponBox *EXT_FUNC __API_HOOK(CreateWeaponBox)(CBasePlayerItem *pItem, CBasePl #else pWeaponBox->GiveAmmo(pPlayerOwner->m_rgAmmo[pItem->PrimaryAmmoIndex()], (char *)pItem->pszAmmo1(), pItem->iMaxAmmo1()); #endif +#ifndef REGAMEDLL_FIXES + // by removing ammo ONLY on exhaustible weapons (slot 4 and 5) + // you are allowing to duplicate ammo whenever: + // (1) you have 2 weapons sharing the same ammo type (e.g. mp5navy and glock) + // (2) you are dropping a weapon alive and pickup another (with same ammo type) without ammo + // and, logically, you throw your ammo with your gun with packing enabled if (exhaustibleAmmo) +#endif { pPlayerOwner->m_rgAmmo[pItem->PrimaryAmmoIndex()] = 0; } @@ -1309,10 +1316,10 @@ CWeaponBox *EXT_FUNC __API_HOOK(CreateWeaponBox)(CBasePlayerItem *pItem, CBasePl return pWeaponBox; } -void PackPlayerItem(CBasePlayer *pPlayer, CBasePlayerItem *pItem, bool packAmmo) +CWeaponBox *PackPlayerItem(CBasePlayer *pPlayer, CBasePlayerItem *pItem, bool packAmmo) { if (!pItem) - return; + return nullptr; const char *modelName = GetCSModelName(pItem->m_iId); if (modelName) @@ -1322,7 +1329,7 @@ void PackPlayerItem(CBasePlayer *pPlayer, CBasePlayerItem *pItem, bool packAmmo) Vector vecVelocity = pPlayer->pev->velocity * 0.75f; // create a box to pack the stuff into - CreateWeaponBox(pItem, pPlayer, + return CreateWeaponBox(pItem, pPlayer, modelName, vecOrigin, vecAngles, @@ -1330,6 +1337,8 @@ void PackPlayerItem(CBasePlayer *pPlayer, CBasePlayerItem *pItem, bool packAmmo) CGameRules::GetItemKillDelay(), packAmmo ); } + + return nullptr; } #ifdef REGAMEDLL_ADD @@ -1386,78 +1395,130 @@ void PackPlayerNade(CBasePlayer *pPlayer, CBasePlayerItem *pItem, bool packAmmo) void CBasePlayer::PackDeadPlayerItems() { // get the game rules - bool bPackGun = (g_pGameRules->DeadPlayerWeapons(this) != GR_PLR_DROP_GUN_NO); + int iPackGun = g_pGameRules->DeadPlayerWeapons(this); bool bPackAmmo = (g_pGameRules->DeadPlayerAmmo(this) != GR_PLR_DROP_AMMO_NO); - if (bPackGun) + if (iPackGun != GR_PLR_DROP_GUN_NO) { - bool bShieldDropped = false; + bool bSkipPrimSec = false; if (HasShield()) { DropShield(); - bShieldDropped = true; +#ifdef REGAMEDLL_ADD + if(iPackGun != GR_PLR_DROP_GUN_ALL) +#endif + { + bSkipPrimSec = true; + } } int nBestWeight = 0; CBasePlayerItem *pBestItem = nullptr; - for (int n = 0; n < MAX_ITEM_TYPES; n++) - { - // there's a weapon here. Should I pack it? - CBasePlayerItem *pPlayerItem = m_rgpPlayerItems[n]; +#ifdef REGAMEDLL_ADD + int iGunsPacked = 0; - while (pPlayerItem) + if (iPackGun == GR_PLR_DROP_GUN_ACTIVE) + { + // check if we've just already dropped our active gun + if (!bSkipPrimSec && m_pActiveItem && m_pActiveItem->CanDrop() && m_pActiveItem->iItemSlot() < KNIFE_SLOT) { - ItemInfo info; - if (pPlayerItem->iItemSlot() < KNIFE_SLOT && !bShieldDropped) - { -#ifdef REGAMEDLL_API - if (pPlayerItem->CSPlayerItem()->GetItemInfo(&info)) -#else - if (pPlayerItem->GetItemInfo(&info)) + pBestItem = m_pActiveItem; + + // if active item is undroppable, then nothing is dropped + } + + // are we allowing nade drop? + if ((int)nadedrops.value >= 1) + { + // goto item loop but skip guns + iPackGun = GR_PLR_DROP_GUN_ALL; + bSkipPrimSec = true; + } + } + + if (iPackGun == GR_PLR_DROP_GUN_ALL || iPackGun == GR_PLR_DROP_GUN_BEST) #endif + { + for (int n = 0; n < MAX_ITEM_TYPES; n++) + { + // there's a weapon here. Should I pack it? + CBasePlayerItem *pPlayerItem = m_rgpPlayerItems[n]; + + while (pPlayerItem) + { + ItemInfo info; + if (pPlayerItem->iItemSlot() < KNIFE_SLOT && !bSkipPrimSec) { - if (info.iWeight > nBestWeight) +#ifdef REGAMEDLL_API + if (pPlayerItem->CSPlayerItem()->GetItemInfo(&info) +#else + if (pPlayerItem->GetItemInfo(&info) +#endif +#ifdef REGAMEDLL_FIXES + && pPlayerItem->CanDrop() // needs to be droppable +#endif + ) { - nBestWeight = info.iWeight; - pBestItem = pPlayerItem; +#ifdef REGAMEDLL_ADD + if (iPackGun == GR_PLR_DROP_GUN_ALL) + { + CBasePlayerItem *pNext = pPlayerItem->m_pNext; + + CWeaponBox *pWeaponBox = PackPlayerItem(this, pPlayerItem, bPackAmmo); + if (pWeaponBox) + { + // just push a few units in forward to separate them + pWeaponBox->pev->velocity = pWeaponBox->pev->velocity * (1.0 + (iGunsPacked * 0.2)); + iGunsPacked++; + } + + pPlayerItem = pNext; + continue; + } +#endif + if (info.iWeight > nBestWeight) + { + nBestWeight = info.iWeight; + pBestItem = pPlayerItem; + } } } - } - // drop a grenade after death - else if (pPlayerItem->iItemSlot() == GRENADE_SLOT) - { - if (AreRunningCZero()) + // drop a grenade after death + else if (pPlayerItem->iItemSlot() == GRENADE_SLOT) { + if (AreRunningCZero()) + { #ifdef REGAMEDLL_FIXES - if (pPlayerItem->m_flStartThrow == 0.0f && m_rgAmmo[pPlayerItem->PrimaryAmmoIndex()] > 0) + if (pPlayerItem->m_flStartThrow == 0.0f && m_rgAmmo[pPlayerItem->PrimaryAmmoIndex()] > 0) #endif - { - PackPlayerItem(this, pPlayerItem, true); + { + PackPlayerItem(this, pPlayerItem, true); + } } - } #ifdef REGAMEDLL_ADD - else - { - switch ((int)nadedrops.value) + else { - case 1: - PackPlayerNade(this, pPlayerItem, true); - break; - case 2: - { - CBasePlayerItem *pNext = pPlayerItem->m_pNext; - PackPlayerNade(this, pPlayerItem, true); - pPlayerItem = pNext; - continue; + switch ((int)nadedrops.value) + { + case 1: + PackPlayerNade(this, pPlayerItem, true); + break; + case 2: + { + CBasePlayerItem *pNext = pPlayerItem->m_pNext; + PackPlayerNade(this, pPlayerItem, true); + pPlayerItem = pNext; + continue; + } + } } - } - } #endif - } + } - pPlayerItem = pPlayerItem->m_pNext; + pPlayerItem = pPlayerItem->m_pNext; + } } } @@ -8033,13 +8094,21 @@ CBaseEntity *EXT_FUNC CBasePlayer::__API_HOOK(DropPlayerItem)(const char *pszIte Vector vecAngles = pev->angles; Vector vecVelocity = gpGlobals->v_forward * 300 + gpGlobals->v_forward * 100; + bool bPackAmmo = false; + +#ifdef REGAMEDLL_ADD + if (ammodrop.value >= 2.0f) + bPackAmmo = true; +#endif + CWeaponBox *pWeaponBox = CreateWeaponBox(pWeapon, this, modelname, vecOrigin, vecAngles, vecVelocity, CGameRules::GetItemKillDelay(), - false); + bPackAmmo + ); if (!pWeaponBox) {