diff --git a/src/game/server/swarm/asw_radiation_volume.cpp b/src/game/server/swarm/asw_radiation_volume.cpp index cd5db90b8..97c96aede 100644 --- a/src/game/server/swarm/asw_radiation_volume.cpp +++ b/src/game/server/swarm/asw_radiation_volume.cpp @@ -44,7 +44,7 @@ void CASW_Radiation_Volume::Spawn( void ) AddEffects(EF_NODRAW); SetSolid( SOLID_BBOX ); float boxWidth = m_flBoxWidth; - UTIL_SetSize(this, Vector(-boxWidth,-boxWidth,0),Vector(boxWidth,boxWidth,boxWidth * 2)); + UTIL_SetSize( this, Vector( -boxWidth, -boxWidth, 0 ), Vector( boxWidth, boxWidth, boxWidth * 2 ) ); SetCollisionGroup(ASW_COLLISION_GROUP_PASSABLE); AddSolidFlags(FSOLID_TRIGGER | FSOLID_NOT_SOLID); SetTouch( &CASW_Radiation_Volume::RadTouch ); @@ -61,25 +61,67 @@ bool CASW_Radiation_Volume::IsValidRadTarget( CBaseEntity *pOther ) return pOther->IsNPC(); } -void CASW_Radiation_Volume::RadTouch( CBaseEntity *pOther ) +// Helper centralizing detection logic used by RadTouch and RadTouching +bool CASW_Radiation_Volume::IsInRadiationVolume( CBaseEntity *pEnt ) { - // if other is a valid entity to radiate, add it to our list - if (IsValidRadTarget(pOther) && m_hRadTouching.Find(pOther) == m_hRadTouching.InvalidIndex()) + if ( !pEnt ) + return false; + + // m_flBoxWidth used as radius: + const float flRadius = m_flBoxWidth; + const float flRadiusSqr = flRadius * flRadius; + + const Vector vecCenter = GetAbsOrigin(); + CCollisionProperty* pEntColl = pEnt->CollisionProp(); + CCollisionProperty* pVolColl = CollisionProp(); + if ( !pVolColl ) + return false; + + // compute the nearest point on the other entity to our center (robust for large NPCs) + Vector vecNearest; + if ( pEntColl ) + pEntColl->CalcNearestPoint( vecCenter, &vecNearest ); + else + vecNearest = pEnt->WorldSpaceCenter(); + + // If other is a marine, use CYLINDER test: + // - horizontal (XY) distance < radius + // - AND the nearest point must be within our cuboid bounds (so Z is constrained by the volume) + if ( pEnt->Classify() == CLASS_ASW_MARINE ) { - m_hRadTouching.AddToTail(pOther); - if (GetNextThink() == TICK_NEVER_THINK) - SetNextThink( gpGlobals->curtime ); + // must be inside vertical bounds (cuboid) + if ( !pVolColl->IsPointInBounds( vecNearest ) ) + return false; + + // horizontal delta (XY) + Vector vecDelta = vecNearest - vecCenter; + // horizontal distance squared check (circle) + if ( ( vecDelta.x * vecDelta.x + vecDelta.y * vecDelta.y ) >= flRadiusSqr ) + return false; + + return true; } + // aliens: full cuboid + return pVolColl->IsPointInBounds( vecNearest ); } -bool CASW_Radiation_Volume::RadTouching(CBaseEntity *pEnt) +void CASW_Radiation_Volume::RadTouch( CBaseEntity* pOther ) { - if (!pEnt || !pEnt->CollisionProp() || !CollisionProp()) - return false; + // if other is a valid entity to radiate, add it to our list + if ( !IsValidRadTarget( pOther ) + || m_hRadTouching.Find( pOther ) != m_hRadTouching.InvalidIndex() // avoid duplicates + || !IsInRadiationVolume( pOther ) ) + return; - Vector vecNearest; - pEnt->CollisionProp()->CalcNearestPoint( GetAbsOrigin(), &vecNearest ); - return CollisionProp()->IsPointInBounds(vecNearest); + m_hRadTouching.AddToTail( pOther ); + if ( GetNextThink() == TICK_NEVER_THINK ) + SetNextThink( gpGlobals->curtime ); +} + +bool CASW_Radiation_Volume::RadTouching( CBaseEntity* pEnt ) +{ + // simply reuse centralized detection + return IsInRadiationVolume( pEnt ); } void CASW_Radiation_Volume::RadHurt(CBaseEntity *pEnt) @@ -90,7 +132,7 @@ void CASW_Radiation_Volume::RadHurt(CBaseEntity *pEnt) int iDamageType = DMG_RADIATION; CBaseEntity *pAttacker = this; - if (m_hCreator.Get() && pEnt->Classify() != CLASS_ASW_MARINE) // don't deal friendly fire damage from rad barrels + if (m_hCreator.Get() && pEnt->Classify() != CLASS_ASW_MARINE) // don't deal friendly fire damage from rad barrels pAttacker = m_hCreator.Get(); CBaseEntity *pWeapon = NULL; diff --git a/src/game/server/swarm/asw_radiation_volume.h b/src/game/server/swarm/asw_radiation_volume.h index 561b92d14..86611b082 100644 --- a/src/game/server/swarm/asw_radiation_volume.h +++ b/src/game/server/swarm/asw_radiation_volume.h @@ -13,6 +13,8 @@ class CASW_Radiation_Volume : public CBaseEntity void RadHurt(CBaseEntity *pEnt); bool RadTouching(CBaseEntity *pEnt); bool IsValidRadTarget( CBaseEntity *pOther ); + // helper that centralizes the collision/volume checks used by RadTouch and RadTouching + bool IsInRadiationVolume( CBaseEntity *pEnt ); DECLARE_DATADESC(); CUtlVector m_hRadTouching;