Skip to content

Commit

Permalink
CWeaponBox::Touch: Reworked dropped grenade pickup
Browse files Browse the repository at this point in the history
  • Loading branch information
s1lentq committed Feb 4, 2024
1 parent 4d90a5f commit 5d2174f
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 21 deletions.
38 changes: 38 additions & 0 deletions regamedll/dlls/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6351,6 +6351,44 @@ CBaseEntity *CBasePlayer::GiveNamedItemEx(const char *pszName)
return pEntity;
}

// Creates a copy of the specified entity (pEntitySource) and gives it to the player
// The cloned entity inherits base properties (entvars) of the original entity
// Returns Pointer to the cloned entity, or NULL if the entity cannot be created
CBaseEntity *CBasePlayer::GiveCopyItem(CBaseEntity *pEntitySource)
{
edict_t *pEdict = CREATE_NAMED_ENTITY(pEntitySource->pev->classname);
if (FNullEnt(pEdict))
{
ALERT(at_console, "NULL Ent in GiveCloneItem classname `%s`!\n", STRING(pEntitySource->pev->classname));
return nullptr;
}

// copy entity properties
Q_memcpy(&pEdict->v, pEntitySource->pev, sizeof(pEdict->v));

pEdict->v.pContainingEntity = pEdict;
pEdict->v.origin = pev->origin;
pEdict->v.spawnflags |= SF_NORESPAWN;
pEdict->v.owner = NULL; // will re-link owner after touching
pEdict->v.chain = ENT(pEntitySource->pev); // refer to source copy entity

DispatchSpawn(pEdict);
DispatchTouch(pEdict, ENT(pev));
pEdict->v.chain = NULL;

CBaseEntity *pEntity = GET_PRIVATE<CBaseEntity>(pEdict);

// not allow the item to fall to the ground.
if (FNullEnt(pEdict->v.owner) || pEdict->v.owner != edict())
{
pEdict->v.flags |= FL_KILLME;
UTIL_Remove(pEntity);
return nullptr;
}

return pEntity;
}

