diff --git a/src/game/client/weapon_selection.cpp b/src/game/client/weapon_selection.cpp index 45334fcdc..835b4add1 100644 --- a/src/game/client/weapon_selection.cpp +++ b/src/game/client/weapon_selection.cpp @@ -400,6 +400,38 @@ void CBaseHudWeaponSelection::UserCmd_Slot10(void) SelectSlot( 10 ); } +void ClientInstantPhysSwap() +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + C_BaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon(); + if ( !pWeapon ) + return; + + const char *strWeaponName = pWeapon->GetName(); + + if ( !Q_stricmp( strWeaponName, "weapon_physcannon" ) ) + { + input->MakeWeaponSelection( pPlayer->GetLastWeapon() ); // back to previous weapon + } + else + { + for ( int i = 0; i < pPlayer->WeaponCount(); ++i ) + { + C_BaseCombatWeapon *pWeapon = pPlayer->GetWeapon( i ); + if ( pWeapon && !Q_stricmp( pWeapon->GetClassname(), "weapon_physcannon" ) ) // switch to physcannon + { + input->MakeWeaponSelection( pWeapon ); + return; + } + } + } +} + +static ConCommand cl_physswap( "phys_swap", ClientInstantPhysSwap, "Client-predicted physcannon swap for low-latency switching." ); + //----------------------------------------------------------------------------- // Purpose: returns true if the CHudMenu should take slot1, etc commands //----------------------------------------------------------------------------- diff --git a/src/game/server/basecombatweapon.cpp b/src/game/server/basecombatweapon.cpp index 29d347104..db1d23093 100644 --- a/src/game/server/basecombatweapon.cpp +++ b/src/game/server/basecombatweapon.cpp @@ -242,6 +242,7 @@ CBaseEntity* CBaseCombatWeapon::Respawn( void ) { pNewWeapon->AddEffects( EF_NODRAW );// invisible for now pNewWeapon->SetTouch( NULL );// no touch + pNewWeapon->AddEFlags( EFL_NO_PHYSCANNON_INTERACTION ); pNewWeapon->SetThink( &CBaseCombatWeapon::AttemptToMaterialize ); UTIL_DropToFloor( this, MASK_SOLID ); @@ -641,6 +642,7 @@ void CBaseCombatWeapon::AttemptToMaterialize( void ) if ( time == 0 ) { Materialize(); + RemoveEFlags( EFL_NO_PHYSCANNON_INTERACTION ); return; } diff --git a/src/game/server/bmodels.cpp b/src/game/server/bmodels.cpp index 3fa00f205..c64915233 100644 --- a/src/game/server/bmodels.cpp +++ b/src/game/server/bmodels.cpp @@ -1446,7 +1446,7 @@ bool CFuncVPhysicsClip::EntityPassesFilter( CBaseEntity *pOther ) if ( pFilter ) return pFilter->PassesFilter( this, pOther ); - if ( pOther->GetMoveType() == MOVETYPE_VPHYSICS && pOther->VPhysicsGetObject()->IsMoveable() ) + if ( pOther->GetMoveType() == MOVETYPE_VPHYSICS && pOther->VPhysicsGetObject() && pOther->VPhysicsGetObject()->IsMoveable() ) return true; return false; diff --git a/src/game/server/client.cpp b/src/game/server/client.cpp index ae1840256..72810c110 100644 --- a/src/game/server/client.cpp +++ b/src/game/server/client.cpp @@ -1045,16 +1045,13 @@ static ConCommand test_dispatcheffect("test_dispatcheffect", CC_Player_TestDispa void CC_Player_PhysSwap( void ) { CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() ); - + if ( pPlayer ) { CBaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon(); if ( pWeapon ) { - // Tell the client to stop selecting weapons - engine->ClientCommand( UTIL_GetCommandClient()->edict(), "cancelselect" ); - const char *strWeaponName = pWeapon->GetName(); if ( !Q_stricmp( strWeaponName, "weapon_physcannon" ) ) @@ -1069,7 +1066,7 @@ void CC_Player_PhysSwap( void ) } } } -static ConCommand physswap("phys_swap", CC_Player_PhysSwap, "Automatically swaps the current weapon for the physcannon and back again." ); +static ConCommand physswap( "phys_swap", CC_Player_PhysSwap, "Automatically swaps the current weapon for the physcannon and back again." ); #endif //----------------------------------------------------------------------------- diff --git a/src/game/server/gameinterface.cpp b/src/game/server/gameinterface.cpp index eb99cdf4c..1937a5cd7 100644 --- a/src/game/server/gameinterface.cpp +++ b/src/game/server/gameinterface.cpp @@ -90,6 +90,7 @@ #include "serverbenchmark_base.h" #include "querycache.h" #include "player_voice_listener.h" +#include "hl2mp/weapon_physcannon.h" #ifdef TF_DLL #include "gc_clientsystem.h" @@ -2766,6 +2767,21 @@ void CServerGameClients::ClientDisconnect( edict_t *pEdict ) CBasePlayer *player = ( CBasePlayer * )CBaseEntity::Instance( pEdict ); if ( player ) { + CBaseCombatWeapon *pWeapon = player->GetActiveWeapon(); + + if ( pWeapon && !pWeapon->Holster() ) + { + CWeaponPhysCannon *physcannon = dynamic_cast< CWeaponPhysCannon * >( pWeapon ); + + if ( physcannon ) + { + physcannon->KillUsage(); + physcannon->Delete(); + } + } + else + player->ForceDropOfCarriedPhysObjects( NULL ); + if ( !g_fGameOver ) { player->SetMaxSpeed( 0.0f ); diff --git a/src/game/server/hl2/hl2_player.cpp b/src/game/server/hl2/hl2_player.cpp index 7b2d595e4..e9bad5f9b 100644 --- a/src/game/server/hl2/hl2_player.cpp +++ b/src/game/server/hl2/hl2_player.cpp @@ -3213,10 +3213,11 @@ void CHL2_Player::ForceDropOfCarriedPhysObjects( CBaseEntity *pOnlyIfHoldingThis #endif // Drop any objects being handheld. - ClearUseEntity(); + if ( pOnlyIfHoldingThis == NULL || pOnlyIfHoldingThis == GetUseEntity() ) + ClearUseEntity(); // Then force the physcannon to drop anything it's holding, if it's our active weapon - PhysCannonForceDrop( GetActiveWeapon(), NULL ); + PhysCannonForceDrop( GetActiveWeapon(), pOnlyIfHoldingThis ); } void CHL2_Player::InputForceDropPhysObjects( inputdata_t &data ) diff --git a/src/game/server/hl2mp/hl2mp_player.cpp b/src/game/server/hl2mp/hl2mp_player.cpp index 9457928a0..b28a9b6ee 100644 --- a/src/game/server/hl2mp/hl2mp_player.cpp +++ b/src/game/server/hl2mp/hl2mp_player.cpp @@ -22,12 +22,13 @@ #include "gamestats.h" #include "ammodef.h" #include "NextBot.h" - #include "engine/IEngineSound.h" #include "SoundEmitterSystem/isoundemittersystembase.h" #include "ilagcompensationmanager.h" +#include "hl2mp/weapon_physcannon.h" + int g_iLastCitizenModel = 0; int g_iLastCombineModel = 0; @@ -984,6 +985,24 @@ void CHL2MP_Player::ChangeTeam( int iTeam ) BaseClass::ChangeTeam( iTeam ); + if ( iTeam == TEAM_SPECTATOR ) + { + CBaseCombatWeapon *pWeapon = GetActiveWeapon(); + + if ( pWeapon && !pWeapon->Holster() ) + { + CWeaponPhysCannon *physcannon = dynamic_cast< CWeaponPhysCannon * >( pWeapon ); + + if ( physcannon ) + { + physcannon->KillUsage(); + physcannon->Delete(); + } + } + else + ForceDropOfCarriedPhysObjects( NULL ); + } + m_flNextTeamChangeTime = gpGlobals->curtime + TEAM_CHANGE_INTERVAL; if ( HL2MPRules()->IsTeamplay() == true ) diff --git a/src/game/server/item_world.cpp b/src/game/server/item_world.cpp index ec1a63dbe..9fe8e1781 100644 --- a/src/game/server/item_world.cpp +++ b/src/game/server/item_world.cpp @@ -500,6 +500,7 @@ CBaseEntity* CItem::Respawn( void ) { SetTouch( NULL ); AddEffects( EF_NODRAW ); + AddEFlags( EFL_NO_PHYSCANNON_INTERACTION ); VPhysicsDestroyObject(); diff --git a/src/game/server/physics.cpp b/src/game/server/physics.cpp index 279fd507d..8a335d1e4 100644 --- a/src/game/server/physics.cpp +++ b/src/game/server/physics.cpp @@ -2291,6 +2291,9 @@ void CCollisionEvent::AddDamageEvent( CBaseEntity *pEntity, const CTakeDamageInf if ( pEntity->IsMarkedForDeletion() ) return; + if ( !pEntity->VPhysicsGetObject() ) + return; + int iTimeBasedDamage = g_pGameRules->Damage_GetTimeBased(); if ( !( info.GetDamageType() & (DMG_BURN | DMG_DROWN | iTimeBasedDamage | DMG_PREVENT_PHYSICS_FORCE) ) ) { diff --git a/src/game/server/physobj.cpp b/src/game/server/physobj.cpp index efaffd075..74a1cee52 100644 --- a/src/game/server/physobj.cpp +++ b/src/game/server/physobj.cpp @@ -633,7 +633,8 @@ int CPhysBox::DrawDebugTextOverlays(void) //----------------------------------------------------------------------------- void CPhysBox::InputWake( inputdata_t &inputdata ) { - VPhysicsGetObject()->Wake(); + if ( VPhysicsGetObject() != NULL ) + VPhysicsGetObject()->Wake(); } //----------------------------------------------------------------------------- @@ -642,7 +643,8 @@ void CPhysBox::InputWake( inputdata_t &inputdata ) //----------------------------------------------------------------------------- void CPhysBox::InputSleep( inputdata_t &inputdata ) { - VPhysicsGetObject()->Sleep(); + if ( VPhysicsGetObject() != NULL ) + VPhysicsGetObject()->Sleep(); } //----------------------------------------------------------------------------- @@ -705,7 +707,8 @@ void CPhysBox::InputForceDrop( inputdata_t &inputdata ) //----------------------------------------------------------------------------- void CPhysBox::Move( const Vector &direction ) { - VPhysicsGetObject()->ApplyForceCenter( direction ); + if ( VPhysicsGetObject() ) + VPhysicsGetObject()->ApplyForceCenter( direction ); } // Update the visible representation of the physic system's representation of this object diff --git a/src/game/server/props.cpp b/src/game/server/props.cpp index dec14e42d..e3c0c61db 100644 --- a/src/game/server/props.cpp +++ b/src/game/server/props.cpp @@ -2742,6 +2742,13 @@ void CPhysicsProp::OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t r } } + if ( pPhysicsObject && ( pPhysicsObject->GetGameFlags() & FVPHYSICS_WAS_THROWN ) ) + { + PhysClearGameFlags( pPhysicsObject, FVPHYSICS_WAS_THROWN ); + } + + m_bFirstCollisionAfterLaunch = false; + m_OnPhysGunPickup.FireOutput( pPhysGunUser, this ); if( reason == PICKED_UP_BY_CANNON ) diff --git a/src/game/shared/hl2mp/weapon_physcannon.cpp b/src/game/shared/hl2mp/weapon_physcannon.cpp index 26fdfefdb..67f9252ba 100644 --- a/src/game/shared/hl2mp/weapon_physcannon.cpp +++ b/src/game/shared/hl2mp/weapon_physcannon.cpp @@ -792,6 +792,12 @@ void CPlayerPickupController::Use( CBaseEntity *pActivator, CBaseEntity *pCaller //Adrian: Oops, our object became motion disabled, let go! IPhysicsObject *pPhys = pAttached->VPhysicsGetObject(); + if ( !pPhys ) + { + Shutdown(); + return; + } + if ( pPhys && pPhys->IsMoveable() == false ) { Shutdown(); @@ -808,7 +814,7 @@ void CPlayerPickupController::Use( CBaseEntity *pActivator, CBaseEntity *pCaller } #endif // +ATTACK will throw phys objects - if ( m_pPlayer->m_nButtons & IN_ATTACK ) + if ( pPhys && m_pPlayer->m_nButtons & IN_ATTACK ) { Shutdown( true ); Vector vecLaunch; @@ -1127,15 +1133,15 @@ void CWeaponPhysCannon::Drop( const Vector &vecVelocity ) { ForceDrop(); -#ifndef CLIENT_DLL - UTIL_Remove( this ); +#ifdef GAME_DLL + Delete(); #endif } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -bool CWeaponPhysCannon::CanHolster( void ) +bool CWeaponPhysCannon::CanHolster( void ) const { //Don't holster this weapon if we're holding onto something if ( m_bActive ) @@ -2006,20 +2012,13 @@ void CWeaponPhysCannon::DetachObject( bool playSound, bool wasLaunched ) if ( m_bActive == false ) return; - CHL2MP_Player *pOwner = (CHL2MP_Player *)ToBasePlayer( GetOwner() ); - if( pOwner != NULL ) - { - pOwner->EnableSprint( true ); - pOwner->SetMaxSpeed( hl2_normspeed.GetFloat() ); - } - CBaseEntity *pObject = m_grabController.GetAttached(); m_grabController.DetachEntity( wasLaunched ); if ( pObject != NULL ) { - Pickup_OnPhysGunDrop( pObject, pOwner, wasLaunched ? LAUNCHED_BY_CANNON : DROPPED_BY_CANNON ); + Pickup_OnPhysGunDrop( pObject, GetPlayerOwner(), wasLaunched ? LAUNCHED_BY_CANNON : DROPPED_BY_CANNON ); } if ( pObject && m_bResetOwnerEntity == true ) @@ -2337,7 +2336,7 @@ void CWeaponPhysCannon::ItemPostFrame() } } - if (( pOwner->m_nButtons & IN_ATTACK2 ) == 0 ) + if ( ( pOwner->m_nButtons & IN_ATTACK2 ) == 0 && CanPerformSecondaryAttack() ) { m_nAttack2Debounce = 0; } diff --git a/src/game/shared/hl2mp/weapon_physcannon.h b/src/game/shared/hl2mp/weapon_physcannon.h index 9b45d9d15..517be6c25 100644 --- a/src/game/shared/hl2mp/weapon_physcannon.h +++ b/src/game/shared/hl2mp/weapon_physcannon.h @@ -286,7 +286,7 @@ public: bool DropIfEntityHeld( CBaseEntity *pTarget ); // Drops its held entity if it matches the entity passed in CGrabController &GetGrabController() { return m_grabController; } - bool CanHolster( void ); + bool CanHolster( void ) const; bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); bool Deploy( void ); @@ -294,6 +294,12 @@ public: virtual void SetViewModel( void ); virtual const char *GetShootSound( int iIndex ) const; + + void KillUsage() + { + ForceDrop(); + DestroyEffects(); + } #ifndef CLIENT_DLL CNetworkQAngle ( m_attachedAnglesPlayerSpace );