From 2858c1d4a04ae3d97fc076f9436b8af9cec8ccf8 Mon Sep 17 00:00:00 2001 From: SuperCake Date: Mon, 31 Aug 2026 05:19:05 +0200 Subject: [PATCH 1/4] feat: add chance and max penetrate to debug overlay --- src/game/shared/swarm/asw_marine_shared.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/game/shared/swarm/asw_marine_shared.cpp b/src/game/shared/swarm/asw_marine_shared.cpp index cc026713b..95ff01cf6 100644 --- a/src/game/shared/swarm/asw_marine_shared.cpp +++ b/src/game/shared/swarm/asw_marine_shared.cpp @@ -1412,6 +1412,12 @@ void CASW_Marine::FirePenetratingBullets( const FireBulletsInfo_t &info, int iMa } } + if ( bShowHitboxes && IsInhabited() && tr.DidHit() ) + { + CFmtStr text( "%.2f %d", fPenetrateChance, iMaxPenetrate ); + NDebugOverlay::Text( tr.endpos, text, false, 4 ); + } + // See if we hit glass if ( tr.m_pEnt != NULL ) { From 953e3ceb3d3ed858e29c4cca21b6e0c8656c405f Mon Sep 17 00:00:00 2001 From: SuperCake Date: Mon, 31 Aug 2026 23:39:55 +0200 Subject: [PATCH 2/4] fix: recalculate trace when it starts in a solid it leaves fix sniper rifle infinite harmless penetration tracer --- src/game/shared/swarm/asw_marine_shared.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/game/shared/swarm/asw_marine_shared.cpp b/src/game/shared/swarm/asw_marine_shared.cpp index 95ff01cf6..4b3d3ac5c 100644 --- a/src/game/shared/swarm/asw_marine_shared.cpp +++ b/src/game/shared/swarm/asw_marine_shared.cpp @@ -1263,6 +1263,21 @@ void CASW_Marine::FirePenetratingBullets( const FireBulletsInfo_t &info, int iMa } VectorNormalize( vecFinalDir ); + // if ( tr.startsolid ) + // Msg( ">> startsolid fraction left:%f full:%f %s\n", tr.fractionleftsolid, tr.fraction, tr.m_pEnt ? tr.m_pEnt->GetClassname() : "" ); + // started trace inside a cursed solid? // Fix sniper rifle world penetration #241 + if ( tr.startsolid && tr.fraction != 0.0f && tr.DidHitWorld() ) + { + // Could calculate new start point here with tr.fractionleftsolid, + // but the code down below already handles next penetration. + // Just prevent bad TraceLine escaping the solid causing seemingly + // infitite tracer with tr.m_Ent = solid it started in. + AI_TraceLine(info.m_vecSrc, info.m_vecSrc, MASK_SHOT, &traceFilter, &tr); + vecEnd = tr.endpos; + } + // else if ( tr.startsolid ) + // Msg( " ... but it was ok I guess\n" ); + #ifdef GAME_DLL if ( ai_debug_shoot_positions.GetBool() ) { @@ -1521,11 +1536,13 @@ void CASW_Marine::FirePenetratingBullets( const FireBulletsInfo_t &info, int iMa int iNextMaxPenetrate = iMaxPenetrate; if ( !tr.DidHitWorld() ) { + // Msg ( "Penetrate %.2f %d entity %s\n", fPenetrateChance, iMaxPenetrate, tr.m_pEnt->GetClassname() ); behindNPCInfo.m_pAdditionalIgnoreEnt = tr.m_pEnt; iNextMaxPenetrate--; } else { + // Msg ( "Penetrate %.2f %d world entity %s\n", fPenetrateChance, iMaxPenetrate, tr.m_pEnt->GetClassname() ); // Penetrate past the solid behindNPCInfo.m_vecSrc = behindNPCInfo.m_vecSrc + behindNPCInfo.m_vecDirShooting * 28.0f; behindNPCInfo.m_pAdditionalIgnoreEnt = NULL; From 65c17e48aad5b5c052dda7b2752566b79795da8a Mon Sep 17 00:00:00 2001 From: SuperCake Date: Tue, 1 Sep 2026 18:36:35 +0200 Subject: [PATCH 3/4] fix: prevent sniper rifle from piercing shielbugs --- src/game/shared/swarm/asw_marine_shared.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/game/shared/swarm/asw_marine_shared.cpp b/src/game/shared/swarm/asw_marine_shared.cpp index 4b3d3ac5c..21a6ba578 100644 --- a/src/game/shared/swarm/asw_marine_shared.cpp +++ b/src/game/shared/swarm/asw_marine_shared.cpp @@ -1465,9 +1465,11 @@ void CASW_Marine::FirePenetratingBullets( const FireBulletsInfo_t &info, int iMa { if ( tr.m_pEnt->Classify() == CLASS_ASW_SHIELDBUG ) // don't let bullets pass through shieldbugs { - bPierce = false; + bool bShieldbugBlocked = false; + bShieldbugBlocked = ( tr.hitgroup == HITGROUP_BONE_SHIELD || tr.hitbox == 1 ); // see CASW_Shieldbug::BlockedDamage + bPierce = !bShieldbugBlocked; // allow piercing vulnerable body parts } - else if ( ( info.m_nFlags & FIRE_BULLETS_NO_PIERCING_SPARK ) == 0 ) + if ( bPierce && !( info.m_nFlags & FIRE_BULLETS_NO_PIERCING_SPARK ) ) { CEffectData data; data.m_vOrigin = tr.endpos; @@ -1483,7 +1485,8 @@ void CASW_Marine::FirePenetratingBullets( const FireBulletsInfo_t &info, int iMa } } - if ( ( tr.m_pEnt != NULL ) && fPenetrateChance > 1.0f ) + if ( ( tr.m_pEnt != NULL ) && fPenetrateChance > 1.0f && + ( tr.m_pEnt->Classify() != CLASS_ASW_SHIELDBUG || bPierce ) ) { // We can only penetrate a few walls fPenetrateChance -= 1.0f; From e70c29475c179ce87514d610ada12ac1f71180ed Mon Sep 17 00:00:00 2001 From: SuperCake Date: Wed, 2 Sep 2026 12:38:12 +0200 Subject: [PATCH 4/4] feat: add convars for piercing shieldbugs --- src/game/shared/swarm/asw_marine_shared.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/game/shared/swarm/asw_marine_shared.cpp b/src/game/shared/swarm/asw_marine_shared.cpp index 21a6ba578..0a60b1ce1 100644 --- a/src/game/shared/swarm/asw_marine_shared.cpp +++ b/src/game/shared/swarm/asw_marine_shared.cpp @@ -92,6 +92,9 @@ ConVar rd_difficulty_tier( "rd_difficulty_tier", "0", FCVAR_REPLICATED | FCVAR_C ConVar sv_showimpacts( "sv_showimpacts", "0", FCVAR_REPLICATED, "Shows client (red) and server (blue) bullet impact point (1=both, 2=client-only, 3=server-only)" ); ConVar rd_shoot_from_face( "rd_shoot_from_face", "1", FCVAR_REPLICATED | FCVAR_CHEAT, "In first person, the gun fires out of our eyes instead of from where the gun is being held." ); +ConVar rd_shieldbug_pierce( "rd_shieldbug_pierce", "0", FCVAR_REPLICATED | FCVAR_CHEAT, "Penetration force needed to pierce the Shieldbug's shield. \"0\" for no piercing." ); +ConVar rd_shieldbug_pierce_wall( "rd_shieldbug_pierce_wall", "1", FCVAR_REPLICATED | FCVAR_CHEAT, "Only allow piercing Shieldbug's shield (asw_shieldbug_pierce) when the bullet can pierce a wall." ); + #ifdef GAME_DLL extern ConVar ai_show_hull_attacks; ConVar asw_melee_knockback_up_force( "asw_melee_knockback_up_force", "1.0", FCVAR_CHEAT ); @@ -1455,6 +1458,7 @@ void CASW_Marine::FirePenetratingBullets( const FireBulletsInfo_t &info, int iMa fDiceRoll = RandomFloat( 0.0f, 1.0f ); } + bool bShieldbugBlocked = false; bool bPierce = ( tr.m_pEnt != NULL ) && ( fDiceRoll < fPenetrateChance) && !bHitGlass && !tr.DidHitWorld(); if (bPierce) { @@ -1465,9 +1469,19 @@ void CASW_Marine::FirePenetratingBullets( const FireBulletsInfo_t &info, int iMa { if ( tr.m_pEnt->Classify() == CLASS_ASW_SHIELDBUG ) // don't let bullets pass through shieldbugs { - bool bShieldbugBlocked = false; bShieldbugBlocked = ( tr.hitgroup == HITGROUP_BONE_SHIELD || tr.hitbox == 1 ); // see CASW_Shieldbug::BlockedDamage bPierce = !bShieldbugBlocked; // allow piercing vulnerable body parts + + if ( bShieldbugBlocked + && rd_shieldbug_pierce.GetInt() > 0 + && iMaxPenetrate >= rd_shieldbug_pierce.GetInt() + && ( !rd_shieldbug_pierce_wall.GetBool() || fPenetrateChance > 1.0f ) + ) + { + bPierce = true; + // shields are tougher than flesh, so the bullet should lose more force + iMaxPenetrate -= rd_shieldbug_pierce.GetInt() - 1; // "-1": keep extra penetration for flashy tracer effect + } } if ( bPierce && !( info.m_nFlags & FIRE_BULLETS_NO_PIERCING_SPARK ) ) { @@ -1537,7 +1551,7 @@ void CASW_Marine::FirePenetratingBullets( const FireBulletsInfo_t &info, int iMa } int iNextMaxPenetrate = iMaxPenetrate; - if ( !tr.DidHitWorld() ) + if ( !tr.DidHitWorld() && !bShieldbugBlocked ) { // Msg ( "Penetrate %.2f %d entity %s\n", fPenetrateChance, iMaxPenetrate, tr.m_pEnt->GetClassname() ); behindNPCInfo.m_pAdditionalIgnoreEnt = tr.m_pEnt;