ValveSoftware / halflife

Half-Life 1 engine based games
Other
3.65k stars 617 forks source link

(Half-Life/Opposing Force) Show pickup icons in HUD for all weapons #3137

Open matinlunaire opened 3 years ago

matinlunaire commented 3 years ago

Normally, GoldSource games display notification icons when picking up certain weapons, like these: 20210904061658_1

However, these icons never show for picking up crowbar, wrench, knife, or pistol, both in single player and deathmatch.

Would be nice to see them for these weapons too, as some maps don't give them by default and this makes orientation in game world a bit easier. Also handy when picking up dropped backpacks.

SamVanheer commented 2 years ago

I suspect the reason why they don't show pickup icons for those weapons is because you spawn with the crowbar and pistol in Half-Life multiplayer, and in Opposing Force CTF you start with the wrench and desert eagle.

To stop you from seeing the pickup icons on spawn they disabled that.

The code can be reworked to do both:

In util.h add this to the end of the file:

/**
*   @brief Helper type to run a function when the helper is destroyed.
*   Useful for running cleanup on scope exit and function return.
*/
template<typename Func>
struct CallOnDestroy
{
    const Func Function;

    explicit CallOnDestroy(Func&& function)
        : Function(function)
    {
    }

    ~CallOnDestroy()
    {
        Function();
    }
};

At the end of the CBasePlayer class definition here: https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/player.h#L324-L326

Add this:

public:
//True if the player is currently spawning.
bool m_bIsSpawning = false;

At the start of this function: https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/player.cpp#L2850-L2852

Add this (requires C++11 or newer):

m_bIsSpawning = true;

//Make sure this gets reset even if somebody adds an early return or throws an exception.
const CallOnDestroy resetIsSpawning{[this]()
    {
        //Done spawning; reset.
        m_bIsSpawning = false;
    }
};

Modify this function: https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/weapons.cpp#L792-L808

To look like this:

bool CBasePlayerWeapon::AddToPlayer(CBasePlayer* pPlayer)
{
    int bResult = CBasePlayerItem::AddToPlayer(pPlayer);

    pPlayer->pev->weapons |= (1<<m_iId);

    if (!m_iPrimaryAmmoType)
    {
        m_iPrimaryAmmoType = pPlayer->GetAmmoIndex(pszAmmo1());
        m_iSecondaryAmmoType = pPlayer->GetAmmoIndex(pszAmmo2());
    }

    if (!bResult)
    {
        return FALSE;
    }

    if (!AddWeapon())
    {
        return FALSE;
    }

    //Don't show weapon pickup if we're spawning or if it's an exhaustible weapon (will show ammo pickup instead).
    if (!m_pPlayer->m_bIsSpawning && (iFlags() & ITEM_FLAG_EXHAUSTIBLE) == 0)
    {
        MESSAGE_BEGIN(MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev);
        WRITE_BYTE(m_iId);
        MESSAGE_END();
    }

    return TRUE;
}

Remove the AddToPlayer function from all weapon classes except CHgun and CSatchel. Those two need to be modified.

Modify this function: https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/hornetgun.cpp#L75-L94

To look like this:

int CHgun::AddToPlayer(CBasePlayer* pPlayer)
{
#ifndef CLIENT_DLL
    if (g_pGameRules->IsMultiplayer())
    {
        // in multiplayer, all hivehands come full.
        m_iDefaultAmmo = HORNET_MAX_CARRY;
    }
#endif

    return CBasePlayerWeapon::AddToPlayer(pPlayer);
}

Modify this function: https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/satchel.cpp#L201-L213

To look like this:

int CSatchel::AddToPlayer(CBasePlayer* pPlayer)
{
    m_chargeReady = 0; // this satchel charge weapon now forgets that any satchels are deployed by it.
    return CBasePlayerWeapon::AddToPlayer(pPlayer);
}

The changes made to the player class allows code to know if the player is currently spawning.

The changes made to the weapon base class lets the base class handle the weapon pickup logic. It'll tell the HUD to show the pickup if the player isn't spawning (weapons given on spawn will not show up as a pickup) and if it's not an exhaustible weapon.

Exhaustible weapons are the hand grenade, satchel charge, tripmine and Snark grenade. They don't currently show up as weapon pickups, only as ammo pickups so this behavior is consistent with what it was before.

The changes made to the Hornet gun code ensures the weapon always has ammo when picked up, even if another player emptied it before dropping it. This was the original behavior, now done in a slightly different way that results in the same behavior.

The changes made to the Satchel charge code ensures the weapon forgets about deployed satchels as before, only now it doesn't skip the CBasePlayerWeapon version of AddToPlayer. This fixes a minor issue where m_iPrimaryAmmoType isn't initialized and ensures consistency with all other weapons in calling the correct version of the function. It also gets rid of a minor case of code duplication (the AddWeapon part).