Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Picking up weapons that give free/regenerating ammo sometimes shows weapon icon as red #3250

Open
SamVanheer opened this issue Mar 1, 2022 · 0 comments

Comments

@SamVanheer
Copy link

Sometimes when you pick up a weapon that gives free or regenerating ammo on pickup the weapon icon shows as red to indicate the weapon is out of ammo.

This happens with the Hornet gun. To reproduce:

  1. Start a multiplayer game (e.g. on map crossfire)
  2. Pick up a Hornet gun
  3. Empty it completely
  4. Drop it before it regenerates ammo (console command drop weapon_hornetgun)
  5. Pick the weapon up again
  6. The HUD will show the weapon as red for a moment before changing it to the normal HUD color

This happens because the ammo HUD isn't told about ammo immediately. The server only updates the client's ammo HUD when it's processing inputs received from the client, which happens at a certain time relative to the server processing weapon pickup to allow out-of-sync state to occur.

As a result there is a small window between the server sending the weapon pickup message and the ammo update message.

To fix this the ammo HUD needs to be updated before the weapon pickup is sent.

The fix i'm about to describe builds on the fix for #3137.

After this line:

void SendAmmoUpdate(void);

Add:

void SendSingleAmmoUpdate(int ammoIndex);

private:
void InternalSendSingleAmmoUpdate(int ammoIndex);

public:

Modify this function:

halflife/dlls/player.cpp

Lines 3918 to 3936 in c7240b9

void CBasePlayer::SendAmmoUpdate(void)
{
for (int i=0; i < MAX_AMMO_SLOTS;i++)
{
if (m_rgAmmo[i] != m_rgAmmoLast[i])
{
m_rgAmmoLast[i] = m_rgAmmo[i];
ASSERT( m_rgAmmo[i] >= 0 );
ASSERT( m_rgAmmo[i] < 255 );
// send "Ammo" update message
MESSAGE_BEGIN( MSG_ONE, gmsgAmmoX, NULL, pev );
WRITE_BYTE( i );
WRITE_BYTE( max( min( m_rgAmmo[i], 254 ), 0 ) ); // clamp the value to one byte
MESSAGE_END();
}
}
}

To look like this:

void CBasePlayer::SendAmmoUpdate()
{
	for (int i = 0; i < MAX_AMMO_SLOTS; i++)
	{
		InternalSendSingleAmmoUpdate(i);
	}
}

void CBasePlayer::SendSingleAmmoUpdate(int ammoIndex)
{
	if (ammoIndex < 0 || ammoIndex >= MAX_AMMO_SLOTS)
	{
		return;
	}

	InternalSendSingleAmmoUpdate(ammoIndex);
}

void CBasePlayer::InternalSendSingleAmmoUpdate(int ammoIndex)
{
	if (m_rgAmmo[ammoIndex] != m_rgAmmoLast[ammoIndex])
	{
		m_rgAmmoLast[ammoIndex] = m_rgAmmo[ammoIndex];

		ASSERT(m_rgAmmo[ammoIndex] >= 0);
		ASSERT(m_rgAmmo[ammoIndex] < 255);

		// send "Ammo" update message
		MESSAGE_BEGIN(MSG_ONE, gmsgAmmoX, NULL, pev);
		WRITE_BYTE(ammoIndex);
		WRITE_BYTE(max(min(m_rgAmmo[ammoIndex], 254), 0)); // clamp the value to one byte
		MESSAGE_END();
	}
}

Referencing the code from #3137, modify CBasePlayerWeapon::AddToPlayer 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;
	}

	//Immediately update the ammo HUD so weapon pickup isn't sometimes red because the HUD doesn't know about regenerating/free ammo yet.
	if (-1 != m_iPrimaryAmmoType)
	{
		m_pPlayer->SendSingleAmmoUpdate(CBasePlayer::GetAmmoIndex(pszAmmo1()));
	}

	if (-1 != m_iSecondaryAmmoType)
	{
		m_pPlayer->SendSingleAmmoUpdate(CBasePlayer::GetAmmoIndex(pszAmmo2()));
	}

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

The changes made to SendAmmoUpdate allows the weapons code to send an update for a single ammo type. The changes made to AddToPlayer updates the ammo HUD before updating the pickup history HUD.

hammermaps added a commit to sohl-modders/Updated-SOHL-1.2 that referenced this issue Apr 24, 2023
@SamVanheer SamVanheer reopened this May 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants