summaryrefslogtreecommitdiff
path: root/game/server/portal/trigger_portal_cleanser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/server/portal/trigger_portal_cleanser.cpp')
-rw-r--r--game/server/portal/trigger_portal_cleanser.cpp269
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