diff options
Diffstat (limited to 'game/server/portal/trigger_portal_cleanser.cpp')
| -rw-r--r-- | game/server/portal/trigger_portal_cleanser.cpp | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/game/server/portal/trigger_portal_cleanser.cpp b/game/server/portal/trigger_portal_cleanser.cpp new file mode 100644 index 0000000..97fffc3 --- /dev/null +++ b/game/server/portal/trigger_portal_cleanser.cpp @@ -0,0 +1,269 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A volume which bumps portal placement. Keeps a global list loaded in from the map +// and provides an interface with which prop_portal can get this list and avoid successfully +// creating portals partially inside the volume. +// +// $NoKeywords: $ +//======================================================================================// + +#include "cbase.h" +#include "triggers.h" +#include "portal_player.h" +#include "weapon_portalgun.h" +#include "prop_portal_shared.h" +#include "portal_shareddefs.h" +#include "physobj.h" +#include "portal/weapon_physcannon.h" +#include "model_types.h" +#include "rumble_shared.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +static char *g_pszPortalNonCleansable[] = +{ + "func_door", + "func_door_rotating", + "prop_door_rotating", + "func_tracktrain", + "env_ghostanimating", + "physicsshadowclone", + "prop_energy_ball", + NULL, +}; + +//----------------------------------------------------------------------------- +// Purpose: Removes anything that touches it. If the trigger has a targetname, +// firing it will toggle state. +//----------------------------------------------------------------------------- +class CTriggerPortalCleanser : public CBaseTrigger +{ +public: + DECLARE_CLASS( CTriggerPortalCleanser, CBaseTrigger ); + + void Spawn( void ); + void Touch( CBaseEntity *pOther ); + + DECLARE_DATADESC(); + + // Outputs + COutputEvent m_OnDissolve; + COutputEvent m_OnFizzle; + COutputEvent m_OnDissolveBox; +}; + +BEGIN_DATADESC( CTriggerPortalCleanser ) + +// Outputs +DEFINE_OUTPUT( m_OnDissolve, "OnDissolve" ), +DEFINE_OUTPUT( m_OnFizzle, "OnFizzle" ), +DEFINE_OUTPUT( m_OnDissolveBox, "OnDissolveBox" ), + +END_DATADESC() + + +LINK_ENTITY_TO_CLASS( trigger_portal_cleanser, CTriggerPortalCleanser ); + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTriggerPortalCleanser::Spawn( void ) +{ + BaseClass::Spawn(); + InitTrigger(); +} + +// Creates a base entity with model/physics matching the parameter ent. +// Used to avoid higher level functions on a disolving entity, which should be inert +// and not react the way it used to (touches, etc). +// Uses simple physics entities declared in physobj.cpp +CBaseEntity* ConvertToSimpleProp ( CBaseEntity* pEnt ) +{ + CBaseEntity *pRetVal = NULL; + int modelindex = pEnt->GetModelIndex(); + const model_t *model = modelinfo->GetModel( modelindex ); + if ( model && modelinfo->GetModelType(model) == mod_brush ) + { + pRetVal = CreateEntityByName( "simple_physics_brush" ); + } + else + { + pRetVal = CreateEntityByName( "simple_physics_prop" ); + } + + pRetVal->KeyValue( "model", STRING(pEnt->GetModelName()) ); + pRetVal->SetAbsOrigin( pEnt->GetAbsOrigin() ); + pRetVal->SetAbsAngles( pEnt->GetAbsAngles() ); + pRetVal->Spawn(); + pRetVal->VPhysicsInitNormal( SOLID_VPHYSICS, 0, false ); + + return pRetVal; +} + + +void CTriggerPortalCleanser::Touch( CBaseEntity *pOther ) +{ + if ( !PassesTriggerFilters( pOther ) ) + return; + + if ( pOther->IsPlayer() ) + { + CPortal_Player *pPlayer = ToPortalPlayer( pOther ); + + if ( pPlayer ) + { + CWeaponPortalgun *pPortalgun = dynamic_cast<CWeaponPortalgun*>( pPlayer->Weapon_OwnsThisType( "weapon_portalgun" ) ); + + if ( pPortalgun ) + { + bool bFizzledPortal = false; + + if ( pPortalgun->CanFirePortal1() ) + { + CProp_Portal *pPortal = CProp_Portal::FindPortal( pPortalgun->m_iPortalLinkageGroupID, false ); + + if ( pPortal && pPortal->m_bActivated ) + { + pPortal->DoFizzleEffect( PORTAL_FIZZLE_KILLED, false ); + pPortal->Fizzle(); + // HACK HACK! Used to make the gun visually change when going through a cleanser! + pPortalgun->m_fEffectsMaxSize1 = 50.0f; + + bFizzledPortal = true; + } + + // Cancel portals that are still mid flight + if ( pPortal && pPortal->GetNextThink( s_pDelayedPlacementContext ) > gpGlobals->curtime ) + { + pPortal->SetContextThink( NULL, gpGlobals->curtime, s_pDelayedPlacementContext ); + pPortalgun->m_fEffectsMaxSize2 = 50.0f; + bFizzledPortal = true; + } + } + + if ( pPortalgun->CanFirePortal2() ) + { + CProp_Portal *pPortal = CProp_Portal::FindPortal( pPortalgun->m_iPortalLinkageGroupID, true ); + + if ( pPortal && pPortal->m_bActivated ) + { + pPortal->DoFizzleEffect( PORTAL_FIZZLE_KILLED, false ); + pPortal->Fizzle(); + // HACK HACK! Used to make the gun visually change when going through a cleanser! + pPortalgun->m_fEffectsMaxSize2 = 50.0f; + + bFizzledPortal = true; + } + + // Cancel portals that are still mid flight + if ( pPortal && pPortal->GetNextThink( s_pDelayedPlacementContext ) > gpGlobals->curtime ) + { + pPortal->SetContextThink( NULL, gpGlobals->curtime, s_pDelayedPlacementContext ); + pPortalgun->m_fEffectsMaxSize2 = 50.0f; + bFizzledPortal = true; + } + } + + if ( bFizzledPortal ) + { + pPortalgun->SendWeaponAnim( ACT_VM_FIZZLE ); + pPortalgun->SetLastFiredPortal( 0 ); + m_OnFizzle.FireOutput( pOther, this ); + pPlayer->RumbleEffect( RUMBLE_RPG_MISSILE, 0, RUMBLE_FLAG_RESTART ); + } + } + } + + return; + } + + CBaseAnimating *pBaseAnimating = dynamic_cast<CBaseAnimating*>( pOther ); + + if ( pBaseAnimating && !pBaseAnimating->IsDissolving() ) + { + int i = 0; + + while ( g_pszPortalNonCleansable[ i ] ) + { + if ( FClassnameIs( pBaseAnimating, g_pszPortalNonCleansable[ i ] ) ) + { + // Don't dissolve non cleansable objects + return; + } + + ++i; + } + + // The portal weight box, used for puzzles in the portal mod is differentiated by its name + // always being 'box'. We use special logic when the cleanser dissolves a box so this is a special output for it. + if ( pBaseAnimating->NameMatches( "box" ) ) + { + m_OnDissolveBox.FireOutput( pOther, this ); + } + + if ( FClassnameIs( pBaseAnimating, "updateitem2" ) ) + { + pBaseAnimating->EmitSound( "UpdateItem.Fizzle" ); + } + + Vector vOldVel; + AngularImpulse vOldAng; + pBaseAnimating->GetVelocity( &vOldVel, &vOldAng ); + + IPhysicsObject* pOldPhys = pBaseAnimating->VPhysicsGetObject(); + + if ( pOldPhys && ( pOldPhys->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) ) + { + CPortal_Player *pPlayer = (CPortal_Player *)GetPlayerHoldingEntity( pBaseAnimating ); + if( pPlayer ) + { + // Modify the velocity for held objects so it gets away from the player + pPlayer->ForceDropOfCarriedPhysObjects( pBaseAnimating ); + + pPlayer->GetAbsVelocity(); + vOldVel = pPlayer->GetAbsVelocity() + Vector( pPlayer->EyeDirection2D().x * 4.0f, pPlayer->EyeDirection2D().y * 4.0f, -32.0f ); + } + } + + // Swap object with an disolving physics model to avoid touch logic + CBaseEntity *pDisolvingObj = ConvertToSimpleProp( pBaseAnimating ); + if ( pDisolvingObj ) + { + // Remove old prop, transfer name and children to the new simple prop + pDisolvingObj->SetName( pBaseAnimating->GetEntityName() ); + UTIL_TransferPoseParameters( pBaseAnimating, pDisolvingObj ); + TransferChildren( pBaseAnimating, pDisolvingObj ); + pDisolvingObj->SetCollisionGroup( COLLISION_GROUP_INTERACTIVE_DEBRIS ); + pBaseAnimating->AddSolidFlags( FSOLID_NOT_SOLID ); + pBaseAnimating->AddEffects( EF_NODRAW ); + + IPhysicsObject* pPhys = pDisolvingObj->VPhysicsGetObject(); + if ( pPhys ) + { + pPhys->EnableGravity( false ); + + Vector vVel = vOldVel; + AngularImpulse vAng = vOldAng; + + // Disolving hurts, damp and blur the motion a little + vVel *= 0.5f; + vAng.z += 20.0f; + + pPhys->SetVelocity( &vVel, &vAng ); + } + + pBaseAnimating->AddFlag( FL_DISSOLVING ); + UTIL_Remove( pBaseAnimating ); + } + + CBaseAnimating *pDisolvingAnimating = dynamic_cast<CBaseAnimating*>( pDisolvingObj ); + if ( pDisolvingAnimating ) + { + pDisolvingAnimating->Dissolve( "", gpGlobals->curtime, false, ENTITY_DISSOLVE_NORMAL ); + } + + m_OnDissolve.FireOutput( pOther, this ); + } +}
\ No newline at end of file |