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 <wopox1337@ya.ru>

* Improve readability

* Improve readability x2

Co-authored-by: Sergey Shorokhov <wopox1337@ya.ru>

* Tabulation tip

* Compile error resolved

* Add mp_weapondrop 3: drop all weapons

---------

Co-authored-by: Sergey Shorokhov <wopox1337@ya.ru>
This commit is contained in:
Francisco Muñoz 2023-07-10 08:45:24 -04:00 committed by GitHub
parent d4deabfe59
commit 8ddda261fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 166 additions and 49 deletions

View File

@ -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.<br/>`0` disabled<br/>`1` enabled |
| mp_nadedrops | 0 | 0 | 2 | Drop a grenade after player death.<br/>`0` disabled<br/>`1` drop first available grenade<br/>`2` drop all grenades |
| mp_weapondrop | 1 | 0 | 3 | Drop player weapon after death.<br/>`0` do not drop weapons after death<br/>`1` drop best/heaviest weapon after death<br/>`2` drop active weapon after death<br/>`3` drop all weapons after death (primary and secondary) |
| mp_ammodrop | 1 | 0 | 2 | Drop ammo on weapon boxes on death or manual drop.<br/>`0` always keep ammo on player<br/>`1` drop all ammo only after death<br/>`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.<br />`-1` means no time limit<br /> |
| mp_auto_reload_weapons | 0 | 0 | 1 | Automatically reload each weapon on player spawn.<br/>`0` disabled<br/>`1` enabled |
| mp_refill_bpammo_weapons | 0 | 0 | 2 | Refill amount of backpack ammo up to the max.<br/>`0` disabled<br/>`1` refill backpack ammo on player spawn<br/>`2` refill backpack ammo on player spawn and on the purchase of the item |

18
dist/game.cfg vendored
View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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)
{