halflife icon indicating copy to clipboard operation
halflife copied to clipboard

Trip mine laser beam duplicates after going back and forth through level changes

Open SamVanheer opened this issue 2 years ago • 1 comments

An active trip mine will duplicate its laser beam after going back and forth through level changes.

This video shows the problem: https://www.youtube.com/watch?v=PizJX3pc0xk

This happens because effects entities like beams don't transition to other maps: https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/effects.h#L112

When the trip mine transitions to another map it recreates the beam. When you go back to the previous map it will also recreate the beam, but the original beam entity will still exist since the beam is saved and restored by default: https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/effects.h#L110-L111

Effects entities encode which entity they attach to in a way that makes transitioning them rather complicated so that's not an option.

To fix this the beam needs to be made temporary so that the trip mine code can recreate it on demand.

Change this: https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/tripmine.cpp#L86

To this:

//Don't save, recreate.
//DEFINE_FIELD(CTripmineGrenade, m_pBeam, FIELD_CLASSPTR),

After this line: https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/tripmine.cpp#L257

Add this:

//Mark as temporary so the beam will be recreated on save game load and level transitions.
m_pBeam->pev->spawnflags |= SF_BEAM_TEMPORARY;

The trip mine will now recreate the beam. The logic for this already exists: https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/tripmine.cpp#L277-L283

But is incorrect, and will cause some tripmines to explode when loading save games (e.g. on c1a3d).

This is the corrected code:

if (!m_pBeam)
{
	// Use the same trace parameters as the original trace above so the right entity is hit.
	TraceResult tr2;
	UTIL_TraceLine(pev->origin + m_vecDir * 8, pev->origin - m_vecDir * 32, dont_ignore_monsters, ENT(pev), &tr2);
	MakeBeam();
	if (tr2.pHit)
	{
		// reset owner too
		pev->owner = tr2.pHit;
		m_hOwner = CBaseEntity::Instance(tr2.pHit);
	}
}

Also of note: the reason why the beams seem to attach to random entities (the light and battery in the video) is because the beam uses PointEntInit, and the entity endpoint stores the index of the entity. The tripmine entity index is not consistent between the two maps, so it will attach to whichever entity is in that slot, if any. If there is no entity it will still attach to that slot, but the origin value won't be valid and will likely be 0, 0, 0, or whatever the last value was that the client received from the server for that slot.

Issue #1670 covers a bug fix that changes the beam to use PointsInit so that particular aspect of this bug won't happen. Instead the beams will overlap, creating a seemingly brighter beam.

This bug was originally found by vasiavasiavasia95.

SamVanheer avatar Feb 10 '22 14:02 SamVanheer

Updated with a fix for tripmines exploding when loading save games.

SamVanheer avatar Sep 26 '22 09:09 SamVanheer