CBaseEntity *FindEntityForward(CBaseEntity *pEntity)
{
TraceResult tr;
Expand Down
1 change: 1 addition & 0 deletions regamedll/dlls/player.h
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,7 @@ class CBasePlayer: public CBaseMonster {
void ItemPostFrame();
CBaseEntity *GiveNamedItem(const char *pszName);
CBaseEntity *GiveNamedItemEx(const char *pszName);
CBaseEntity *GiveCopyItem(CBaseEntity *pEntityBase);
void EnableControl(BOOL fControl);
bool HintMessage(const char *pMessage, BOOL bDisplayIfPlayerDead = FALSE, BOOL bOverride = FALSE);
bool HintMessageEx(const char *pMessage, float duration = 6.0f, bool bDisplayIfPlayerDead = false, bool bOverride = false);
Expand Down
86 changes: 65 additions & 21 deletions regamedll/dlls/weapons.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1852,39 +1852,72 @@ bool CWeaponBox::GiveAmmoToPlayer(CBasePlayer *pPlayer, CBasePlayerWeapon *pWeap
return false; // can't pickup more, these ammo are full in backpack

// If already have a weapon in backpack, just refill ammo for it
if (iCurrentAmmo > 0)
int iAmmoIndex = GetAmmoIndex(pszAmmo);
if (iAmmoIndex > 0)
{
int iAmmoIndex = GetAmmoIndex(pszAmmo);
if (iAmmoIndex > 0)
// How many weapon ammo can pick up?
int iAmmoPickup = min(m_rgAmmo[iAmmoIndex], iMaxAmmo - iCurrentAmmo);
if (iAmmoPickup > 0)
{
// how many gren ammo can pick up?
int iAmmoPickup = min(m_rgAmmo[iAmmoIndex], iMaxAmmo - iCurrentAmmo);
if (iAmmoPickup > 0)
if (iCurrentAmmo == 0 && !(pPlayer->pev->weapons & (1<<pWeapon->m_iId)) && (pWeapon->iFlags() & ITEM_FLAG_EXHAUSTIBLE))
{
if (!FStringNull(m_rgiszAmmo[iAmmoIndex]) &&
pPlayer->GiveAmmo(iAmmoPickup, STRING(m_rgiszAmmo[iAmmoIndex]), iMaxAmmo) != -1)
if (m_rgAmmo[iAmmoIndex] > iMaxAmmo)
{
m_rgAmmo[iAmmoIndex] -= iAmmoPickup;

if (m_rgAmmo[iAmmoIndex] < 0)
m_rgAmmo[iAmmoIndex] = 0;
// If ammo capacity of the dropped weapon exceeds the player's backpack capacity,
// make a copy of dropped weapon and give it to the player
CBasePlayerItem *copyItem = (CBasePlayerItem *)pPlayer->GiveCopyItem(pWeapon);
if (copyItem)
{
// The cloned weapon must inherit properties from a dropped weapon, such as Item Info
#ifdef REGAMEDLL_API
ItemInfo info;
if (pWeapon->CSPlayerItem()->GetItemInfo(&info))
copyItem->CSPlayerItem()->SetItemInfo(&info);
#endif
m_rgAmmo[iAmmoIndex]--;
iAmmoPickup--;
}
}
else
{
// If no weapon in backpack, then issue weapon
if (pPlayer->AddPlayerItem(pWeapon))
{
pWeapon->AttachToPlayer(pPlayer);
if (pGivenItem) *pGivenItem = pWeapon;
}

EMIT_SOUND(pPlayer->edict(), CHAN_ITEM, "items/9mmclip1.wav", VOL_NORM, ATTN_NORM);
// unlink this weapon from the box
return true;
}
}

// ammo exhausted, remove this weapon
if (m_rgAmmo[iAmmoIndex] <= 0)
Assert(iAmmoPickup != 0);
Assert(m_rgAmmo[iAmmoIndex] != 0);

if (!FStringNull(m_rgiszAmmo[iAmmoIndex]) &&
pPlayer->GiveAmmo(iAmmoPickup, STRING(m_rgiszAmmo[iAmmoIndex]), iMaxAmmo) != -1)
{
pWeapon->Kill();
m_rgAmmo[iAmmoIndex] -= iAmmoPickup;

// unlink this weapon from the box
return true;
if (m_rgAmmo[iAmmoIndex] < 0)
m_rgAmmo[iAmmoIndex] = 0;

EMIT_SOUND(pPlayer->edict(), CHAN_ITEM, "items/9mmclip1.wav", VOL_NORM, ATTN_NORM);
}
}

// ammo has not been exhausted yet, keep this weapon in weaponbox
return false;
// ammo exhausted, remove this weapon
if (m_rgAmmo[iAmmoIndex] <= 0)
{
pWeapon->Kill();

// unlink this weapon from the box
return true;
}

// ammo has not been exhausted yet, keep this weapon in weaponbox
return false;
}

// If no weapon in backpack, then issue weapon
Expand Down Expand Up @@ -2045,9 +2078,20 @@ void CWeaponBox::Touch(CBaseEntity *pOther)
#ifdef REGAMEDLL_FIXES
CBasePlayerItem *pNext = m_rgpPlayerItems[i]->m_pNext;

// Determine the max ammo capacity for the picked-up grenade
int iMaxPickupAmmo = pGrenade->iMaxAmmo1();

// If the player already has the same weapon in inventory,
// prioritize the max ammo capacity value over the one from the dropped weapon
// When the pickup occurs, ammo will be granted up to
// the max ammo capacity of the weapon currently held by the player
CBasePlayerItem *pInventoryItem = (CBasePlayerItem *)pPlayer->GetItemById((WeaponIdType)pGrenade->m_iId);
if (pInventoryItem && !Q_stricmp(pInventoryItem->pszAmmo1(), pGrenade->pszAmmo1()))
iMaxPickupAmmo = pInventoryItem->iMaxAmmo1();

// Pickup grenade item or refill ammo
if (GiveAmmoToPlayer(pPlayer, pGrenade,
playerGrenades, pGrenade->pszAmmo1(), pGrenade->iMaxAmmo1(), &givenItem))
playerGrenades, pGrenade->pszAmmo1(), iMaxPickupAmmo, &givenItem))
{
// unlink this weapon from the box
m_rgpPlayerItems[i] = pItem = pNext;
Expand Down

0 comments on commit 5d2174f

Please sign in to comment.