diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index ac8590c3..c5be5135 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -13515,6 +13515,10 @@ bool CAI_BaseNPC::CineCleanup() } // Clear interaction partner, because we're not running a scripted sequence anymore +#ifdef MAPBASE + // We need the interaction partner for server ragdoll death cleanup, so don't clear if we're not alive + if (IsAlive()) +#endif m_hInteractionPartner = NULL; CleanupForcedInteraction(); } diff --git a/sp/src/game/server/hl2/npc_BaseZombie.cpp b/sp/src/game/server/hl2/npc_BaseZombie.cpp index fee51dd7..4d2447f4 100644 --- a/sp/src/game/server/hl2/npc_BaseZombie.cpp +++ b/sp/src/game/server/hl2/npc_BaseZombie.cpp @@ -2435,6 +2435,20 @@ void CNPC_BaseZombie::RemoveHead( void ) } +//--------------------------------------------------------- +//--------------------------------------------------------- +void CNPC_BaseZombie::SetModel( const char *szModelName ) +{ +#ifdef MAPBASE + // Zombies setting the same model again is a problem when they should maintain their current sequence (e.g. during dynamic interactions) + if ( IsRunningDynamicInteraction() && GetModelIndex() != 0 && FStrEq( szModelName, STRING(GetModelName()) ) ) + return; +#endif + + BaseClass::SetModel( szModelName ); +} + + bool CNPC_BaseZombie::ShouldPlayFootstepMoan( void ) { if( random->RandomInt( 1, zombie_stepfreq.GetInt() * s_iAngryZombies ) == 1 ) diff --git a/sp/src/game/server/hl2/npc_BaseZombie.h b/sp/src/game/server/hl2/npc_BaseZombie.h index 743186de..56a57d94 100644 --- a/sp/src/game/server/hl2/npc_BaseZombie.h +++ b/sp/src/game/server/hl2/npc_BaseZombie.h @@ -186,6 +186,7 @@ public: // Headcrab releasing/breaking apart void RemoveHead( void ); virtual void SetZombieModel( void ) { }; + virtual void SetModel( const char *szModelName ); virtual void BecomeTorso( const Vector &vecTorsoForce, const Vector &vecLegsForce ); virtual bool CanBecomeLiveTorso() { return false; } virtual bool HeadcrabFits( CBaseAnimating *pCrab ); diff --git a/sp/src/game/server/hl2/npc_combine.cpp b/sp/src/game/server/hl2/npc_combine.cpp index 73bac242..df0af9ea 100644 --- a/sp/src/game/server/hl2/npc_combine.cpp +++ b/sp/src/game/server/hl2/npc_combine.cpp @@ -47,6 +47,8 @@ ConVar npc_combine_protected_run( "npc_combine_protected_run", "0", FCVAR_NONE, ConVar npc_combine_altfire_not_allies_only( "npc_combine_altfire_not_allies_only", "1", FCVAR_NONE, "Mapbase: Elites are normally only allowed to fire their alt-fire attack at the player and the player's allies; This allows elites to alt-fire at other enemies too." ); ConVar npc_combine_new_cover_behavior( "npc_combine_new_cover_behavior", "1", FCVAR_NONE, "Mapbase: Toggles small patches for parts of npc_combine AI related to soldiers failing to take cover. These patches are minimal and only change cases where npc_combine would otherwise look at an enemy without shooting or run up to the player to melee attack when they don't have to. Consult the Mapbase wiki for more information." ); + +ConVar npc_combine_fixed_shootpos( "npc_combine_fixed_shootpos", "0", FCVAR_NONE, "Mapbase: Toggles fixed Combine soldier shoot position." ) #endif #define COMBINE_SKIN_DEFAULT 0 @@ -2959,6 +2961,28 @@ Vector CNPC_Combine::Weapon_ShootPosition( ) // FIXME: rename this "estimated" since it's not based on animation // FIXME: the orientation won't be correct when testing from arbitary positions for arbitary angles +#ifdef MAPBASE + // HACKHACK: This weapon shoot position code does not work properly when in close range, causing the aim + // to drift to the left as the enemy gets closer to it. + // This problem is usually bearable for regular combat, but it causes dynamic interaction yaw to be offset + // as well, preventing most from ever being triggered. + // Ideally, this should be fixed from the root cause, but due to the sensitivity of such a change, this is + // currently being tied to a cvar which is off by default. + // + // If the cvar is disabled but the soldier has valid interactions on its current enemy, then a separate hack + // will still attempt to correct the drift as the enemy gets closer. + if ( npc_combine_fixed_shootpos.GetBool() ) + { + right *= 0.0f; + } + else if ( HasValidInteractionsOnCurrentEnemy() ) + { + float flDistSqr = GetEnemy()->WorldSpaceCenter().DistToSqr( WorldSpaceCenter() ); + if (flDistSqr < Square( 128.0f )) + right *= (flDistSqr / Square( 128.0f )); + } +#endif + if ( bStanding ) { if( HasShotgun() ) diff --git a/sp/src/game/server/physics_prop_ragdoll.cpp b/sp/src/game/server/physics_prop_ragdoll.cpp index 93efddc7..cc788fc6 100644 --- a/sp/src/game/server/physics_prop_ragdoll.cpp +++ b/sp/src/game/server/physics_prop_ragdoll.cpp @@ -1557,6 +1557,16 @@ CBaseEntity *CreateServerRagdoll( CBaseAnimating *pAnimating, int forceBone, con pRagdoll->CollisionProp()->SetCollisionBounds( mins, maxs ); #ifdef MAPBASE + // If this was a NPC running a dynamic interaction, disable collisions with the interaction partner + if (pAnimating->IsNPC() /*&& pAnimating->MyNPCPointer()->IsRunningDynamicInteraction()*/) + { + CAI_BaseNPC *pNPC = pAnimating->MyNPCPointer(); + if (pNPC->GetInteractionPartner() && pNPC->GetInteractionPartner()->VPhysicsGetObject()) + { + PhysDisableEntityCollisions( pRagdoll, pNPC->GetInteractionPartner() ); + } + } + variant_t variant; variant.SetEntity(pRagdoll); pAnimating->FireNamedOutput("OnServerRagdoll", variant, pRagdoll, pAnimating);