add hl1,portal,dod source code

This commit is contained in:
nillerusr
2022-04-16 12:05:19 +03:00
parent bc6873014e
commit 23a370d9bb
524 changed files with 174173 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+481
View File
@@ -0,0 +1,481 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Provides structures and classes necessary to simulate a portal.
//
// $NoKeywords: $
//=====================================================================================//
#ifndef PORTALSIMULATION_H
#define PORTALSIMULATION_H
#ifdef _WIN32
#pragma once
#endif
#include "mathlib/polyhedron.h"
#include "const.h"
#include "tier1/utlmap.h"
#include "tier1/utlvector.h"
#define PORTAL_SIMULATORS_EMBED_GUID //define this to embed a unique integer with each portal simulator for debugging purposes
struct StaticPropPolyhedronGroups_t //each static prop is made up of a group of polyhedrons, these help us pull those groups from an array
{
int iStartIndex;
int iNumPolyhedrons;
};
enum PortalSimulationEntityFlags_t
{
PSEF_OWNS_ENTITY = (1 << 0), //this environment is responsible for the entity's physics objects
PSEF_OWNS_PHYSICS = (1 << 1),
PSEF_IS_IN_PORTAL_HOLE = (1 << 2), //updated per-phyframe
PSEF_CLONES_ENTITY_FROM_MAIN = (1 << 3), //entity is close enough to the portal to affect objects intersecting the portal
//PSEF_HAS_LINKED_CLONE = (1 << 1), //this environment has a clone of the entity which is transformed from its linked portal
};
enum PS_PhysicsObjectSourceType_t
{
PSPOST_LOCAL_BRUSHES,
PSPOST_REMOTE_BRUSHES,
PSPOST_LOCAL_STATICPROPS,
PSPOST_REMOTE_STATICPROPS,
PSPOST_HOLYWALL_TUBE
};
struct PortalTransformAsAngledPosition_t //a matrix transformation from this portal to the linked portal, stored as vector and angle transforms
{
Vector ptOriginTransform;
QAngle qAngleTransform;
};
inline bool LessFunc_Integer( const int &a, const int &b ) { return a < b; };
class CPortalSimulatorEventCallbacks //sends out notifications of events to game specific code
{
public:
virtual void PortalSimulator_TookOwnershipOfEntity( CBaseEntity *pEntity ) { };
virtual void PortalSimulator_ReleasedOwnershipOfEntity( CBaseEntity *pEntity ) { };
virtual void PortalSimulator_TookPhysicsOwnershipOfEntity( CBaseEntity *pEntity ) { };
virtual void PortalSimulator_ReleasedPhysicsOwnershipOfEntity( CBaseEntity *pEntity ) { };
};
//====================================================================================
// To any coder trying to understand the following nested structures....
//
// You may be wondering... why? wtf?
//
// The answer. The previous incarnation of server side portal simulation suffered
// terribly from evolving variables with increasingly cryptic names with no clear
// definition of what part of the system the variable was involved with.
//
// It's my hope that a nested structure with clear boundaries will eliminate that
// horrible, awful, nasty, frustrating confusion. (It was really really bad). This
// system has the added benefit of pseudo-forcing a naming structure.
//
// Lastly, if it all roots in one struct, we can const reference it out to allow
// easy reads without writes
//
// It's broken out like this to solve a few problems....
// 1. It cleans up intellisense when you don't actually define a structure
// within a structure.
// 2. Shorter typenames when you want to have a pointer/reference deep within
// the nested structure.
// 3. Needed at least one level removed from CPortalSimulator so
// pointers/references could be made while the primary instance of the
// data was private/protected.
//
// It may be slightly difficult to understand in it's broken out structure, but
// intellisense brings all the data together in a very cohesive manner for
// working with.
//====================================================================================
struct PS_PlacementData_t //stuff useful for geometric operations
{
Vector ptCenter;
QAngle qAngles;
Vector vForward;
Vector vUp;
Vector vRight;
VPlane PortalPlane;
VMatrix matThisToLinked;
VMatrix matLinkedToThis;
PortalTransformAsAngledPosition_t ptaap_ThisToLinked;
PortalTransformAsAngledPosition_t ptaap_LinkedToThis;
CPhysCollide *pHoleShapeCollideable; //used to test if a collideable is in the hole, should NOT be collided against in general
PS_PlacementData_t( void )
{
memset( this, 0, sizeof( PS_PlacementData_t ) );
}
};
struct PS_SD_Static_World_Brushes_t
{
CUtlVector<CPolyhedron *> Polyhedrons; //the building blocks of more complex collision
CPhysCollide *pCollideable;
#ifndef CLIENT_DLL
IPhysicsObject *pPhysicsObject;
PS_SD_Static_World_Brushes_t() : pCollideable(NULL), pPhysicsObject(NULL) {};
#else
PS_SD_Static_World_Brushes_t() : pCollideable(NULL) {};
#endif
};
struct PS_SD_Static_World_StaticProps_ClippedProp_t
{
StaticPropPolyhedronGroups_t PolyhedronGroup;
CPhysCollide * pCollide;
#ifndef CLIENT_DLL
IPhysicsObject * pPhysicsObject;
#endif
IHandleEntity * pSourceProp;
int iTraceContents;
short iTraceSurfaceProps;
static CBaseEntity * pTraceEntity;
static const char * szTraceSurfaceName; //same for all static props, here just for easy reference
static const int iTraceSurfaceFlags; //same for all static props, here just for easy reference
};
struct PS_SD_Static_World_StaticProps_t
{
CUtlVector<CPolyhedron *> Polyhedrons; //the building blocks of more complex collision
CUtlVector<PS_SD_Static_World_StaticProps_ClippedProp_t> ClippedRepresentations;
bool bCollisionExists; //the shortcut to know if collideables exist for each prop
bool bPhysicsExists; //the shortcut to know if physics obects exist for each prop
PS_SD_Static_World_StaticProps_t( void ) : bCollisionExists( false ), bPhysicsExists( false ) { };
};
struct PS_SD_Static_World_t //stuff in front of the portal
{
PS_SD_Static_World_Brushes_t Brushes;
PS_SD_Static_World_StaticProps_t StaticProps;
};
struct PS_SD_Static_Wall_Local_Tube_t //a minimal tube, an object must fit inside this to be eligible for portaling
{
CUtlVector<CPolyhedron *> Polyhedrons; //the building blocks of more complex collision
CPhysCollide *pCollideable;
#ifndef CLIENT_DLL
IPhysicsObject *pPhysicsObject;
PS_SD_Static_Wall_Local_Tube_t() : pCollideable(NULL), pPhysicsObject(NULL) {};
#else
PS_SD_Static_Wall_Local_Tube_t() : pCollideable(NULL) {};
#endif
};
struct PS_SD_Static_Wall_Local_Brushes_t
{
CUtlVector<CPolyhedron *> Polyhedrons; //the building blocks of more complex collision
CPhysCollide *pCollideable;
#ifndef CLIENT_DLL
IPhysicsObject *pPhysicsObject;
PS_SD_Static_Wall_Local_Brushes_t() : pCollideable(NULL), pPhysicsObject(NULL) {};
#else
PS_SD_Static_Wall_Local_Brushes_t() : pCollideable(NULL) {};
#endif
};
struct PS_SD_Static_Wall_Local_t //things in the wall that are completely independant of having a linked portal
{
PS_SD_Static_Wall_Local_Tube_t Tube;
PS_SD_Static_Wall_Local_Brushes_t Brushes;
};
struct PS_SD_Static_Wall_RemoteTransformedToLocal_Brushes_t
{
IPhysicsObject *pPhysicsObject;
PS_SD_Static_Wall_RemoteTransformedToLocal_Brushes_t() : pPhysicsObject(NULL) {};
};
struct PS_SD_Static_Wall_RemoteTransformedToLocal_StaticProps_t
{
CUtlVector<IPhysicsObject *> PhysicsObjects;
};
struct PS_SD_Static_Wall_RemoteTransformedToLocal_t //things taken from the linked portal's "World" collision and transformed into local space
{
PS_SD_Static_Wall_RemoteTransformedToLocal_Brushes_t Brushes;
PS_SD_Static_Wall_RemoteTransformedToLocal_StaticProps_t StaticProps;
};
struct PS_SD_Static_Wall_t //stuff behind the portal
{
PS_SD_Static_Wall_Local_t Local;
#ifndef CLIENT_DLL
PS_SD_Static_Wall_RemoteTransformedToLocal_t RemoteTransformedToLocal;
#endif
};
struct PS_SD_Static_SurfaceProperties_t //surface properties to pretend every collideable here is using
{
int contents;
csurface_t surface;
CBaseEntity *pEntity;
};
struct PS_SD_Static_t //stuff that doesn't move around
{
PS_SD_Static_World_t World;
PS_SD_Static_Wall_t Wall;
PS_SD_Static_SurfaceProperties_t SurfaceProperties;
};
class CPhysicsShadowClone;
struct PS_SD_Dynamic_PhysicsShadowClones_t
{
CUtlVector<CBaseEntity *> ShouldCloneFromMain; //a list of entities that should be cloned from main if physics simulation is enabled
//in single-environment mode, this helps us track who should collide with who
CUtlVector<CPhysicsShadowClone *> FromLinkedPortal;
};
struct PS_SD_Dynamic_t //stuff that moves around
{
unsigned int EntFlags[MAX_EDICTS]; //flags maintained for every entity in the world based on its index
PS_SD_Dynamic_PhysicsShadowClones_t ShadowClones;
CUtlVector<CBaseEntity *> OwnedEntities;
PS_SD_Dynamic_t()
{
memset( EntFlags, 0, sizeof( EntFlags ) );
}
};
class CPSCollisionEntity;
struct PS_SimulationData_t //compartmentalized data for coherent management
{
PS_SD_Static_t Static;
#ifndef CLIENT_DLL
PS_SD_Dynamic_t Dynamic;
IPhysicsEnvironment *pPhysicsEnvironment;
CPSCollisionEntity *pCollisionEntity; //the entity we'll be tying physics objects to for collision
PS_SimulationData_t() : pPhysicsEnvironment(NULL), pCollisionEntity(NULL) {};
#endif
};
struct PS_InternalData_t
{
PS_PlacementData_t Placement;
PS_SimulationData_t Simulation;
};
class CPortalSimulator
{
public:
CPortalSimulator( void );
~CPortalSimulator( void );
void MoveTo( const Vector &ptCenter, const QAngle &angles );
void ClearEverything( void );
void AttachTo( CPortalSimulator *pLinkedPortalSimulator );
void DetachFromLinked( void ); //detach portals to sever the connection, saves work when planning on moving both portals
CPortalSimulator *GetLinkedPortalSimulator( void ) const;
void SetPortalSimulatorCallbacks( CPortalSimulatorEventCallbacks *pCallbacks );
bool IsReadyToSimulate( void ) const; //is active and linked to another portal
void SetCollisionGenerationEnabled( bool bEnabled ); //enable/disable collision generation for the hole in the wall, needed for proper vphysics simulation
bool IsCollisionGenerationEnabled( void ) const;
void SetVPhysicsSimulationEnabled( bool bEnabled ); //enable/disable vphysics simulation. Will automatically update the linked portal to be the same
bool IsSimulatingVPhysics( void ) const; //this portal is setup to handle any physically simulated object, false means the portal is handling player movement only
bool EntityIsInPortalHole( CBaseEntity *pEntity ) const; //true if the entity is within the portal cutout bounds and crossing the plane. Not just *near* the portal
bool EntityHitBoxExtentIsInPortalHole( CBaseAnimating *pBaseAnimating ) const; //true if the entity is within the portal cutout bounds and crossing the plane. Not just *near* the portal
void RemoveEntityFromPortalHole( CBaseEntity *pEntity ); //if the entity is in the portal hole, this forcibly moves it out by any means possible
bool RayIsInPortalHole( const Ray_t &ray ) const; //traces a ray against the same detector for EntityIsInPortalHole(), bias is towards false positives
#ifndef CLIENT_DLL
int GetMoveableOwnedEntities( CBaseEntity **pEntsOut, int iEntOutLimit ); //gets owned entities that aren't either world or static props. Excludes fake portal ents such as physics clones
static CPortalSimulator *GetSimulatorThatOwnsEntity( const CBaseEntity *pEntity ); //fairly cheap to call
static CPortalSimulator *GetSimulatorThatCreatedPhysicsObject( const IPhysicsObject *pObject, PS_PhysicsObjectSourceType_t *pOut_SourceType = NULL );
static void Pre_UTIL_Remove( CBaseEntity *pEntity );
static void Post_UTIL_Remove( CBaseEntity *pEntity );
//these three really should be made internal and the public interface changed to a "watch this entity" setup
void TakeOwnershipOfEntity( CBaseEntity *pEntity ); //general ownership, not necessarily physics ownership
void ReleaseOwnershipOfEntity( CBaseEntity *pEntity, bool bMovingToLinkedSimulator = false ); //if bMovingToLinkedSimulator is true, the code skips some steps that are going to be repeated when the entity is added to the other simulator
void ReleaseAllEntityOwnership( void ); //go back to not owning any entities
//void TeleportEntityToLinkedPortal( CBaseEntity *pEntity );
void StartCloningEntity( CBaseEntity *pEntity );
void StopCloningEntity( CBaseEntity *pEntity );
bool OwnsEntity( const CBaseEntity *pEntity ) const;
bool OwnsPhysicsForEntity( const CBaseEntity *pEntity ) const;
bool CreatedPhysicsObject( const IPhysicsObject *pObject, PS_PhysicsObjectSourceType_t *pOut_SourceType = NULL ) const; //true if the physics object was generated by this portal simulator
static void PrePhysFrame( void );
static void PostPhysFrame( void );
#endif //#ifndef CLIENT_DLL
#ifdef PORTAL_SIMULATORS_EMBED_GUID
int GetPortalSimulatorGUID( void ) const { return m_iPortalSimulatorGUID; };
#endif
protected:
bool m_bLocalDataIsReady; //this side of the portal is properly setup, no guarantees as to linkage to another portal
bool m_bSimulateVPhysics;
bool m_bGenerateCollision;
bool m_bSharedCollisionConfiguration; //when portals are in certain configurations, they need to cross-clip and share some collision data and things get nasty. For the love of all that is holy, pray that this is false.
CPortalSimulator *m_pLinkedPortal;
bool m_bInCrossLinkedFunction; //A flag to mark that we're already in a linked function and that the linked portal shouldn't call our side
CPortalSimulatorEventCallbacks *m_pCallbacks;
#ifdef PORTAL_SIMULATORS_EMBED_GUID
int m_iPortalSimulatorGUID;
#endif
struct
{
bool bPolyhedronsGenerated;
bool bLocalCollisionGenerated;
bool bLinkedCollisionGenerated;
bool bLocalPhysicsGenerated;
bool bLinkedPhysicsGenerated;
} m_CreationChecklist;
friend class CPSCollisionEntity;
#ifndef CLIENT_DLL //physics handled purely by server side
void TakePhysicsOwnership( CBaseEntity *pEntity );
void ReleasePhysicsOwnership( CBaseEntity *pEntity, bool bContinuePhysicsCloning = true, bool bMovingToLinkedSimulator = false );
void CreateAllPhysics( void );
void CreateMinimumPhysics( void ); //stuff needed by any part of physics simulations
void CreateLocalPhysics( void );
void CreateLinkedPhysics( void );
void ClearAllPhysics( void );
void ClearMinimumPhysics( void );
void ClearLocalPhysics( void );
void ClearLinkedPhysics( void );
void ClearLinkedEntities( void ); //gets rid of transformed shadow clones
#endif
void CreateAllCollision( void );
void CreateLocalCollision( void );
void CreateLinkedCollision( void );
void ClearAllCollision( void );
void ClearLinkedCollision( void );
void ClearLocalCollision( void );
void CreatePolyhedrons( void ); //carves up the world around the portal's position into sets of polyhedrons
void ClearPolyhedrons( void );
void UpdateLinkMatrix( void );
void MarkAsOwned( CBaseEntity *pEntity );
void MarkAsReleased( CBaseEntity *pEntity );
PS_InternalData_t m_InternalData;
public:
const PS_InternalData_t &m_DataAccess;
friend class CPS_AutoGameSys_EntityListener;
};
extern CUtlVector<CPortalSimulator *> const &g_PortalSimulators;
#ifndef CLIENT_DLL
class CPSCollisionEntity : public CBaseEntity
{
DECLARE_CLASS( CPSCollisionEntity, CBaseEntity );
private:
CPortalSimulator *m_pOwningSimulator;
public:
CPSCollisionEntity( void );
virtual ~CPSCollisionEntity( void );
virtual void Spawn( void );
virtual void Activate( void );
virtual int ObjectCaps( void );
virtual IPhysicsObject *VPhysicsGetObject( void );
virtual int VPhysicsGetObjectList( IPhysicsObject **pList, int listMax );
virtual void UpdateOnRemove( void );
virtual bool ShouldCollide( int collisionGroup, int contentsMask ) const;
virtual void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ) {}
virtual void VPhysicsFriction( IPhysicsObject *pObject, float energy, int surfaceProps, int surfacePropsHit ) {}
static bool IsPortalSimulatorCollisionEntity( const CBaseEntity *pEntity );
friend class CPortalSimulator;
};
#endif
#ifndef CLIENT_DLL
inline bool CPortalSimulator::OwnsEntity( const CBaseEntity *pEntity ) const
{
return ((m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] & PSEF_OWNS_ENTITY) != 0);
}
inline bool CPortalSimulator::OwnsPhysicsForEntity( const CBaseEntity *pEntity ) const
{
return ((m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] & PSEF_OWNS_PHYSICS) != 0);
}
#endif
inline bool CPortalSimulator::IsReadyToSimulate( void ) const
{
return m_bLocalDataIsReady && m_pLinkedPortal && m_pLinkedPortal->m_bLocalDataIsReady;
}
inline bool CPortalSimulator::IsSimulatingVPhysics( void ) const
{
return m_bSimulateVPhysics;
}
inline bool CPortalSimulator::IsCollisionGenerationEnabled( void ) const
{
return m_bGenerateCollision;
}
inline CPortalSimulator *CPortalSimulator::GetLinkedPortalSimulator( void ) const
{
return m_pLinkedPortal;
}
#endif //#ifndef PORTALSIMULATION_H
@@ -0,0 +1,485 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=====================================================================================//
#include "cbase.h"
#include "StaticCollisionPolyhedronCache.h"
#include "engine/IEngineTrace.h"
#include "edict.h"
#include "tier0/memdbgon.h"
class CPolyhedron_LumpedMemory : public CPolyhedron //we'll be allocating one big chunk of memory for all our polyhedrons. No individual will own any memory.
{
public:
virtual void Release( void ) { };
static CPolyhedron_LumpedMemory *AllocateAt( void *pMemory, int iVertices, int iLines, int iIndices, int iPolygons )
{
#include "tier0/memdbgoff.h" //the following placement new doesn't compile with memory debugging
CPolyhedron_LumpedMemory *pAllocated = new ( pMemory ) CPolyhedron_LumpedMemory;
#include "tier0/memdbgon.h"
pAllocated->iVertexCount = iVertices;
pAllocated->iLineCount = iLines;
pAllocated->iIndexCount = iIndices;
pAllocated->iPolygonCount = iPolygons;
pAllocated->pVertices = (Vector *)(pAllocated + 1); //start vertex memory at the end of the class
pAllocated->pLines = (Polyhedron_IndexedLine_t *)(pAllocated->pVertices + iVertices);
pAllocated->pIndices = (Polyhedron_IndexedLineReference_t *)(pAllocated->pLines + iLines);
pAllocated->pPolygons = (Polyhedron_IndexedPolygon_t *)(pAllocated->pIndices + iIndices);
return pAllocated;
}
};
static uint8 *s_BrushPolyhedronMemory = NULL;
static uint8 *s_StaticPropPolyhedronMemory = NULL;
CStaticCollisionPolyhedronCache g_StaticCollisionPolyhedronCache;
typedef ICollideable *ICollideablePtr; //needed for key comparison function syntax
static bool CollideablePtr_KeyCompareFunc( const ICollideablePtr &a, const ICollideablePtr &b )
{
return a < b;
};
CStaticCollisionPolyhedronCache::CStaticCollisionPolyhedronCache( void )
: m_CollideableIndicesMap( CollideablePtr_KeyCompareFunc )
{
}
CStaticCollisionPolyhedronCache::~CStaticCollisionPolyhedronCache( void )
{
Clear();
}
void CStaticCollisionPolyhedronCache::LevelInitPreEntity( void )
{
// FIXME: Fast updates would be nice but this method doesn't work with the recent changes to standard containers.
// For now we're going with the quick fix of always doing a full update. -Jeep
// if( Q_stricmp( m_CachedMap, MapName() ) != 0 )
// {
// // New map or the last load was a transition, fully update the cache
// m_CachedMap.Set( MapName() );
Update();
// }
// else
// {
// // No need for a full update, but we need to remap static prop ICollideable's in the old system to the new system
// for( int i = m_CollideableIndicesMap.Count(); --i >= 0; )
// {
//#ifdef _DEBUG
// StaticPropPolyhedronCacheInfo_t cacheInfo = m_CollideableIndicesMap.Element(i);
//#endif
// m_CollideableIndicesMap.Reinsert( staticpropmgr->GetStaticPropByIndex( m_CollideableIndicesMap.Element(i).iStaticPropIndex ), i );
//
// Assert( (m_CollideableIndicesMap.Element(i).iStartIndex == cacheInfo.iStartIndex) &&
// (m_CollideableIndicesMap.Element(i).iNumPolyhedrons == cacheInfo.iNumPolyhedrons) &&
// (m_CollideableIndicesMap.Element(i).iStaticPropIndex == cacheInfo.iStaticPropIndex) ); //I'm assuming this doesn't cause a reindex of the unordered list, if it does then this needs to be rewritten
// }
// }
}
void CStaticCollisionPolyhedronCache::Shutdown( void )
{
Clear();
}
void CStaticCollisionPolyhedronCache::Clear( void )
{
//The uses one big lump of memory to store polyhedrons. No need to Release() the polyhedrons.
//Brushes
{
m_BrushPolyhedrons.RemoveAll();
if( s_BrushPolyhedronMemory != NULL )
{
delete []s_BrushPolyhedronMemory;
s_BrushPolyhedronMemory = NULL;
}
}
//Static props
{
m_CollideableIndicesMap.RemoveAll();
m_StaticPropPolyhedrons.RemoveAll();
if( s_StaticPropPolyhedronMemory != NULL )
{
delete []s_StaticPropPolyhedronMemory;
s_StaticPropPolyhedronMemory = NULL;
}
}
}
void CStaticCollisionPolyhedronCache::Update( void )
{
Clear();
//There's no efficient way to know exactly how much memory we'll need to cache off all these polyhedrons.
//So we're going to allocated temporary workspaces as we need them and consolidate into one allocation at the end.
const size_t workSpaceSize = 1024 * 1024; //1MB. Fairly arbitrary size for a workspace. Brushes usually use 1-3MB in the end. Static props usually use about half as much as brushes.
uint8 *workSpaceAllocations[256];
size_t usedSpaceInWorkspace[256];
unsigned int workSpacesAllocated = 0;
uint8 *pCurrentWorkSpace = new uint8 [workSpaceSize];
size_t roomLeftInWorkSpace = workSpaceSize;
workSpaceAllocations[workSpacesAllocated] = pCurrentWorkSpace;
usedSpaceInWorkspace[workSpacesAllocated] = 0;
++workSpacesAllocated;
//brushes
{
int iBrush = 0;
CUtlVector<Vector4D> Planes;
float fStackPlanes[4 * 400]; //400 is a crapload of planes in my opinion
while( enginetrace->GetBrushInfo( iBrush, &Planes, NULL ) )
{
int iPlaneCount = Planes.Count();
AssertMsg( iPlaneCount != 0, "A brush with no planes???????" );
const Vector4D *pReturnedPlanes = Planes.Base();
CPolyhedron *pTempPolyhedron;
if( iPlaneCount > 400 )
{
// o_O, we'll have to get more memory to transform this brush
float *pNonstackPlanes = new float [4 * iPlaneCount];
for( int i = 0; i != iPlaneCount; ++i )
{
pNonstackPlanes[(i * 4) + 0] = pReturnedPlanes[i].x;
pNonstackPlanes[(i * 4) + 1] = pReturnedPlanes[i].y;
pNonstackPlanes[(i * 4) + 2] = pReturnedPlanes[i].z;
pNonstackPlanes[(i * 4) + 3] = pReturnedPlanes[i].w;
}
pTempPolyhedron = GeneratePolyhedronFromPlanes( pNonstackPlanes, iPlaneCount, 0.01f, true );
delete []pNonstackPlanes;
}
else
{
for( int i = 0; i != iPlaneCount; ++i )
{
fStackPlanes[(i * 4) + 0] = pReturnedPlanes[i].x;
fStackPlanes[(i * 4) + 1] = pReturnedPlanes[i].y;
fStackPlanes[(i * 4) + 2] = pReturnedPlanes[i].z;
fStackPlanes[(i * 4) + 3] = pReturnedPlanes[i].w;
}
pTempPolyhedron = GeneratePolyhedronFromPlanes( fStackPlanes, iPlaneCount, 0.01f, true );
}
if( pTempPolyhedron )
{
size_t memRequired = (sizeof( CPolyhedron_LumpedMemory )) +
(sizeof( Vector ) * pTempPolyhedron->iVertexCount) +
(sizeof( Polyhedron_IndexedLine_t ) * pTempPolyhedron->iLineCount) +
(sizeof( Polyhedron_IndexedLineReference_t ) * pTempPolyhedron->iIndexCount) +
(sizeof( Polyhedron_IndexedPolygon_t ) * pTempPolyhedron->iPolygonCount);
Assert( memRequired < workSpaceSize );
if( roomLeftInWorkSpace < memRequired )
{
usedSpaceInWorkspace[workSpacesAllocated - 1] = workSpaceSize - roomLeftInWorkSpace;
pCurrentWorkSpace = new uint8 [workSpaceSize];
roomLeftInWorkSpace = workSpaceSize;
workSpaceAllocations[workSpacesAllocated] = pCurrentWorkSpace;
usedSpaceInWorkspace[workSpacesAllocated] = 0;
++workSpacesAllocated;
}
CPolyhedron *pWorkSpacePolyhedron = CPolyhedron_LumpedMemory::AllocateAt( pCurrentWorkSpace,
pTempPolyhedron->iVertexCount,
pTempPolyhedron->iLineCount,
pTempPolyhedron->iIndexCount,
pTempPolyhedron->iPolygonCount );
pCurrentWorkSpace += memRequired;
roomLeftInWorkSpace -= memRequired;
memcpy( pWorkSpacePolyhedron->pVertices, pTempPolyhedron->pVertices, pTempPolyhedron->iVertexCount * sizeof( Vector ) );
memcpy( pWorkSpacePolyhedron->pLines, pTempPolyhedron->pLines, pTempPolyhedron->iLineCount * sizeof( Polyhedron_IndexedLine_t ) );
memcpy( pWorkSpacePolyhedron->pIndices, pTempPolyhedron->pIndices, pTempPolyhedron->iIndexCount * sizeof( Polyhedron_IndexedLineReference_t ) );
memcpy( pWorkSpacePolyhedron->pPolygons, pTempPolyhedron->pPolygons, pTempPolyhedron->iPolygonCount * sizeof( Polyhedron_IndexedPolygon_t ) );
m_BrushPolyhedrons.AddToTail( pWorkSpacePolyhedron );
pTempPolyhedron->Release();
}
else
{
m_BrushPolyhedrons.AddToTail( NULL );
}
++iBrush;
}
usedSpaceInWorkspace[workSpacesAllocated - 1] = workSpaceSize - roomLeftInWorkSpace;
if( usedSpaceInWorkspace[0] != 0 ) //At least a little bit of memory was used.
{
//consolidate workspaces into a single memory chunk
size_t totalMemoryNeeded = 0;
for( unsigned int i = 0; i != workSpacesAllocated; ++i )
{
totalMemoryNeeded += usedSpaceInWorkspace[i];
}
uint8 *pFinalDest = new uint8 [totalMemoryNeeded];
s_BrushPolyhedronMemory = pFinalDest;
DevMsg( 2, "CStaticCollisionPolyhedronCache: Used %.2f KB to cache %d brush polyhedrons.\n", ((float)totalMemoryNeeded) / 1024.0f, m_BrushPolyhedrons.Count() );
int iCount = m_BrushPolyhedrons.Count();
for( int i = 0; i != iCount; ++i )
{
CPolyhedron_LumpedMemory *pSource = (CPolyhedron_LumpedMemory *)m_BrushPolyhedrons[i];
if( pSource == NULL )
continue;
size_t memRequired = (sizeof( CPolyhedron_LumpedMemory )) +
(sizeof( Vector ) * pSource->iVertexCount) +
(sizeof( Polyhedron_IndexedLine_t ) * pSource->iLineCount) +
(sizeof( Polyhedron_IndexedLineReference_t ) * pSource->iIndexCount) +
(sizeof( Polyhedron_IndexedPolygon_t ) * pSource->iPolygonCount);
CPolyhedron_LumpedMemory *pDest = (CPolyhedron_LumpedMemory *)pFinalDest;
m_BrushPolyhedrons[i] = pDest;
pFinalDest += memRequired;
int memoryOffset = ((uint8 *)pDest) - ((uint8 *)pSource);
memcpy( pDest, pSource, memRequired );
//move all the pointers to their new location.
pDest->pVertices = (Vector *)(((uint8 *)(pDest->pVertices)) + memoryOffset);
pDest->pLines = (Polyhedron_IndexedLine_t *)(((uint8 *)(pDest->pLines)) + memoryOffset);
pDest->pIndices = (Polyhedron_IndexedLineReference_t *)(((uint8 *)(pDest->pIndices)) + memoryOffset);
pDest->pPolygons = (Polyhedron_IndexedPolygon_t *)(((uint8 *)(pDest->pPolygons)) + memoryOffset);
}
}
}
unsigned int iBrushWorkSpaces = workSpacesAllocated;
workSpacesAllocated = 1;
pCurrentWorkSpace = workSpaceAllocations[0];
usedSpaceInWorkspace[0] = 0;
roomLeftInWorkSpace = workSpaceSize;
//static props
{
CUtlVector<ICollideable *> StaticPropCollideables;
staticpropmgr->GetAllStaticProps( &StaticPropCollideables );
if( StaticPropCollideables.Count() != 0 )
{
ICollideable **pCollideables = StaticPropCollideables.Base();
ICollideable **pStop = pCollideables + StaticPropCollideables.Count();
int iStaticPropIndex = 0;
do
{
ICollideable *pProp = *pCollideables;
vcollide_t *pCollide = modelinfo->GetVCollide( pProp->GetCollisionModel() );
StaticPropPolyhedronCacheInfo_t cacheInfo;
cacheInfo.iStartIndex = m_StaticPropPolyhedrons.Count();
if( pCollide != NULL )
{
VMatrix matToWorldPosition = pProp->CollisionToWorldTransform();
for( int i = 0; i != pCollide->solidCount; ++i )
{
CPhysConvex *ConvexesArray[1024];
int iConvexes = physcollision->GetConvexesUsedInCollideable( pCollide->solids[i], ConvexesArray, 1024 );
for( int j = 0; j != iConvexes; ++j )
{
CPolyhedron *pTempPolyhedron = physcollision->PolyhedronFromConvex( ConvexesArray[j], true );
if( pTempPolyhedron )
{
for( int iPointCounter = 0; iPointCounter != pTempPolyhedron->iVertexCount; ++iPointCounter )
pTempPolyhedron->pVertices[iPointCounter] = matToWorldPosition * pTempPolyhedron->pVertices[iPointCounter];
for( int iPolyCounter = 0; iPolyCounter != pTempPolyhedron->iPolygonCount; ++iPolyCounter )
pTempPolyhedron->pPolygons[iPolyCounter].polyNormal = matToWorldPosition.ApplyRotation( pTempPolyhedron->pPolygons[iPolyCounter].polyNormal );
size_t memRequired = (sizeof( CPolyhedron_LumpedMemory )) +
(sizeof( Vector ) * pTempPolyhedron->iVertexCount) +
(sizeof( Polyhedron_IndexedLine_t ) * pTempPolyhedron->iLineCount) +
(sizeof( Polyhedron_IndexedLineReference_t ) * pTempPolyhedron->iIndexCount) +
(sizeof( Polyhedron_IndexedPolygon_t ) * pTempPolyhedron->iPolygonCount);
Assert( memRequired < workSpaceSize );
if( roomLeftInWorkSpace < memRequired )
{
usedSpaceInWorkspace[workSpacesAllocated - 1] = workSpaceSize - roomLeftInWorkSpace;
if( workSpacesAllocated < iBrushWorkSpaces )
{
//re-use a workspace already allocated during brush polyhedron conversion
pCurrentWorkSpace = workSpaceAllocations[workSpacesAllocated];
usedSpaceInWorkspace[workSpacesAllocated] = 0;
}
else
{
//allocate a new workspace
pCurrentWorkSpace = new uint8 [workSpaceSize];
workSpaceAllocations[workSpacesAllocated] = pCurrentWorkSpace;
usedSpaceInWorkspace[workSpacesAllocated] = 0;
}
roomLeftInWorkSpace = workSpaceSize;
++workSpacesAllocated;
}
CPolyhedron *pWorkSpacePolyhedron = CPolyhedron_LumpedMemory::AllocateAt( pCurrentWorkSpace,
pTempPolyhedron->iVertexCount,
pTempPolyhedron->iLineCount,
pTempPolyhedron->iIndexCount,
pTempPolyhedron->iPolygonCount );
pCurrentWorkSpace += memRequired;
roomLeftInWorkSpace -= memRequired;
memcpy( pWorkSpacePolyhedron->pVertices, pTempPolyhedron->pVertices, pTempPolyhedron->iVertexCount * sizeof( Vector ) );
memcpy( pWorkSpacePolyhedron->pLines, pTempPolyhedron->pLines, pTempPolyhedron->iLineCount * sizeof( Polyhedron_IndexedLine_t ) );
memcpy( pWorkSpacePolyhedron->pIndices, pTempPolyhedron->pIndices, pTempPolyhedron->iIndexCount * sizeof( Polyhedron_IndexedLineReference_t ) );
memcpy( pWorkSpacePolyhedron->pPolygons, pTempPolyhedron->pPolygons, pTempPolyhedron->iPolygonCount * sizeof( Polyhedron_IndexedPolygon_t ) );
m_StaticPropPolyhedrons.AddToTail( pWorkSpacePolyhedron );
#ifdef _DEBUG
CPhysConvex *pConvex = physcollision->ConvexFromConvexPolyhedron( *pTempPolyhedron );
AssertMsg( pConvex != NULL, "Conversion from Convex to Polyhedron was unreversable" );
if( pConvex )
{
physcollision->ConvexFree( pConvex );
}
#endif
pTempPolyhedron->Release();
}
}
}
cacheInfo.iNumPolyhedrons = m_StaticPropPolyhedrons.Count() - cacheInfo.iStartIndex;
cacheInfo.iStaticPropIndex = iStaticPropIndex;
Assert( staticpropmgr->GetStaticPropByIndex( iStaticPropIndex ) == pProp );
m_CollideableIndicesMap.InsertOrReplace( pProp, cacheInfo );
}
++iStaticPropIndex;
++pCollideables;
} while( pCollideables != pStop );
usedSpaceInWorkspace[workSpacesAllocated - 1] = workSpaceSize - roomLeftInWorkSpace;
if( usedSpaceInWorkspace[0] != 0 ) //At least a little bit of memory was used.
{
//consolidate workspaces into a single memory chunk
size_t totalMemoryNeeded = 0;
for( unsigned int i = 0; i != workSpacesAllocated; ++i )
{
totalMemoryNeeded += usedSpaceInWorkspace[i];
}
uint8 *pFinalDest = new uint8 [totalMemoryNeeded];
s_StaticPropPolyhedronMemory = pFinalDest;
DevMsg( 2, "CStaticCollisionPolyhedronCache: Used %.2f KB to cache %d static prop polyhedrons.\n", ((float)totalMemoryNeeded) / 1024.0f, m_StaticPropPolyhedrons.Count() );
int iCount = m_StaticPropPolyhedrons.Count();
for( int i = 0; i != iCount; ++i )
{
CPolyhedron_LumpedMemory *pSource = (CPolyhedron_LumpedMemory *)m_StaticPropPolyhedrons[i];
size_t memRequired = (sizeof( CPolyhedron_LumpedMemory )) +
(sizeof( Vector ) * pSource->iVertexCount) +
(sizeof( Polyhedron_IndexedLine_t ) * pSource->iLineCount) +
(sizeof( Polyhedron_IndexedLineReference_t ) * pSource->iIndexCount) +
(sizeof( Polyhedron_IndexedPolygon_t ) * pSource->iPolygonCount);
CPolyhedron_LumpedMemory *pDest = (CPolyhedron_LumpedMemory *)pFinalDest;
m_StaticPropPolyhedrons[i] = pDest;
pFinalDest += memRequired;
int memoryOffset = ((uint8 *)pDest) - ((uint8 *)pSource);
memcpy( pDest, pSource, memRequired );
//move all the pointers to their new location.
pDest->pVertices = (Vector *)(((uint8 *)(pDest->pVertices)) + memoryOffset);
pDest->pLines = (Polyhedron_IndexedLine_t *)(((uint8 *)(pDest->pLines)) + memoryOffset);
pDest->pIndices = (Polyhedron_IndexedLineReference_t *)(((uint8 *)(pDest->pIndices)) + memoryOffset);
pDest->pPolygons = (Polyhedron_IndexedPolygon_t *)(((uint8 *)(pDest->pPolygons)) + memoryOffset);
}
}
}
}
if( iBrushWorkSpaces > workSpacesAllocated )
workSpacesAllocated = iBrushWorkSpaces;
for( unsigned int i = 0; i != workSpacesAllocated; ++i )
{
delete []workSpaceAllocations[i];
}
}
const CPolyhedron *CStaticCollisionPolyhedronCache::GetBrushPolyhedron( int iBrushNumber )
{
Assert( iBrushNumber < m_BrushPolyhedrons.Count() );
if( (iBrushNumber < 0) || (iBrushNumber >= m_BrushPolyhedrons.Count()) )
return NULL;
return m_BrushPolyhedrons[iBrushNumber];
}
int CStaticCollisionPolyhedronCache::GetStaticPropPolyhedrons( ICollideable *pStaticProp, CPolyhedron **pOutputPolyhedronArray, int iOutputArraySize )
{
unsigned short iPropIndex = m_CollideableIndicesMap.Find( pStaticProp );
if( !m_CollideableIndicesMap.IsValidIndex( iPropIndex ) ) //static prop never made it into the cache for some reason (specifically no collision data when this workaround was written)
return 0;
StaticPropPolyhedronCacheInfo_t cacheInfo = m_CollideableIndicesMap.Element( iPropIndex );
if( cacheInfo.iNumPolyhedrons < iOutputArraySize )
iOutputArraySize = cacheInfo.iNumPolyhedrons;
for( int i = cacheInfo.iStartIndex, iWriteIndex = 0; iWriteIndex != iOutputArraySize; ++i, ++iWriteIndex )
{
pOutputPolyhedronArray[iWriteIndex] = m_StaticPropPolyhedrons[i];
}
return iOutputArraySize;
}
@@ -0,0 +1,52 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Portals use polyhedrons to clip and carve their custom collision areas.
// This file should provide caches of polyhedrons with the initial conversion
// processes already completed.
//
// $NoKeywords: $
//=====================================================================================//
#include "igamesystem.h"
#include "mathlib/polyhedron.h"
#include "tier1/utlvector.h"
#include "tier1/utlstring.h"
#include "tier1/utlmap.h"
class CStaticCollisionPolyhedronCache : public CAutoGameSystem
{
public:
CStaticCollisionPolyhedronCache( void );
~CStaticCollisionPolyhedronCache( void );
void LevelInitPreEntity( void );
void Shutdown( void );
const CPolyhedron *GetBrushPolyhedron( int iBrushNumber );
int GetStaticPropPolyhedrons( ICollideable *pStaticProp, CPolyhedron **pOutputPolyhedronArray, int iOutputArraySize );
private:
// See comments in LevelInitPreEntity for why these members are commented out
// CUtlString m_CachedMap;
CUtlVector<CPolyhedron *> m_BrushPolyhedrons;
struct StaticPropPolyhedronCacheInfo_t
{
int iStartIndex;
int iNumPolyhedrons;
int iStaticPropIndex; //helps us remap ICollideable pointers when the map is restarted
};
CUtlVector<CPolyhedron *> m_StaticPropPolyhedrons;
CUtlMap<ICollideable *, StaticPropPolyhedronCacheInfo_t> m_CollideableIndicesMap;
void Clear( void );
void Update( void );
};
extern CStaticCollisionPolyhedronCache g_StaticCollisionPolyhedronCache;
+547
View File
@@ -0,0 +1,547 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "achievementmgr.h"
#include "baseachievement.h"
#ifdef GAME_DLL
#include "prop_portal.h"
#include "util.h"
CAchievementMgr g_AchievementMgrPortal; // global achievement mgr for Portal
class CAchievementPortalInfiniteFall : public CBaseAchievement
{
DECLARE_CLASS( CAchievementPortalInfiniteFall, CBaseAchievement );
public:
void Init()
{
SetFlags( ACH_SAVE_WITH_GAME );
SetGameDirFilter( "portal" );
SetGoal( 1 );
m_fAccumulatedDistance = 0.0f;
m_bIsFlinging = false;
}
virtual void ListenForEvents()
{
ListenForGameEvent( "portal_player_portaled" );
ListenForGameEvent( "portal_player_touchedground" );
}
virtual void PreRestoreSavedGame()
{
m_fAccumulatedDistance = 0.0f;
m_bIsFlinging = false;
BaseClass::PreRestoreSavedGame();
}
protected:
virtual void FireGameEvent( IGameEvent *event )
{
const char *name = event->GetName();
if ( 0 == Q_strcmp( name, "portal_player_portaled" ) )
{
bool bIsPortal2 = event->GetBool( "portal2", false );
// Get the portals that they teleported through
CProp_Portal *pInPortal = CProp_Portal::FindPortal( 0, bIsPortal2, false );
CProp_Portal *pOutPortal = CProp_Portal::FindPortal( 0, !bIsPortal2, false );
if ( pInPortal && pOutPortal )
{
if ( m_bIsFlinging )
{
// Add up how far we traveled since the last teleport
m_fAccumulatedDistance += m_fZPortalPosition - pInPortal->GetAbsOrigin().z;
if ( m_fAccumulatedDistance > 30000.0f * 12 )
IncrementCount();
}
// Remember the Z position to get the distance when the teleport again or land
m_fZPortalPosition = pOutPortal->GetAbsOrigin().z;
m_bIsFlinging = true;
}
}
else if ( 0 == Q_strcmp( name, "portal_player_touchedground" ) )
{
if ( m_bIsFlinging )
{
CBasePlayer *pLocalPlayer = UTIL_GetLocalPlayer();
if ( pLocalPlayer )
{
m_fAccumulatedDistance += m_fZPortalPosition - pLocalPlayer->GetAbsOrigin().z;
if ( m_fAccumulatedDistance > 30000.0f * 12 )
IncrementCount();
m_fAccumulatedDistance = 0.0f;
m_bIsFlinging = false;
}
}
}
}
private:
bool m_bIsFlinging;
float m_fAccumulatedDistance;
float m_fZPortalPosition;
};
DECLARE_ACHIEVEMENT( CAchievementPortalInfiniteFall, ACHIEVEMENT_PORTAL_INFINITEFALL, "PORTAL_INFINITEFALL", 5 );
class CAchievementPortalLongJump : public CBaseAchievement
{
DECLARE_CLASS( CAchievementPortalLongJump, CBaseAchievement );
public:
void Init()
{
SetFlags( ACH_SAVE_WITH_GAME );
SetGameDirFilter( "portal" );
SetGoal( 1 );
m_fAccumulatedDistance = 0.0f;
m_bIsFlinging = false;
}
virtual void ListenForEvents()
{
ListenForGameEvent( "portal_player_portaled" );
ListenForGameEvent( "portal_player_touchedground" );
}
virtual void PreRestoreSavedGame()
{
m_fAccumulatedDistance = 0.0f;
m_bIsFlinging = false;
BaseClass::PreRestoreSavedGame();
}
protected:
virtual void FireGameEvent( IGameEvent *event )
{
const char *name = event->GetName();
if ( 0 == Q_strcmp( name, "portal_player_portaled" ) )
{
bool bIsPortal2 = event->GetBool( "portal2", false );
// Get the portals that they teleported through
CProp_Portal *pInPortal = CProp_Portal::FindPortal( 0, bIsPortal2, false );
CProp_Portal *pOutPortal = CProp_Portal::FindPortal( 0, !bIsPortal2, false );
if ( pInPortal && pOutPortal )
{
if ( m_bIsFlinging )
{
// Add up how far we traveled since the last teleport
float flDist = pInPortal->GetAbsOrigin().AsVector2D().DistTo( m_vec2DPortalPosition );
// Ignore small distances that can be caused by microadjustments in infinite falls
if ( flDist > 63.0f )
{
m_fAccumulatedDistance += flDist;
}
if ( m_fAccumulatedDistance > 300.0f * 12 )
IncrementCount();
}
// Remember the 2D position to get the distance when the teleport again or land
m_vec2DPortalPosition = pOutPortal->GetAbsOrigin().AsVector2D();
m_bIsFlinging = true;
}
}
else if ( 0 == Q_strcmp( name, "portal_player_touchedground" ) )
{
if ( m_bIsFlinging )
{
CBasePlayer *pLocalPlayer = UTIL_GetLocalPlayer();
if ( pLocalPlayer )
{
float flDist = pLocalPlayer->GetAbsOrigin().AsVector2D().DistTo( m_vec2DPortalPosition );
// Ignore small distances that can be caused by microadjustments in infinite falls
if ( flDist > 63.0f )
{
m_fAccumulatedDistance += flDist;
}
if ( m_fAccumulatedDistance > 300.0f * 12 )
IncrementCount();
m_fAccumulatedDistance = 0.0f;
m_bIsFlinging = false;
}
}
}
}
private:
bool m_bIsFlinging;
float m_fAccumulatedDistance;
Vector2D m_vec2DPortalPosition;
};
DECLARE_ACHIEVEMENT( CAchievementPortalLongJump, ACHIEVEMENT_PORTAL_LONGJUMP, "PORTAL_LONGJUMP", 5 );
class CAchievementPortalBeat2AdvancedMaps: public CBaseAchievement
{
public:
virtual void Init()
{
SetFlags( ACH_SAVE_GLOBAL );
SetGoal( 2 );
m_iProgressMsgMinimum = 0;
}
virtual void ListenForEvents()
{
ListenForGameEvent( "advanced_map_complete" );
}
protected:
virtual void FireGameEvent( IGameEvent* event )
{
if ( !Q_stricmp( event->GetName(), "advanced_map_complete" ) )
{
if ( !IsAchieved() )
{
int iNumAdvanced = event->GetInt( "numadvanced" );
SetCount ( iNumAdvanced );
if ( iNumAdvanced >= GetGoal() )
{
AwardAchievement();
}
else
{
HandleProgressUpdate();
}
}
}
}
virtual void CalcProgressMsgIncrement()
{
// show progress every tick
m_iProgressMsgIncrement = 1;
}
};
DECLARE_ACHIEVEMENT( CAchievementPortalBeat2AdvancedMaps, ACHIEVEMENT_PORTAL_BEAT_2ADVANCEDMAPS, "PORTAL_BEAT_2ADVANCEDMAPS", 10 );
class CAchievementPortalBeat4AdvancedMaps : public CBaseAchievement
{
public:
virtual void Init()
{
SetFlags( ACH_SAVE_GLOBAL );
SetGoal( 4 );
m_iProgressMsgMinimum = 3;
}
virtual void ListenForEvents()
{
ListenForGameEvent( "advanced_map_complete" );
}
protected:
virtual void FireGameEvent( IGameEvent* event )
{
if ( !Q_stricmp( event->GetName(), "advanced_map_complete" ) )
{
if ( !IsAchieved() )
{
int iNumAdvanced = event->GetInt( "numadvanced" );
SetCount ( iNumAdvanced );
if ( iNumAdvanced >= GetGoal() )
{
AwardAchievement();
}
else
{
HandleProgressUpdate();
}
}
}
}
virtual void CalcProgressMsgIncrement()
{
// show progress every tick
m_iProgressMsgIncrement = 1;
}
};
DECLARE_ACHIEVEMENT( CAchievementPortalBeat4AdvancedMaps, ACHIEVEMENT_PORTAL_BEAT_4ADVANCEDMAPS, "PORTAL_BEAT_4ADVANCEDMAPS", 20 );
class CAchievementPortalBeat6AdvancedMaps : public CBaseAchievement
{
public:
virtual void Init()
{
SetFlags( ACH_SAVE_GLOBAL );
SetGoal( 6 );
m_iProgressMsgMinimum = 5;
}
virtual void ListenForEvents()
{
ListenForGameEvent( "advanced_map_complete" );
}
protected:
virtual void FireGameEvent( IGameEvent* event )
{
if ( !Q_stricmp( event->GetName(), "advanced_map_complete" ) )
{
if ( !IsAchieved() )
{
int iNumAdvanced = event->GetInt( "numadvanced" );
SetCount ( iNumAdvanced );
if ( iNumAdvanced >= GetGoal() )
{
AwardAchievement();
}
else
{
HandleProgressUpdate();
}
}
}
}
virtual void CalcProgressMsgIncrement()
{
// show progress every tick
m_iProgressMsgIncrement = 1;
}
};
DECLARE_ACHIEVEMENT( CAchievementPortalBeat6AdvancedMaps, ACHIEVEMENT_PORTAL_BEAT_6ADVANCEDMAPS, "PORTAL_BEAT_6ADVANCEDMAPS", 30 );
class CAchievementPortalGetAllBronze : public CBaseAchievement
{
public:
virtual void Init()
{
SetFlags( ACH_SAVE_GLOBAL );
SetGoal( 18 );
}
virtual void ListenForEvents()
{
ListenForGameEvent( "challenge_map_complete" );
}
protected:
virtual void FireGameEvent( IGameEvent* event )
{
if ( !Q_stricmp( event->GetName(), "challenge_map_complete" ) )
{
if ( !IsAchieved() )
{
int iBronzeCount = event->GetInt( "numbronze" );
SetCount ( iBronzeCount );
if ( iBronzeCount >= GetGoal() )
{
AwardAchievement();
}
else
{
HandleProgressUpdate();
}
}
}
}
virtual void CalcProgressMsgIncrement()
{
// show progress every tick
m_iProgressMsgIncrement = 1;
}
};
DECLARE_ACHIEVEMENT( CAchievementPortalGetAllBronze, ACHIEVEMENT_PORTAL_GET_ALLBRONZE, "PORTAL_GET_ALLBRONZE", 10 );
class CAchievementPortalGetAllSilver : public CBaseAchievement
{
public:
virtual void Init()
{
SetFlags( ACH_SAVE_GLOBAL );
SetGoal( 18 );
}
virtual void ListenForEvents()
{
ListenForGameEvent( "challenge_map_complete" );
}
protected:
virtual void FireGameEvent( IGameEvent* event )
{
if ( !Q_stricmp( event->GetName(), "challenge_map_complete" ) )
{
if ( !IsAchieved() )
{
int iSilverCount = event->GetInt( "numsilver" );
SetCount ( iSilverCount );
if ( iSilverCount >= GetGoal() )
{
AwardAchievement();
}
else
{
HandleProgressUpdate();
}
}
}
}
virtual void CalcProgressMsgIncrement()
{
// show progress every tick
m_iProgressMsgIncrement = 1;
}
};
DECLARE_ACHIEVEMENT( CAchievementPortalGetAllSilver, ACHIEVEMENT_PORTAL_GET_ALLSILVER, "PORTAL_GET_ALLSILVER", 20 );
class CAchievementPortalGetAllGold : public CBaseAchievement
{
public:
virtual void Init()
{
SetFlags( ACH_SAVE_GLOBAL );
SetGoal( 18 );
}
virtual void ListenForEvents()
{
ListenForGameEvent( "challenge_map_complete" );
}
protected:
virtual void FireGameEvent( IGameEvent* event )
{
if ( !Q_stricmp( event->GetName(), "challenge_map_complete" ) )
{
if ( !IsAchieved() )
{
int iGoldCount = event->GetInt( "numgold" );
SetCount ( iGoldCount );
if ( iGoldCount >= GetGoal() )
{
AwardAchievement();
}
else
{
HandleProgressUpdate();
}
}
}
}
virtual void CalcProgressMsgIncrement()
{
// show progress every tick
m_iProgressMsgIncrement = 1;
}
};
DECLARE_ACHIEVEMENT( CAchievementPortalGetAllGold, ACHIEVEMENT_PORTAL_GET_ALLGOLD, "PORTAL_GET_ALLGOLD", 40 );
class CAchievementPortalDetachAllCameras : public CBaseAchievement
{
protected:
virtual void ListenForEvents()
{
ListenForGameEvent( "security_camera_detached" );
}
void FireGameEvent_Internal( IGameEvent *event )
{
if ( 0 == Q_strcmp( event->GetName(), "security_camera_detached" ) )
{
IncrementCount();
}
}
public:
virtual void Init()
{
SetFlags( ACH_SAVE_WITH_GAME );
SetGoal( 33 );
ListenForGameEvent( "security_camera_detached" );
}
};
DECLARE_ACHIEVEMENT( CAchievementPortalDetachAllCameras, ACHIEVEMENT_PORTAL_DETACH_ALL_CAMERAS, "PORTAL_DETACH_ALL_CAMERAS", 5 );
class CAchievementPortalHitTurretWithTurret : public CBaseAchievement
{
protected:
virtual void ListenForEvents()
{
ListenForGameEvent( "turret_hit_turret" );
}
void FireGameEvent_Internal( IGameEvent *event )
{
if ( 0 == Q_strcmp( event->GetName(), "turret_hit_turret" ) )
{
IncrementCount();
}
}
public:
virtual void Init()
{
SetFlags( ACH_SAVE_GLOBAL );
SetGoal( 1 );
ListenForGameEvent( "turret_hit_turret" );
}
};
DECLARE_ACHIEVEMENT( CAchievementPortalHitTurretWithTurret, ACHIEVEMENT_PORTAL_HIT_TURRET_WITH_TURRET, "PORTAL_HIT_TURRET_WITH_TURRET", 5 );
#ifndef _XBOX
class CAchievementPortalFindAllDinosaurs : public CBaseAchievement
{
DECLARE_CLASS( CAchievementPortalFindAllDinosaurs, CBaseAchievement );
void Init()
{
SetFlags( ACH_HAS_COMPONENTS | ACH_SAVE_GLOBAL );
m_iNumComponents = 26;
SetStoreProgressInSteam( true );
SetGoal( m_iNumComponents );
BaseClass::Init();
m_iProgressMsgMinimum = 1;
}
virtual void ListenForEvents()
{
ListenForGameEvent( "dinosaur_signal_found" );
}
virtual void FireGameEvent_Internal( IGameEvent *event )
{
if ( 0 == Q_strcmp( event->GetName(), "dinosaur_signal_found" ) )
{
int id = event->GetInt( "id", -1 );
Assert( id >= 0 && id < m_iNumComponents );
if ( id >= 0 && id < m_iNumComponents )
{
EnsureComponentBitSetAndEvaluate( id );
// Update our Steam stat
steamapicontext->SteamUserStats()->SetStat( "PORTAL_TRANSMISSION_RECEIVED_STAT", m_iCount );
}
else
{
Warning( "Failed to set achievement progress. Dinosaur ID(%d) out of range (0 to %d)\n", id, m_iNumComponents );
}
}
}
virtual void CalcProgressMsgIncrement()
{
// Show progress every tick
m_iProgressMsgIncrement = 1;
}
};
DECLARE_ACHIEVEMENT( CAchievementPortalFindAllDinosaurs, ACHIEVEMENT_PORTAL_TRANSMISSION_RECEIVED, "PORTAL_TRANSMISSION_RECEIVED", 0 );
#endif // _XBOX
// achievements which are won by a map event firing once
DECLARE_MAP_EVENT_ACHIEVEMENT( ACHIEVEMENT_PORTAL_GET_PORTALGUNS, "PORTAL_GET_PORTALGUNS", 5 );
DECLARE_MAP_EVENT_ACHIEVEMENT( ACHIEVEMENT_PORTAL_KILL_COMPANIONCUBE, "PORTAL_KILL_COMPANIONCUBE", 5 );
DECLARE_MAP_EVENT_ACHIEVEMENT( ACHIEVEMENT_PORTAL_ESCAPE_TESTCHAMBERS, "PORTAL_ESCAPE_TESTCHAMBERS", 5 );
DECLARE_MAP_EVENT_ACHIEVEMENT( ACHIEVEMENT_PORTAL_BEAT_GAME, "PORTAL_BEAT_GAME", 10 );
#endif // GAME_DLL
@@ -0,0 +1,69 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef ENV_LIGHTRAIL_ENDPOINT_SHARED_H
#define ENV_LIGHTRAIL_ENDPOINT_SHARED_H
#ifdef _WIN32
#pragma once
#endif
#define SF_ENDPOINT_START_SMALLFX (1<<0) //Define spawnflags
//#define SF_ENDPOINT_START_LARGEFX (1<<1)
enum //Enumeration of the 4 states the endpoints can be in.
{
ENDPOINT_STATE_OFF, //No FX displayed
ENDPOINT_STATE_SMALLFX, //Just the small particle trail is displayed and a faint glow
ENDPOINT_STATE_CHARGING, //Ramp up over a certain amount of time to the large bright glow
ENDPOINT_STATE_LARGEFX, //Shows a particle trail and a large bright glow
ENDPOINT_STATE_COUNT,
};
#ifndef CLIENT_DLL
// ============================================================================
//
// Energy core - charges up and then releases energy from its position
//
// ============================================================================
class CEnv_Lightrail_Endpoint : public CBaseEntity
{
DECLARE_CLASS( CEnv_Lightrail_Endpoint, CBaseEntity );
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
public:
void InputStartCharge( inputdata_t &inputdata );
void InputStartSmallFX(inputdata_t &inputdata );
void InputStartLargeFX( inputdata_t &inputdata );
void InputStop( inputdata_t &inputdata );
void SetSmallFXScale( float flSmallScale ) { m_flSmallScale = flSmallScale; }
void SetLargeFXScale( float flLargeScale ) { m_flLargeScale = flLargeScale; }
void StartCharge( float flWarmUpTime ); //Charging difference between the small and large fx
void StartSmallFX(); //Start discharging the scaled down version of the FX
void StartLargeFX(); //Start discharging the larger brighter version of the FX
void StopSmallFX( float flCoolDownTime ); //Stop discharging the small fx
void StopLargeFX( float flCoolDownTime ); //Stop discharging the small fx
virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo );
virtual int UpdateTransmitState( void );
virtual void Precache();
void Spawn( void );
private:
CNetworkVar( float, m_flSmallScale ); //Scale of the small fx
CNetworkVar( float, m_flLargeScale ); //Scale of the large fx
CNetworkVar( int, m_nState ); //Current state of the fx
CNetworkVar( float, m_flDuration );
CNetworkVar( float, m_flStartTime );
};
#endif
#endif // ENV_LIGHTRAIL_ENDPOINT_SHARED_H
@@ -0,0 +1,79 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: A version of path_track which draws.
//
//=============================================================================//
#ifndef ENV_PORTAL_PATH_TRACK_SHARED_H
#define ENV_PORTAL_PATH_TRACK_SHARED_H
#ifdef _WIN32
#pragma once
#endif
// States for track drawing
enum
{
PORTAL_PATH_TRACK_STATE_OFF,
PORTAL_PATH_TRACK_STATE_INACTIVE,
PORTAL_PATH_TRACK_STATE_ACTIVE,
PORTAL_PATH_TRACK_STATE_COUNT
};
#ifndef CLIENT_DLL
#include "pathtrack.h"
class CBeam;
//==============================================================
//
//==============================================================
class CEnvPortalPathTrack : public CPathTrack
{
DECLARE_CLASS( CEnvPortalPathTrack, CPathTrack );
DECLARE_DATADESC();
DECLARE_SERVERCLASS();
public:
CEnvPortalPathTrack();
~CEnvPortalPathTrack();
virtual void Precache();
void Spawn( void );
void Activate( void );
void InitTrackFX();
void ShutDownTrackFX();
void InitEndpointFX();
void ShutDownEndpointFX();
void InputActivateTrack( inputdata_t &inputdata );
void InputActivateEndpoint( inputdata_t &inputdata );
void InputDeactivateTrack( inputdata_t &inputdata );
void InputDeactivateEndpoint( inputdata_t &inputdata );
void ActivateTrackFX ( void ); //Activate all of the track's beams (at least the ones that are flagged to display)
void ActivateEndpointFX ( void ); //Activate all of the endpoint's glowy bits that are flagged to display
void DeactivateTrackFX ( void ); //Activate all of the track's beams (at least the ones that are flagged to display)
void DeactivateEndpointFX ( void ); //Activate all of the endpoint's glowy bits that are flagged to display
protected:
CNetworkVar( bool, m_bTrackActive );
CNetworkVar( bool, m_bEndpointActive );
// CNetworkVar( float, m_fScaleEndpoint ); // Scale of the endpoint for this beam
// CNetworkVar( float, m_fScaleTrack ); // Scale of the track effect
// CNetworkVar( float, m_fFadeOutEndpoint ); // Scale of the track effect
// CNetworkVar( float, m_fFadeInEndpoint ); // Scale of the track effect
CNetworkVar( int, m_nState ); // particle emmision state
COutputEvent m_OnActivatedEndpoint;
CBeam *m_pBeam; // Pointer to look at a cbeam object for the track fx
};
#endif // CLIENT_DLL
#endif //ENV_PORTAL_PATH_TRACK_SHARED_H
@@ -0,0 +1,103 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "prop_portal_shared.h"
#include "portal_collideable_enumerator.h"
#define PORTAL_TELEPORTATION_PLANE_OFFSET 7.0f
CPortalCollideableEnumerator::CPortalCollideableEnumerator( const CProp_Portal *pAssociatedPortal )
{
Assert( pAssociatedPortal );
m_hTestPortal = pAssociatedPortal;
pAssociatedPortal->GetVectors( &m_vPlaneNormal, NULL, NULL );
m_ptForward1000 = pAssociatedPortal->GetAbsOrigin();
m_ptForward1000 += m_vPlaneNormal * PORTAL_TELEPORTATION_PLANE_OFFSET;
m_fPlaneDist = m_vPlaneNormal.Dot( m_ptForward1000 );
m_ptForward1000 += m_vPlaneNormal * 1000.0f;
m_iHandleCount = 0;
}
IterationRetval_t CPortalCollideableEnumerator::EnumElement( IHandleEntity *pHandleEntity )
{
EHANDLE hEnt = pHandleEntity->GetRefEHandle();
CBaseEntity *pEnt = hEnt.Get();
if( pEnt == NULL ) //I really never thought this would be necessary
return ITERATION_CONTINUE;
if( hEnt == m_hTestPortal )
return ITERATION_CONTINUE; //ignore this portal
/*if( staticpropmgr->IsStaticProp( pHandleEntity ) )
{
//we're dealing with a static prop, which unfortunately doesn't have everything I want to use for checking
ICollideable *pCollideable = pEnt->GetCollideable();
Vector vMins, vMaxs;
pCollideable->WorldSpaceSurroundingBounds( &vMins, &vMaxs );
Vector ptTest( (m_vPlaneNormal.x > 0.0f)?(vMaxs.x):(vMins.x),
(m_vPlaneNormal.y > 0.0f)?(vMaxs.y):(vMins.y),
(m_vPlaneNormal.z > 0.0f)?(vMaxs.z):(vMins.z) );
float fPtPlaneDist = m_vPlaneNormal.Dot( ptTest ) - m_fPlaneDist;
if( fPtPlaneDist <= 0.0f )
return ITERATION_CONTINUE;
}
else*/
{
//not a static prop, w00t
CCollisionProperty *pEntityCollision = pEnt->CollisionProp();
if( !pEntityCollision->IsSolid() )
return ITERATION_CONTINUE; //not solid
Vector ptEntCenter = pEntityCollision->WorldSpaceCenter();
float fBoundRadius = pEntityCollision->BoundingRadius();
float fPtPlaneDist = m_vPlaneNormal.Dot( ptEntCenter ) - m_fPlaneDist;
if( fPtPlaneDist < -fBoundRadius )
return ITERATION_CONTINUE; //object wholly behind the portal
if( !(fPtPlaneDist > fBoundRadius) && (fPtPlaneDist > -fBoundRadius) ) //object is not wholly in front of the portal, but could be partially in front, do more checks
{
Vector ptNearest;
pEntityCollision->CalcNearestPoint( m_ptForward1000, &ptNearest );
fPtPlaneDist = m_vPlaneNormal.Dot( ptNearest ) - m_fPlaneDist;
if( fPtPlaneDist < 0.0f )
return ITERATION_CONTINUE; //closest point was behind the portal plane, we don't want it
}
}
//if we're down here, this entity needs to be added to our enumeration
Assert( m_iHandleCount < 1024 );
if( m_iHandleCount < 1024 )
m_pHandles[m_iHandleCount] = pHandleEntity;
++m_iHandleCount;
return ITERATION_CONTINUE;
}
@@ -0,0 +1,41 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef PORTAL_COLLIDEABLE_ENUMERATOR_H
#define PORTAL_COLLIDEABLE_ENUMERATOR_H
#ifdef _WIN32
#pragma once
#endif
#include "ispatialpartition.h"
#ifdef CLIENT_DLL
class C_Prop_Portal;
typedef C_Prop_Portal CProp_Portal;
#else
class CProp_Portal;
#endif
//only enumerates entities in front of the associated portal and are solid (as in a player would get stuck in them)
class CPortalCollideableEnumerator : public IPartitionEnumerator
{
private:
EHANDLE m_hTestPortal; //the associated portal that we only want objects in front of
Vector m_vPlaneNormal; //portal plane normal
float m_fPlaneDist; //plane equation distance
Vector m_ptForward1000; //a point exactly 1000 units from the portal center along its forward vector
public:
IHandleEntity *m_pHandles[1024];
int m_iHandleCount;
CPortalCollideableEnumerator( const CProp_Portal *pAssociatedPortal );
virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity );
};
#endif //#ifndef PORTAL_COLLIDEABLE_ENUMERATOR_H
+21
View File
@@ -0,0 +1,21 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Holds the CPortalGameAccount object
//
// $NoKeywords: $
//=============================================================================//
#include "gcsdk/schemasharedobject.h"
//---------------------------------------------------------------------------------
// Purpose: All the account-level information that the GC tracks for TF
//---------------------------------------------------------------------------------
class CPortalGameAccount : public GCSDK::CSchemaSharedObject< CSchGameAccount >
{
public:
CPortalGameAccount() : GCSDK::CSchemaSharedObject< CSchGameAccount >() {}
CPortalGameAccount( uint32 unAccountID ) : GCSDK::CSchemaSharedObject< CSchGameAccount >()
{
Obj().m_unAccountID = unAccountID;
}
};
@@ -0,0 +1,25 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Holds the CPortalGameAccount object
//
// $NoKeywords: $
//=============================================================================//
#ifdef USE_GC_IN_PORTAL1
#include "gcsdk/schemasharedobject.h"
//---------------------------------------------------------------------------------
// Purpose: All the account-level information that the GC tracks for Portal
//---------------------------------------------------------------------------------
class CPortalGameAccountClient : public GCSDK::CSchemaSharedObject< CSchGameAccountClient >
{
public:
CPortalGameAccountClient() : GCSDK::CSchemaSharedObject< CSchGameAccountClient >() {}
CPortalGameAccountClient( uint32 unAccountID ) : GCSDK::CSchemaSharedObject< CSchGameAccountClient >()
{
Obj().m_unAccountID = unAccountID;
}
};
#endif //#ifdef USE_GC_IN_PORTAL1
+752
View File
@@ -0,0 +1,752 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Special handling for Portal usable ladders
//
//=============================================================================//
#include "cbase.h"
#include "hl_gamemovement.h"
#include "in_buttons.h"
#include "utlrbtree.h"
#include "movevars_shared.h"
#include "portal_shareddefs.h"
#include "portal_collideable_enumerator.h"
#include "prop_portal_shared.h"
#include "rumble_shared.h"
#if defined( CLIENT_DLL )
#include "c_portal_player.h"
#include "c_rumble.h"
#else
#include "portal_player.h"
#include "env_player_surface_trigger.h"
#include "portal_gamestats.h"
#include "physicsshadowclone.h"
#include "recipientfilter.h"
#include "SoundEmitterSystem/isoundemittersystembase.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
ConVar sv_player_trace_through_portals("sv_player_trace_through_portals", "1", FCVAR_REPLICATED | FCVAR_CHEAT, "Causes player movement traces to trace through portals." );
ConVar sv_player_funnel_into_portals("sv_player_funnel_into_portals", "1", FCVAR_REPLICATED | FCVAR_ARCHIVE | FCVAR_ARCHIVE_XBOX, "Causes the player to auto correct toward the center of floor portals." );
class CReservePlayerSpot;
#define PORTAL_FUNNEL_AMOUNT 6.0f
extern bool g_bAllowForcePortalTrace;
extern bool g_bForcePortalTrace;
static inline CBaseEntity *TranslateGroundEntity( CBaseEntity *pGroundEntity )
{
#ifndef CLIENT_DLL
CPhysicsShadowClone *pClone = dynamic_cast<CPhysicsShadowClone *>(pGroundEntity);
if( pClone && pClone->IsUntransformedClone() )
{
CBaseEntity *pSource = pClone->GetClonedEntity();
if( pSource )
return pSource;
}
#endif //#ifndef CLIENT_DLL
return pGroundEntity;
}
//-----------------------------------------------------------------------------
// Purpose: Portal specific movement code
//-----------------------------------------------------------------------------
class CPortalGameMovement : public CHL2GameMovement
{
typedef CGameMovement BaseClass;
public:
CPortalGameMovement();
bool m_bInPortalEnv;
// Overrides
virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMove );
virtual bool CheckJumpButton( void );
void FunnelIntoPortal( CProp_Portal *pPortal, Vector &wishdir );
virtual void AirAccelerate( Vector& wishdir, float wishspeed, float accel );
virtual void AirMove( void );
virtual void PlayerRoughLandingEffects( float fvol );
virtual void CategorizePosition( void );
// Traces the player bbox as it is swept from start to end
virtual void TracePlayerBBox( const Vector& start, const Vector& end, unsigned int fMask, int collisionGroup, trace_t& pm );
// Tests the player position
virtual CBaseHandle TestPlayerPosition( const Vector& pos, int collisionGroup, trace_t& pm );
virtual void Duck( void ); // Check for a forced duck
virtual int CheckStuck( void );
virtual void SetGroundEntity( trace_t *pm );
private:
CPortal_Player *GetPortalPlayer();
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CPortalGameMovement::CPortalGameMovement()
{
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
inline CPortal_Player *CPortalGameMovement::GetPortalPlayer()
{
return static_cast< CPortal_Player * >( player );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pMove -
//-----------------------------------------------------------------------------
void CPortalGameMovement::ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMove )
{
Assert( pMove && pPlayer );
float flStoreFrametime = gpGlobals->frametime;
//!!HACK HACK: Adrian - slow down all player movement by this factor.
//!!Blame Yahn for this one.
gpGlobals->frametime *= pPlayer->GetLaggedMovementValue();
ResetGetPointContentsCache();
// Cropping movement speed scales mv->m_fForwardSpeed etc. globally
// Once we crop, we don't want to recursively crop again, so we set the crop
// flag globally here once per usercmd cycle.
m_iSpeedCropped = SPEED_CROPPED_RESET;
player = pPlayer;
mv = pMove;
mv->m_flMaxSpeed = sv_maxspeed.GetFloat();
m_bInPortalEnv = (((CPortal_Player *)pPlayer)->m_hPortalEnvironment != NULL);
g_bAllowForcePortalTrace = m_bInPortalEnv;
g_bForcePortalTrace = m_bInPortalEnv;
// Run the command.
PlayerMove();
FinishMove();
g_bAllowForcePortalTrace = false;
g_bForcePortalTrace = false;
#ifndef CLIENT_DLL
pPlayer->UnforceButtons( IN_DUCK );
pPlayer->UnforceButtons( IN_JUMP );
#endif
//This is probably not needed, but just in case.
gpGlobals->frametime = flStoreFrametime;
}
//-----------------------------------------------------------------------------
// Purpose: Base jump behavior, plus an anim event
// Input : -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CPortalGameMovement::CheckJumpButton()
{
if ( BaseClass::CheckJumpButton() && GetPortalPlayer() )
{
GetPortalPlayer()->DoAnimationEvent( PLAYERANIMEVENT_JUMP, 0 );
return true;
}
return false;
}
void CPortalGameMovement::FunnelIntoPortal( CProp_Portal *pPortal, Vector &wishdir )
{
// Make sure there's a portal
if ( !pPortal )
return;
// Get portal vectors
Vector vPortalForward, vPortalRight, vPortalUp;
pPortal->GetVectors( &vPortalForward, &vPortalRight, &vPortalUp );
// Make sure it's a floor portal
if ( vPortalForward.z < 0.8f )
return;
vPortalRight.z = 0.0f;
vPortalUp.z = 0.0f;
VectorNormalize( vPortalRight );
VectorNormalize( vPortalUp );
// Make sure the player is looking downward
CPortal_Player *pPlayer = GetPortalPlayer();
Vector vPlayerForward;
pPlayer->EyeVectors( &vPlayerForward );
if ( vPlayerForward.z > -0.1f )
return;
Vector vPlayerOrigin = pPlayer->GetAbsOrigin();
Vector vPlayerToPortal = pPortal->GetAbsOrigin() - vPlayerOrigin;
// Make sure the player is trying to air control, they're falling downward and they are vertically close to the portal
if ( fabsf( wishdir[ 0 ] ) > 64.0f || fabsf( wishdir[ 1 ] ) > 64.0f || mv->m_vecVelocity[ 2 ] > -165.0f || vPlayerToPortal.z < -512.0f )
return;
// Make sure we're in the 2D portal rectangle
if ( ( vPlayerToPortal.Dot( vPortalRight ) * vPortalRight ).Length() > PORTAL_HALF_WIDTH * 1.5f )
return;
if ( ( vPlayerToPortal.Dot( vPortalUp ) * vPortalUp ).Length() > PORTAL_HALF_HEIGHT * 1.5f )
return;
if ( vPlayerToPortal.z > -8.0f )
{
// We're too close the the portal to continue correcting, but zero the velocity so our fling velocity is nice
mv->m_vecVelocity[ 0 ] = 0.0f;
mv->m_vecVelocity[ 1 ] = 0.0f;
}
else
{
// Funnel toward the portal
float fFunnelX = vPlayerToPortal.x * PORTAL_FUNNEL_AMOUNT - mv->m_vecVelocity[ 0 ];
float fFunnelY = vPlayerToPortal.y * PORTAL_FUNNEL_AMOUNT - mv->m_vecVelocity[ 1 ];
wishdir[ 0 ] += fFunnelX;
wishdir[ 1 ] += fFunnelY;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : wishdir -
// accel -
//-----------------------------------------------------------------------------
void CPortalGameMovement::AirAccelerate( Vector& wishdir, float wishspeed, float accel )
{
int i;
float addspeed, accelspeed, currentspeed;
float wishspd;
wishspd = wishspeed;
if (player->pl.deadflag)
return;
if (player->m_flWaterJumpTime)
return;
// Cap speed
if (wishspd > 60.0f)
wishspd = 60.0f;
// Determine veer amount
currentspeed = mv->m_vecVelocity.Dot(wishdir);
// See how much to add
addspeed = wishspd - currentspeed;
// If not adding any, done.
if (addspeed <= 0)
return;
// Determine acceleration speed after acceleration
accelspeed = accel * wishspeed * gpGlobals->frametime * player->m_surfaceFriction;
// Cap it
if (accelspeed > addspeed)
accelspeed = addspeed;
// Adjust pmove vel.
for (i=0 ; i<3 ; i++)
{
mv->m_vecVelocity[i] += accelspeed * wishdir[i];
mv->m_outWishVel[i] += accelspeed * wishdir[i];
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPortalGameMovement::AirMove( void )
{
int i;
Vector wishvel;
float fmove, smove;
Vector wishdir;
float wishspeed;
Vector forward, right, up;
AngleVectors (mv->m_vecViewAngles, &forward, &right, &up); // Determine movement angles
// Copy movement amounts
fmove = mv->m_flForwardMove;
smove = mv->m_flSideMove;
// Zero out z components of movement vectors
forward[2] = 0;
right[2] = 0;
VectorNormalize(forward); // Normalize remainder of vectors
VectorNormalize(right); //
for (i=0 ; i<2 ; i++) // Determine x and y parts of velocity
wishvel[i] = forward[i]*fmove + right[i]*smove;
wishvel[2] = 0; // Zero out z part of velocity
VectorCopy (wishvel, wishdir); // Determine maginitude of speed of move
//
// Don't let the player screw their fling because of adjusting into a floor portal
//
if ( mv->m_vecVelocity[ 0 ] * mv->m_vecVelocity[ 0 ] + mv->m_vecVelocity[ 1 ] * mv->m_vecVelocity[ 1 ] > MIN_FLING_SPEED * MIN_FLING_SPEED )
{
if ( mv->m_vecVelocity[ 0 ] > MIN_FLING_SPEED * 0.5f && wishdir[ 0 ] < 0.0f )
wishdir[ 0 ] = 0.0f;
else if ( mv->m_vecVelocity[ 0 ] < -MIN_FLING_SPEED * 0.5f && wishdir[ 0 ] > 0.0f )
wishdir[ 0 ] = 0.0f;
if ( mv->m_vecVelocity[ 1 ] > MIN_FLING_SPEED * 0.5f && wishdir[ 1 ] < 0.0f )
wishdir[ 1 ] = 0.0f;
else if ( mv->m_vecVelocity[ 1 ] < -MIN_FLING_SPEED * 0.5f && wishdir[ 1 ] > 0.0f )
wishdir[ 1 ] = 0.0f;
}
//
// Try to autocorrect the player to fall into the middle of the portal
//
else if ( sv_player_funnel_into_portals.GetBool() )
{
int iPortalCount = CProp_Portal_Shared::AllPortals.Count();
if( iPortalCount != 0 )
{
CProp_Portal **pPortals = CProp_Portal_Shared::AllPortals.Base();
for( int i = 0; i != iPortalCount; ++i )
{
CProp_Portal *pTempPortal = pPortals[i];
if( pTempPortal->IsActivedAndLinked() )
{
FunnelIntoPortal( pTempPortal, wishdir );
}
}
}
}
wishspeed = VectorNormalize(wishdir);
//
// clamp to server defined max speed
//
if ( wishspeed != 0 && (wishspeed > mv->m_flMaxSpeed))
{
VectorScale (wishvel, mv->m_flMaxSpeed/wishspeed, wishvel);
wishspeed = mv->m_flMaxSpeed;
}
AirAccelerate( wishdir, wishspeed, 15.0f );
// Add in any base velocity to the current velocity.
VectorAdd(mv->m_vecVelocity, player->GetBaseVelocity(), mv->m_vecVelocity );
TryPlayerMove();
// Now pull the base velocity back out. Base velocity is set if you are on a moving object, like a conveyor (or maybe another monster?)
VectorSubtract( mv->m_vecVelocity, player->GetBaseVelocity(), mv->m_vecVelocity );
}
void CPortalGameMovement::PlayerRoughLandingEffects( float fvol )
{
BaseClass::PlayerRoughLandingEffects( fvol );
#ifndef CLIENT_DLL
if ( fvol >= 1.0 )
{
// Play the future shoes sound
CRecipientFilter filter;
filter.AddRecipientsByPAS( player->GetAbsOrigin() );
CSoundParameters params;
if ( CBaseEntity::GetParametersForSound( "PortalPlayer.FallRecover", params, NULL ) )
{
EmitSound_t ep( params );
ep.m_nPitch = 125.0f - player->m_Local.m_flFallVelocity * 0.03f; // lower pitch the harder they land
ep.m_flVolume = MIN( player->m_Local.m_flFallVelocity * 0.00075f - 0.38, 1.0f ); // louder the harder they land
CBaseEntity::EmitSound( filter, player->entindex(), ep );
}
}
#endif
}
void TracePlayerBBoxForGround2( const Vector& start, const Vector& end, const Vector& minsSrc,
const Vector& maxsSrc, IHandleEntity *player, unsigned int fMask,
int collisionGroup, trace_t& pm )
{
VPROF( "TracePlayerBBoxForGround" );
CPortal_Player *pPortalPlayer = dynamic_cast<CPortal_Player *>(player->GetRefEHandle().Get());
CProp_Portal *pPlayerPortal = pPortalPlayer->m_hPortalEnvironment;
#ifndef CLIENT_DLL
if( pPlayerPortal && pPlayerPortal->m_PortalSimulator.IsReadyToSimulate() == false )
pPlayerPortal = NULL;
#endif
Ray_t ray;
Vector mins, maxs;
float fraction = pm.fraction;
Vector endpos = pm.endpos;
// Check the -x, -y quadrant
mins = minsSrc;
maxs.Init( MIN( 0, maxsSrc.x ), MIN( 0, maxsSrc.y ), maxsSrc.z );
ray.Init( start, end, mins, maxs );
if( pPlayerPortal )
UTIL_Portal_TraceRay( pPlayerPortal, ray, fMask, player, collisionGroup, &pm );
else
UTIL_TraceRay( ray, fMask, player, collisionGroup, &pm );
if ( pm.m_pEnt && pm.plane.normal[2] >= 0.7)
{
pm.fraction = fraction;
pm.endpos = endpos;
return;
}
// Check the +x, +y quadrant
mins.Init( MAX( 0, minsSrc.x ), MAX( 0, minsSrc.y ), minsSrc.z );
maxs = maxsSrc;
ray.Init( start, end, mins, maxs );
if( pPlayerPortal )
UTIL_Portal_TraceRay( pPlayerPortal, ray, fMask, player, collisionGroup, &pm );
else
UTIL_TraceRay( ray, fMask, player, collisionGroup, &pm );
if ( pm.m_pEnt && pm.plane.normal[2] >= 0.7)
{
pm.fraction = fraction;
pm.endpos = endpos;
return;
}
// Check the -x, +y quadrant
mins.Init( minsSrc.x, MAX( 0, minsSrc.y ), minsSrc.z );
maxs.Init( MIN( 0, maxsSrc.x ), maxsSrc.y, maxsSrc.z );
ray.Init( start, end, mins, maxs );
if( pPlayerPortal )
UTIL_Portal_TraceRay( pPlayerPortal, ray, fMask, player, collisionGroup, &pm );
else
UTIL_TraceRay( ray, fMask, player, collisionGroup, &pm );
if ( pm.m_pEnt && pm.plane.normal[2] >= 0.7)
{
pm.fraction = fraction;
pm.endpos = endpos;
return;
}
// Check the +x, -y quadrant
mins.Init( MAX( 0, minsSrc.x ), minsSrc.y, minsSrc.z );
maxs.Init( maxsSrc.x, MIN( 0, maxsSrc.y ), maxsSrc.z );
ray.Init( start, end, mins, maxs );
if( pPlayerPortal )
UTIL_Portal_TraceRay( pPlayerPortal, ray, fMask, player, collisionGroup, &pm );
else
UTIL_TraceRay( ray, fMask, player, collisionGroup, &pm );
if ( pm.m_pEnt && pm.plane.normal[2] >= 0.7)
{
pm.fraction = fraction;
pm.endpos = endpos;
return;
}
pm.fraction = fraction;
pm.endpos = endpos;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &input -
//-----------------------------------------------------------------------------
void CPortalGameMovement::CategorizePosition( void )
{
Vector point;
trace_t pm;
// if the player hull point one unit down is solid, the player
// is on ground
// see if standing on something solid
// Doing this before we move may introduce a potential latency in water detection, but
// doing it after can get us stuck on the bottom in water if the amount we move up
// is less than the 1 pixel 'threshold' we're about to snap to. Also, we'll call
// this several times per frame, so we really need to avoid sticking to the bottom of
// water on each call, and the converse case will correct itself if called twice.
CheckWater();
// observers don't have a ground entity
if ( player->IsObserver() )
return;
point[0] = mv->GetAbsOrigin()[0];
point[1] = mv->GetAbsOrigin()[1];
point[2] = mv->GetAbsOrigin()[2] - 2;
Vector bumpOrigin;
bumpOrigin = mv->GetAbsOrigin();
// Shooting up really fast. Definitely not on ground.
// On ladder moving up, so not on ground either
// NOTE: 145 is a jump.
if ( mv->m_vecVelocity[2] > 140 ||
( mv->m_vecVelocity[2] > 0.0f && player->GetMoveType() == MOVETYPE_LADDER ) )
{
SetGroundEntity( NULL );
}
else
{
// Try and move down.
TracePlayerBBox( bumpOrigin, point, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm );
// If we hit a steep plane, we are not on ground
if ( pm.plane.normal[2] < 0.7)
{
// Test four sub-boxes, to see if any of them would have found shallower slope we could
// actually stand on
TracePlayerBBoxForGround2( bumpOrigin, point, GetPlayerMins(), GetPlayerMaxs(), mv->m_nPlayerHandle.Get(), MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, pm );
if ( pm.plane.normal[2] < 0.7)
{
SetGroundEntity( NULL ); // too steep
// probably want to add a check for a +z velocity too!
if ( ( mv->m_vecVelocity.z > 0.0f ) && ( player->GetMoveType() != MOVETYPE_NOCLIP ) )
{
player->m_surfaceFriction = 0.25f;
}
}
else
{
SetGroundEntity( &pm ); // Otherwise, point to index of ent under us.
}
}
else
{
SetGroundEntity( &pm ); // Otherwise, point to index of ent under us.
}
// If we are on something...
if (player->GetGroundEntity() != NULL)
{
// Then we are not in water jump sequence
player->m_flWaterJumpTime = 0;
// If we could make the move, drop us down that 1 pixel
if ( player->GetWaterLevel() < WL_Waist && !pm.startsolid && !pm.allsolid )
{
// check distance we would like to move -- this is supposed to just keep up
// "on the ground" surface not stap us back to earth (i.e. on move origin to
// end position when the ground is within .5 units away) (2 units)
if( pm.fraction )
// if( pm.fraction < 0.5)
{
mv->SetAbsOrigin( pm.endpos );
}
}
}
#ifndef CLIENT_DLL
//Adrian: vehicle code handles for us.
if ( player->IsInAVehicle() == false )
{
// If our gamematerial has changed, tell any player surface triggers that are watching
IPhysicsSurfaceProps *physprops = MoveHelper()->GetSurfaceProps();
surfacedata_t *pSurfaceProp = physprops->GetSurfaceData( pm.surface.surfaceProps );
char cCurrGameMaterial = pSurfaceProp->game.material;
if ( !player->GetGroundEntity() )
{
cCurrGameMaterial = 0;
}
// Changed?
if ( player->m_chPreviousTextureType != cCurrGameMaterial )
{
CEnvPlayerSurfaceTrigger::SetPlayerSurface( player, cCurrGameMaterial );
}
player->m_chPreviousTextureType = cCurrGameMaterial;
}
#endif
}
}
void CPortalGameMovement::Duck( void )
{
return BaseClass::Duck();
}
int CPortalGameMovement::CheckStuck( void )
{
if( BaseClass::CheckStuck() )
{
CPortal_Player *pPortalPlayer = GetPortalPlayer();
#ifndef CLIENT_DLL
if( pPortalPlayer->IsAlive() )
g_PortalGameStats.Event_PlayerStuck( pPortalPlayer );
#endif
//try to fix it, then recheck
Vector vIndecisive;
if( pPortalPlayer->m_hPortalEnvironment )
{
pPortalPlayer->m_hPortalEnvironment->GetVectors( &vIndecisive, NULL, NULL );
}
else
{
vIndecisive.Init( 0.0f, 0.0f, 1.0f );
}
Vector ptOldOrigin = pPortalPlayer->GetAbsOrigin();
if( pPortalPlayer->m_hPortalEnvironment )
{
if( !FindClosestPassableSpace( pPortalPlayer, vIndecisive ) )
{
#ifndef CLIENT_DLL
DevMsg( "Hurting the player for FindClosestPassableSpaceFailure!" );
CTakeDamageInfo info( pPortalPlayer, pPortalPlayer, vec3_origin, vec3_origin, 1e10, DMG_CRUSH );
pPortalPlayer->OnTakeDamage( info );
#endif
}
//make sure we didn't get put behind the portal >_<
Vector ptCurrentOrigin = pPortalPlayer->GetAbsOrigin();
if( vIndecisive.Dot( ptCurrentOrigin - ptOldOrigin ) < 0.0f )
{
pPortalPlayer->SetAbsOrigin( ptOldOrigin + (vIndecisive * 5.0f) ); //this is an anti-bug hack, since this would have probably popped them out of the world, we're just going to move them forward a few units
}
}
mv->SetAbsOrigin( pPortalPlayer->GetAbsOrigin() );
return BaseClass::CheckStuck();
}
else
{
return 0;
}
}
void CPortalGameMovement::SetGroundEntity( trace_t *pm )
{
#ifndef CLIENT_DLL
if ( !player->GetGroundEntity() && pm && pm->m_pEnt )
{
IGameEvent *event = gameeventmanager->CreateEvent( "portal_player_touchedground" );
if ( event )
{
event->SetInt( "userid", player->GetUserID() );
gameeventmanager->FireEvent( event );
}
}
#endif
BaseClass::SetGroundEntity( pm );
}
void CPortalGameMovement::TracePlayerBBox( const Vector& start, const Vector& end, unsigned int fMask, int collisionGroup, trace_t& pm )
{
VPROF( "CGameMovement::TracePlayerBBox" );
CPortal_Player *pPortalPlayer = (CPortal_Player *)((CBaseEntity *)mv->m_nPlayerHandle.Get());
Ray_t ray;
ray.Init( start, end, GetPlayerMins(), GetPlayerMaxs() );
#ifdef CLIENT_DLL
CTraceFilterSimple traceFilter( mv->m_nPlayerHandle.Get(), collisionGroup );
#else
CTraceFilterSimple baseFilter( mv->m_nPlayerHandle.Get(), collisionGroup );
CTraceFilterTranslateClones traceFilter( &baseFilter );
#endif
UTIL_Portal_TraceRay_With( pPortalPlayer->m_hPortalEnvironment, ray, fMask, &traceFilter, &pm );
// If we're moving through a portal and failed to hit anything with the above ray trace
// Use UTIL_Portal_TraceEntity to test this movement through a portal and override the trace with the result
if ( pm.fraction == 1.0f && UTIL_DidTraceTouchPortals( ray, pm ) && sv_player_trace_through_portals.GetBool() )
{
trace_t tempTrace;
UTIL_Portal_TraceEntity( pPortalPlayer, start, end, fMask, &traceFilter, &tempTrace );
if ( tempTrace.DidHit() && tempTrace.fraction < pm.fraction && !tempTrace.startsolid && !tempTrace.allsolid )
{
pm = tempTrace;
}
}
}
CBaseHandle CPortalGameMovement::TestPlayerPosition( const Vector& pos, int collisionGroup, trace_t& pm )
{
TracePlayerBBox( pos, pos, MASK_PLAYERSOLID, collisionGroup, pm ); //hook into the existing portal special trace functionality
//Ray_t ray;
//ray.Init( pos, pos, GetPlayerMins(), GetPlayerMaxs() );
//UTIL_TraceRay( ray, MASK_PLAYERSOLID, mv->m_nPlayerHandle.Get(), collisionGroup, &pm );
if( pm.startsolid && pm.m_pEnt && (pm.contents & MASK_PLAYERSOLID) )
{
#ifdef _DEBUG
AssertMsgOnce( false, "The player got stuck on something. Break to investigate." ); //happens enough to just leave in a perma-debugger
//this next trace is PURELY for tracking down how the player got stuck. Nothing new is discovered over the same trace about 10 lines up
TracePlayerBBox( pos, pos, MASK_PLAYERSOLID, collisionGroup, pm );
#endif
return pm.m_pEnt->GetRefEHandle();
}
#ifndef CLIENT_DLL
else if ( pm.startsolid && pm.m_pEnt && CPSCollisionEntity::IsPortalSimulatorCollisionEntity( pm.m_pEnt ) )
{
// Stuck in a portal environment object, so unstick them!
CPortal_Player *pPortalPlayer = (CPortal_Player *)((CBaseEntity *)mv->m_nPlayerHandle.Get());
pPortalPlayer->SetStuckOnPortalCollisionObject();
return INVALID_EHANDLE_INDEX;
}
#endif
else
{
return INVALID_EHANDLE_INDEX;
}
}
// Expose our interface.
static CPortalGameMovement g_GameMovement;
IGameMovement *g_pGameMovement = ( IGameMovement * )&g_GameMovement;
EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CGameMovement, IGameMovement,INTERFACENAME_GAMEMOVEMENT, g_GameMovement );
File diff suppressed because it is too large Load Diff
+116
View File
@@ -0,0 +1,116 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Game rules for Portal.
//
//=============================================================================//
#ifdef PORTAL_MP
#include "portal_mp_gamerules.h" //redirect to multiplayer gamerules in multiplayer builds
#else
#ifndef PORTAL_GAMERULES_H
#define PORTAL_GAMERULES_H
#ifdef _WIN32
#pragma once
#endif
#include "gamerules.h"
#include "hl2_gamerules.h"
#ifdef CLIENT_DLL
#define CPortalGameRules C_PortalGameRules
#define CPortalGameRulesProxy C_PortalGameRulesProxy
#endif
#if defined ( CLIENT_DLL )
#include "steam/steam_api.h"
#endif
class CPortalGameRulesProxy : public CGameRulesProxy
{
public:
DECLARE_CLASS( CPortalGameRulesProxy, CGameRulesProxy );
DECLARE_NETWORKCLASS();
};
class CPortalGameRules : public CHalfLife2
{
public:
DECLARE_CLASS( CPortalGameRules, CSingleplayRules );
virtual bool Init();
virtual bool ShouldCollide( int collisionGroup0, int collisionGroup1 );
virtual bool ShouldUseRobustRadiusDamage(CBaseEntity *pEntity);
#ifndef CLIENT_DLL
virtual bool ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target );
virtual float GetAutoAimScale( CBasePlayer *pPlayer );
#endif
#ifdef CLIENT_DLL
virtual bool IsBonusChallengeTimeBased( void );
#endif
private:
// Rules change for the mega physgun
CNetworkVar( bool, m_bMegaPhysgun );
#ifdef CLIENT_DLL
DECLARE_CLIENTCLASS_NOBASE(); // This makes datatables able to access our private vars.
#else
DECLARE_SERVERCLASS_NOBASE(); // This makes datatables able to access our private vars.
CPortalGameRules();
virtual ~CPortalGameRules() {}
virtual void Think( void );
virtual bool ClientCommand( CBaseEntity *pEdict, const CCommand &args );
virtual void PlayerSpawn( CBasePlayer *pPlayer );
virtual void InitDefaultAIRelationships( void );
virtual const char* AIClassText(int classType);
virtual const char *GetGameDescription( void ) { return "Portal"; }
// Ammo
virtual void PlayerThink( CBasePlayer *pPlayer );
virtual float GetAmmoDamage( CBaseEntity *pAttacker, CBaseEntity *pVictim, int nAmmoType );
virtual bool ShouldBurningPropsEmitLight();
bool ShouldRemoveRadio( void );
public:
virtual float FlPlayerFallDamage( CBasePlayer *pPlayer );
bool MegaPhyscannonActive( void ) { return m_bMegaPhysgun; }
private:
int DefaultFOV( void ) { return 75; }
#endif
};
//-----------------------------------------------------------------------------
// Gets us at the Half-Life 2 game rules
//-----------------------------------------------------------------------------
inline CPortalGameRules* PortalGameRules()
{
return static_cast<CPortalGameRules*>(g_pGameRules);
}
#endif // PORTAL_GAMERULES_H
#endif
+28
View File
@@ -0,0 +1,28 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Provides names for GC message types for Portal
//
//=============================================================================
#include "cbase.h"
#ifdef USE_GC_IN_PORTAL1
#include "gcsdk/gcsdk.h"
#include "portal_gcmessages.h"
//-----------------------------------------------------------------------------
// Purpose: A big array of message types for keeping track of their names
//-----------------------------------------------------------------------------
GCSDK::MsgInfo_t g_MsgInfo[] =
{
DECLARE_GC_MSG( k_EMsgGCReportWarKill ),
DECLARE_GC_MSG( k_EMsgGCDev_GrantWarKill ),
};
void InitGCPortalMessageTypes()
{
static GCSDK::CMessageListRegistration m_reg( g_MsgInfo, Q_ARRAYSIZE(g_MsgInfo) );
}
#endif //#ifdef USE_GC_IN_PORTAL1
+28
View File
@@ -0,0 +1,28 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: This file defines all of our over-the-wire net protocols for the
// Game Coordinator for Portal. Note that we never use types
// with undefined length (like int). Always use an explicit type
// (like int32).
//
//=============================================================================
#ifndef PORTAL_GCMESSAGES_H
#define PORTAL_GCMESSAGES_H
#ifdef _WIN32
#pragma once
#endif
enum EGCMsg
{
k_EMsgGCPortalBase = 5000,
k_EMsgGCReportWarKill = k_EMsgGCPortalBase + 1, //War kill tracking. No longer in use
// Development only messages
k_EMsgGCPortalDEVBase = 6000,
k_EMsgGCDev_GrantWarKill = k_EMsgGCPortalDEVBase + 1, //War kill tracking. No longer in use
};
#endif
+78
View File
@@ -0,0 +1,78 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// -------------------------------------------------------
// DO NOT EDIT
// This file was generated from portal\portal_gcschema.sch by SchemaCompiler.EXE
// on Mon Feb 22 13:22:55 2010
// -------------------------------------------------------
#include "cbase.h"
#include "portal_gcschema.h"
CSchGameAccount::CSchGameAccount()
{
memset( PubRecordFixed(), 0, CubRecordFixed() );
}
int CSchGameAccount::GetITable() const { return k_iTable; }
CSchGameAccount::CSchGameAccount( const CSchGameAccount &that ) { *this = that; }
void CSchGameAccount::operator=( const CSchGameAccount &that ) { CRecordBase::operator =( that ); }
CSchGameAccountClient::CSchGameAccountClient()
{
memset( PubRecordFixed(), 0, CubRecordFixed() );
}
int CSchGameAccountClient::GetITable() const { return k_iTable; }
CSchGameAccountClient::CSchGameAccountClient( const CSchGameAccountClient &that ) { *this = that; }
void CSchGameAccountClient::operator=( const CSchGameAccountClient &that ) { CRecordBase::operator =( that ); }
// statics for index IDs
int CSchGameAccount::m_nPrimaryKeyID;
int CSchGameAccountClient::m_nPrimaryKeyID;
// other initializers
// run-time initializer
namespace PORTAL_GCSCHEMA
{
void GenerateIntrinsicSQLSchema( GCSDK::CSchemaFull &schemaFull )
{
GCSDK::CSchema *pSchema;
pSchema = schemaFull.AddNewSchema();
schemaFull.SetITable( pSchema, CSchGameAccount::k_iTable ); // 0
pSchema->SetESchemaCatalog( GCSDK::k_ESchemaCatalogMain );
pSchema->SetName( "GameAccount" );
pSchema->EnsureFieldCount( CSchGameAccount::k_iFieldMax );
pSchema->SetReportingInterval( 0 );
pSchema->AddField( "unAccountID", "AccountID", k_EGCSQLType_int32, sizeof( uint32 ), 0, true, 0 );
pSchema->AddField( "unRewardPoints", "RewardPoints", k_EGCSQLType_int32, sizeof( uint32 ), 0, true, 0 );
pSchema->AddField( "unPointCap", "PointCap", k_EGCSQLType_int32, sizeof( uint32 ), 0, true, 0 );
pSchema->AddField( "unLastCapRollover", "LastCapRollover", k_EGCSQLType_int32, sizeof( RTime32 ), 0, true, 0 );
CSchGameAccount::m_nPrimaryKeyID = pSchema->PrimaryKey( true, 100, "unAccountID" );
pSchema->SetTestWipePolicy( GCSDK::k_EWipePolicyWipeForAllTests );
pSchema->SetBAllowWipeTableInProd( false );
pSchema->CalcOffsets();
schemaFull.CheckSchema( pSchema, CSchGameAccount::k_iFieldMax, sizeof( CSchGameAccount ) - sizeof( GCSDK::CRecordBase ) );
pSchema->PrepareForUse();
pSchema = schemaFull.AddNewSchema();
schemaFull.SetITable( pSchema, CSchGameAccountClient::k_iTable ); // 1
pSchema->SetESchemaCatalog( GCSDK::k_ESchemaCatalogMain );
pSchema->SetName( "GameAccountClient" );
pSchema->EnsureFieldCount( CSchGameAccountClient::k_iFieldMax );
pSchema->SetReportingInterval( 0 );
pSchema->AddField( "unAccountID", "AccountID", k_EGCSQLType_int32, sizeof( uint32 ), 0, true, 0 );
CSchGameAccountClient::m_nPrimaryKeyID = pSchema->PrimaryKey( true, 80, "unAccountID" );
pSchema->SetTestWipePolicy( GCSDK::k_EWipePolicyWipeForAllTests );
pSchema->SetBAllowWipeTableInProd( false );
pSchema->CalcOffsets();
schemaFull.CheckSchema( pSchema, CSchGameAccountClient::k_iFieldMax, sizeof( CSchGameAccountClient ) - sizeof( GCSDK::CRecordBase ) );
pSchema->PrepareForUse();
schemaFull.FinishInit();
}
} // namespace
+80
View File
@@ -0,0 +1,80 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// -------------------------------------------------------
// DO NOT EDIT
// This file was generated from portal\portal_gcschema.sch by SchemaCompiler.EXE
// on Mon Feb 22 13:22:55 2010
// -------------------------------------------------------
#ifndef PORTAL_GCSCHEMA_H
#define PORTAL_GCSCHEMA_H
#ifdef _WIN32
#pragma once
#endif
#include "gcsdk/gcschema.h"
#pragma pack(push, 1)
//-----------------------------------------------------------------------------
// GameAccount
//
//-----------------------------------------------------------------------------
class CSchGameAccount : public GCSDK::CRecordBase
{
public:
const static int k_iTable = 0;
CSchGameAccount();
int GetITable() const;
CSchGameAccount( const CSchGameAccount &that );
void operator=( const CSchGameAccount &that );
uint32 m_unAccountID; // Account ID of the user
uint32 m_unRewardPoints; // number of timed reward points (coplayed minutes) for this user
uint32 m_unPointCap; // Current maximum number of points
RTime32 m_unLastCapRollover; // Last time the player's cap was adjusted
static int m_nPrimaryKeyID;
const static int k_iField_unAccountID = 0;
const static int k_iField_unRewardPoints = 1;
const static int k_iField_unPointCap = 2;
const static int k_iField_unLastCapRollover = 3;
const static int k_iFieldMax = 4;
};
//-----------------------------------------------------------------------------
// GameAccountClient
//
//-----------------------------------------------------------------------------
class CSchGameAccountClient : public GCSDK::CRecordBase
{
public:
const static int k_iTable = 1;
CSchGameAccountClient();
int GetITable() const;
CSchGameAccountClient( const CSchGameAccountClient &that );
void operator=( const CSchGameAccountClient &that );
uint32 m_unAccountID; // Item Owner
static int m_nPrimaryKeyID;
const static int k_iField_unAccountID = 0;
const static int k_iFieldMax = 1;
};
namespace PORTAL_GCSCHEMA
{
// ITABLE_STATS_BEGIN is the number of the first stats table;
// this should be one more than the number of the last data table.
const int ITABLE_STATS_BEGIN = 2;
const int k_iTableStatsFirst = -1;
const int k_iTableStatsMax = -1;
const int NUM_BASE_STATS_TABLES = 0;
extern void GenerateIntrinsicSQLSchema( GCSDK::CSchemaFull &schemaFull );
}
#pragma pack(pop)
#endif // PORTAL_GCSCHEMA_H
+38
View File
@@ -0,0 +1,38 @@
START_SCHEMA( GC, cbase.h )
//-----------------------------------------------------------------------------
// GameAccount
//
//-----------------------------------------------------------------------------
START_TABLE( k_ESchemaCatalogMain, GameAccount, TABLE_PROP_NORMAL )
MEM_FIELD_BIN( unAccountID, AccountID, uint32 ) // Account ID of the user
MEM_FIELD_BIN( unRewardPoints, RewardPoints, uint32 ) // number of timed reward points (coplayed minutes) for this user
MEM_FIELD_BIN( unPointCap, PointCap, uint32 ) // Current maximum number of points
MEM_FIELD_BIN( unLastCapRollover, LastCapRollover, RTime32 ) // Last time the player's cap was adjusted
PRIMARY_KEY_CLUSTERED( 100, unAccountID )
WIPE_TABLE_BETWEEN_TESTS( k_EWipePolicyWipeForAllTests )
ALLOW_WIPE_TABLE_IN_PRODUCTION( false )
END_TABLE
//-----------------------------------------------------------------------------
// GameAccountClient
//
//-----------------------------------------------------------------------------
START_TABLE( k_ESchemaCatalogMain, GameAccountClient, TABLE_PROP_NORMAL )
MEM_FIELD_BIN( unAccountID, AccountID, uint32 ) // Item Owner
PRIMARY_KEY_CLUSTERED( 80, unAccountID )
WIPE_TABLE_BETWEEN_TESTS( k_EWipePolicyWipeForAllTests )
ALLOW_WIPE_TABLE_IN_PRODUCTION( false )
END_TABLE
// --------------------------------------------------------
// WARNING! All new tables need to be added to the end of the file
// if you expect to deploy the GC without deploying new clients.
// --------------------------------------------------------
// NEED A CARRIAGE RETURN HERE!
//-------------------------
File diff suppressed because it is too large Load Diff
+173
View File
@@ -0,0 +1,173 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Game rules for Portal multiplayer testing.
//
//=============================================================================//
#ifndef PORTAL_MP
#pragma message( __FILE__ "(" __LINE__AS_STRING ") : error custom: This file should not be included anywhere except in the portal multiplayer testing builds" )
#endif
#ifndef PORTAL_MP_GAMERULES_H
#define PORTAL_MP_GAMERULES_H
#ifdef _WIN32
#pragma once
#endif
#include "gamerules.h"
//#include "hl2mp_gamerules.h"
//#include "multiplay_gamerules.h"
#include "teamplay_gamerules.h"
class CPortal_Player;
#ifdef CLIENT_DLL
#define CPortalMPGameRules C_PortalMPGameRules
#define CPortalMPGameRulesProxy C_PortalMPGameRulesProxy
#endif
enum
{
TEAM_COMBINE = 2,
TEAM_REBELS,
};
class CPortalMPGameRulesProxy : public CGameRulesProxy
{
public:
DECLARE_CLASS( CPortalMPGameRulesProxy, CGameRulesProxy );
DECLARE_NETWORKCLASS();
};
class PortalMPViewVectors : public CViewVectors
{
public:
PortalMPViewVectors(
Vector vView,
Vector vHullMin,
Vector vHullMax,
Vector vDuckHullMin,
Vector vDuckHullMax,
Vector vDuckView,
Vector vObsHullMin,
Vector vObsHullMax,
Vector vDeadViewHeight,
Vector vCrouchTraceMin,
Vector vCrouchTraceMax ) :
CViewVectors(
vView,
vHullMin,
vHullMax,
vDuckHullMin,
vDuckHullMax,
vDuckView,
vObsHullMin,
vObsHullMax,
vDeadViewHeight )
{
m_vCrouchTraceMin = vCrouchTraceMin;
m_vCrouchTraceMax = vCrouchTraceMax;
}
Vector m_vCrouchTraceMin;
Vector m_vCrouchTraceMax;
};
class CPortalMPGameRules : public CTeamplayRules
{
public:
//DECLARE_CLASS( CPortalGameRules, CSingleplayRules );
//DECLARE_CLASS( CPortalGameRules, CMultiplayRules );
DECLARE_CLASS( CPortalMPGameRules, CTeamplayRules );
#ifdef CLIENT_DLL
DECLARE_CLIENTCLASS_NOBASE(); // This makes datatables able to access our private vars.
#else
DECLARE_SERVERCLASS_NOBASE(); // This makes datatables able to access our private vars.
#endif
CPortalMPGameRules( void );
virtual ~CPortalMPGameRules( void );
virtual void Precache( void );
virtual bool ShouldCollide( int collisionGroup0, int collisionGroup1 );
virtual bool ClientCommand( CBaseEntity *pEdict, const CCommand &args );
virtual float FlWeaponRespawnTime( CBaseCombatWeapon *pWeapon );
virtual float FlWeaponTryRespawn( CBaseCombatWeapon *pWeapon );
virtual Vector VecWeaponRespawnSpot( CBaseCombatWeapon *pWeapon );
virtual int WeaponShouldRespawn( CBaseCombatWeapon *pWeapon );
virtual void Think( void );
virtual void CreateStandardEntities( void );
virtual void ClientSettingsChanged( CBasePlayer *pPlayer );
virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget );
virtual void GoToIntermission( void );
virtual void DeathNotice( CBasePlayer *pVictim, const CTakeDamageInfo &info );
virtual const char *GetGameDescription( void );
// derive this function if you mod uses encrypted weapon info files
virtual const unsigned char *GetEncryptionKey( void ) { return (unsigned char *)"x9Ke0BY7"; }
virtual const CViewVectors* GetViewVectors() const;
const PortalMPViewVectors* GetPortalMPViewVectors() const;
float GetMapRemainingTime();
void CleanUpMap();
void CheckRestartGame();
void RestartGame();
#ifndef CLIENT_DLL
virtual Vector VecItemRespawnSpot( CItem *pItem );
virtual QAngle VecItemRespawnAngles( CItem *pItem );
virtual float FlItemRespawnTime( CItem *pItem );
virtual bool CanHavePlayerItem( CBasePlayer *pPlayer, CBaseCombatWeapon *pItem );
virtual bool FShouldSwitchWeapon( CBasePlayer *pPlayer, CBaseCombatWeapon *pWeapon );
void AddLevelDesignerPlacedObject( CBaseEntity *pEntity );
void RemoveLevelDesignerPlacedObject( CBaseEntity *pEntity );
void ManageObjectRelocation( void );
virtual float GetLaserTurretDamage( void );
virtual float GetLaserTurretMoveSpeed( void );
virtual float GetRocketTurretDamage( void );
#endif
virtual void ClientDisconnected( edict_t *pClient );
bool CheckGameOver( void );
bool IsIntermission( void );
void PlayerKilled( CBasePlayer *pVictim, const CTakeDamageInfo &info );
bool IsTeamplay( void ) { return m_bTeamPlayEnabled; }
void CheckAllPlayersReady( void );
private:
CNetworkVar( bool, m_bTeamPlayEnabled );
CNetworkVar( float, m_flGameStartTime );
CUtlVector<EHANDLE> m_hRespawnableItemsAndWeapons;
float m_tmNextPeriodicThink;
float m_flRestartGameTime;
bool m_bCompleteReset;
bool m_bAwaitingReadyRestart;
bool m_bHeardAllPlayersReady;
};
//-----------------------------------------------------------------------------
// Gets us at the Half-Life 2 game rules
//-----------------------------------------------------------------------------
inline CPortalMPGameRules* PortalMPGameRules()
{
return static_cast<CPortalMPGameRules*>(g_pGameRules);
}
inline CPortalMPGameRules* PortalGameRules()
{
return static_cast<CPortalMPGameRules*>(g_pGameRules);
}
#endif // PORTAL_MP_GAMERULES_H
+926
View File
@@ -0,0 +1,926 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#ifdef CLIENT_DLL
#include "c_portal_player.h"
#include "prediction.h"
#define CRecipientFilter C_RecipientFilter
#else
#include "portal_player.h"
#include "ai_basenpc.h"
#include "portal_gamestats.h"
#include "util.h"
#endif
#include "engine/IEngineSound.h"
#include "SoundEmitterSystem/isoundemittersystembase.h"
acttable_t unarmedActtable[] =
{
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_MELEE, false },
{ ACT_HL2MP_RUN, ACT_HL2MP_RUN_MELEE, false },
{ ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_MELEE, false },
{ ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_MELEE, false },
{ ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE, false },
{ ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_MELEE, false },
{ ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_MELEE, false },
};
const char *g_pszChellConcepts[] =
{
"CONCEPT_CHELL_IDLE",
"CONCEPT_CHELL_DEAD",
};
extern ConVar sv_footsteps;
extern ConVar sv_debug_player_use;
extern float IntervalDistance( float x, float x0, float x1 );
//-----------------------------------------------------------------------------
// Consider the weapon's built-in accuracy, this character's proficiency with
// the weapon, and the status of the target. Use this information to determine
// how accurately to shoot at the target.
//-----------------------------------------------------------------------------
Vector CPortal_Player::GetAttackSpread( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget )
{
if ( pWeapon )
return pWeapon->GetBulletSpread( WEAPON_PROFICIENCY_PERFECT );
return VECTOR_CONE_15DEGREES;
}
void CPortal_Player::GetStepSoundVelocities( float *velwalk, float *velrun )
{
// UNDONE: need defined numbers for run, walk, crouch, crouch run velocities!!!!
if ( ( GetFlags() & FL_DUCKING ) || ( GetMoveType() == MOVETYPE_LADDER ) )
{
*velwalk = 10; // These constants should be based on cl_movespeedkey * cl_forwardspeed somehow
*velrun = 60;
}
else
{
*velwalk = 90;
*velrun = 220;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : step -
// fvol -
// force - force sound to play
//-----------------------------------------------------------------------------
void CPortal_Player::PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force )
{
#ifndef CLIENT_DLL
IncrementStepsTaken();
#endif
BaseClass::PlayStepSound( vecOrigin, psurface, fvol, force );
}
Activity CPortal_Player::TranslateActivity( Activity baseAct, bool *pRequired /* = NULL */ )
{
Activity translated = baseAct;
if ( GetActiveWeapon() )
{
translated = GetActiveWeapon()->ActivityOverride( baseAct, pRequired );
}
else if ( unarmedActtable )
{
acttable_t *pTable = unarmedActtable;
int actCount = ARRAYSIZE(unarmedActtable);
for ( int i = 0; i < actCount; i++, pTable++ )
{
if ( baseAct == pTable->baseAct )
{
translated = (Activity)pTable->weaponAct;
}
}
}
else if (pRequired)
{
*pRequired = false;
}
return translated;
}
CWeaponPortalBase* CPortal_Player::GetActivePortalWeapon() const
{
CBaseCombatWeapon *pWeapon = GetActiveWeapon();
if ( pWeapon )
{
return dynamic_cast< CWeaponPortalBase* >( pWeapon );
}
else
{
return NULL;
}
}
CBaseEntity *CPortal_Player::FindUseEntity()
{
Vector forward, up;
EyeVectors( &forward, NULL, &up );
trace_t tr;
// Search for objects in a sphere (tests for entities that are not solid, yet still useable)
Vector searchCenter = EyePosition();
// NOTE: Some debris objects are useable too, so hit those as well
// A button, etc. can be made out of clip brushes, make sure it's +useable via a traceline, too.
int useableContents = MASK_SOLID | CONTENTS_DEBRIS | CONTENTS_PLAYERCLIP;
UTIL_TraceLine( searchCenter, searchCenter + forward * 1024, useableContents, this, COLLISION_GROUP_NONE, &tr );
// try the hit entity if there is one, or the ground entity if there isn't.
CBaseEntity *pNearest = NULL;
CBaseEntity *pObject = tr.m_pEnt;
// TODO: Removed because we no longer have ghost animatings. We may need similar code that clips rays against transformed objects.
//#ifndef CLIENT_DLL
// // Check for ghost animatings (these aren't hit in the normal trace because they aren't solid)
// if ( !IsUseableEntity(pObject, 0) )
// {
// Ray_t rayGhostAnimating;
// rayGhostAnimating.Init( searchCenter, searchCenter + forward * 1024 );
//
// CBaseEntity *list[1024];
// int nCount = UTIL_EntitiesAlongRay( list, 1024, rayGhostAnimating, 0 );
//
// // Loop through all entities along the pick up ray
// for ( int i = 0; i < nCount; i++ )
// {
// CGhostAnimating *pGhostAnimating = dynamic_cast<CGhostAnimating*>( list[i] );
//
// // If the entity is a ghost animating
// if( pGhostAnimating )
// {
// trace_t trGhostAnimating;
// enginetrace->ClipRayToEntity( rayGhostAnimating, MASK_ALL, pGhostAnimating, &trGhostAnimating );
//
// if ( trGhostAnimating.fraction < tr.fraction )
// {
// // If we're not grabbing the clipped ghost
// VPlane plane = pGhostAnimating->GetLocalClipPlane();
// UTIL_Portal_PlaneTransform( pGhostAnimating->GetCloneTransform(), plane, plane );
// if ( plane.GetPointSide( trGhostAnimating.endpos ) != SIDE_FRONT )
// {
// tr = trGhostAnimating;
// pObject = tr.m_pEnt;
// }
// }
// }
// }
// }
//#endif
int count = 0;
// UNDONE: Might be faster to just fold this range into the sphere query
const int NUM_TANGENTS = 7;
while ( !IsUseableEntity(pObject, 0) && count < NUM_TANGENTS)
{
// trace a box at successive angles down
// 45 deg, 30 deg, 20 deg, 15 deg, 10 deg, -10, -15
const float tangents[NUM_TANGENTS] = { 1, 0.57735026919f, 0.3639702342f, 0.267949192431f, 0.1763269807f, -0.1763269807f, -0.267949192431f };
Vector down = forward - tangents[count]*up;
VectorNormalize(down);
UTIL_TraceHull( searchCenter, searchCenter + down * 72, -Vector(16,16,16), Vector(16,16,16), useableContents, this, COLLISION_GROUP_NONE, &tr );
pObject = tr.m_pEnt;
count++;
}
float nearestDot = CONE_90_DEGREES;
if ( IsUseableEntity(pObject, 0) )
{
Vector delta = tr.endpos - tr.startpos;
float centerZ = CollisionProp()->WorldSpaceCenter().z;
delta.z = IntervalDistance( tr.endpos.z, centerZ + CollisionProp()->OBBMins().z, centerZ + CollisionProp()->OBBMaxs().z );
float dist = delta.Length();
if ( dist < PLAYER_USE_RADIUS )
{
#ifndef CLIENT_DLL
if ( sv_debug_player_use.GetBool() )
{
NDebugOverlay::Line( searchCenter, tr.endpos, 0, 255, 0, true, 30 );
NDebugOverlay::Cross3D( tr.endpos, 16, 0, 255, 0, true, 30 );
}
if ( pObject->MyNPCPointer() && pObject->MyNPCPointer()->IsPlayerAlly( this ) )
{
// If about to select an NPC, do a more thorough check to ensure
// that we're selecting the right one from a group.
pObject = DoubleCheckUseNPC( pObject, searchCenter, forward );
}
g_PortalGameStats.Event_PlayerUsed( searchCenter, forward, pObject );
#endif
return pObject;
}
}
#ifndef CLIENT_DLL
CBaseEntity *pFoundByTrace = pObject;
#endif
// check ground entity first
// if you've got a useable ground entity, then shrink the cone of this search to 45 degrees
// otherwise, search out in a 90 degree cone (hemisphere)
if ( GetGroundEntity() && IsUseableEntity(GetGroundEntity(), FCAP_USE_ONGROUND) )
{
pNearest = GetGroundEntity();
nearestDot = CONE_45_DEGREES;
}
for ( CEntitySphereQuery sphere( searchCenter, PLAYER_USE_RADIUS ); ( pObject = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() )
{
if ( !pObject )
continue;
if ( !IsUseableEntity( pObject, FCAP_USE_IN_RADIUS ) )
continue;
// see if it's more roughly in front of the player than previous guess
Vector point;
pObject->CollisionProp()->CalcNearestPoint( searchCenter, &point );
Vector dir = point - searchCenter;
VectorNormalize(dir);
float dot = DotProduct( dir, forward );
// Need to be looking at the object more or less
if ( dot < 0.8 )
continue;
if ( dot > nearestDot )
{
// Since this has purely been a radius search to this point, we now
// make sure the object isn't behind glass or a grate.
trace_t trCheckOccluded;
UTIL_TraceLine( searchCenter, point, useableContents, this, COLLISION_GROUP_NONE, &trCheckOccluded );
if ( trCheckOccluded.fraction == 1.0 || trCheckOccluded.m_pEnt == pObject )
{
pNearest = pObject;
nearestDot = dot;
}
}
}
#ifndef CLIENT_DLL
if ( !pNearest )
{
// Haven't found anything near the player to use, nor any NPC's at distance.
// Check to see if the player is trying to select an NPC through a rail, fence, or other 'see-though' volume.
trace_t trAllies;
UTIL_TraceLine( searchCenter, searchCenter + forward * PLAYER_USE_RADIUS, MASK_OPAQUE_AND_NPCS, this, COLLISION_GROUP_NONE, &trAllies );
if ( trAllies.m_pEnt && IsUseableEntity( trAllies.m_pEnt, 0 ) && trAllies.m_pEnt->MyNPCPointer() && trAllies.m_pEnt->MyNPCPointer()->IsPlayerAlly( this ) )
{
// This is an NPC, take it!
pNearest = trAllies.m_pEnt;
}
}
if ( pNearest && pNearest->MyNPCPointer() && pNearest->MyNPCPointer()->IsPlayerAlly( this ) )
{
pNearest = DoubleCheckUseNPC( pNearest, searchCenter, forward );
}
if ( sv_debug_player_use.GetBool() )
{
if ( !pNearest )
{
NDebugOverlay::Line( searchCenter, tr.endpos, 255, 0, 0, true, 30 );
NDebugOverlay::Cross3D( tr.endpos, 16, 255, 0, 0, true, 30 );
}
else if ( pNearest == pFoundByTrace )
{
NDebugOverlay::Line( searchCenter, tr.endpos, 0, 255, 0, true, 30 );
NDebugOverlay::Cross3D( tr.endpos, 16, 0, 255, 0, true, 30 );
}
else
{
NDebugOverlay::Box( pNearest->WorldSpaceCenter(), Vector(-8, -8, -8), Vector(8, 8, 8), 0, 255, 0, true, 30 );
}
}
g_PortalGameStats.Event_PlayerUsed( searchCenter, forward, pNearest );
#endif
return pNearest;
}
CBaseEntity* CPortal_Player::FindUseEntityThroughPortal( void )
{
Vector forward, up;
EyeVectors( &forward, NULL, &up );
CProp_Portal *pPortal = GetHeldObjectPortal();
trace_t tr;
// Search for objects in a sphere (tests for entities that are not solid, yet still useable)
Vector searchCenter = EyePosition();
Vector vTransformedForward, vTransformedUp, vTransformedSearchCenter;
VMatrix matThisToLinked = pPortal->MatrixThisToLinked();
UTIL_Portal_PointTransform( matThisToLinked, searchCenter, vTransformedSearchCenter );
UTIL_Portal_VectorTransform( matThisToLinked, forward, vTransformedForward );
UTIL_Portal_VectorTransform( matThisToLinked, up, vTransformedUp );
// NOTE: Some debris objects are useable too, so hit those as well
// A button, etc. can be made out of clip brushes, make sure it's +useable via a traceline, too.
int useableContents = MASK_SOLID | CONTENTS_DEBRIS | CONTENTS_PLAYERCLIP;
//UTIL_TraceLine( vTransformedSearchCenter, vTransformedSearchCenter + vTransformedForward * 1024, useableContents, this, COLLISION_GROUP_NONE, &tr );
Ray_t rayLinked;
rayLinked.Init( searchCenter, searchCenter + forward * 1024 );
UTIL_PortalLinked_TraceRay( pPortal, rayLinked, useableContents, this, COLLISION_GROUP_NONE, &tr );
// try the hit entity if there is one, or the ground entity if there isn't.
CBaseEntity *pNearest = NULL;
CBaseEntity *pObject = tr.m_pEnt;
int count = 0;
// UNDONE: Might be faster to just fold this range into the sphere query
const int NUM_TANGENTS = 7;
while ( !IsUseableEntity(pObject, 0) && count < NUM_TANGENTS)
{
// trace a box at successive angles down
// 45 deg, 30 deg, 20 deg, 15 deg, 10 deg, -10, -15
const float tangents[NUM_TANGENTS] = { 1, 0.57735026919f, 0.3639702342f, 0.267949192431f, 0.1763269807f, -0.1763269807f, -0.267949192431f };
Vector down = vTransformedForward - tangents[count]*vTransformedUp;
VectorNormalize(down);
UTIL_TraceHull( vTransformedSearchCenter, vTransformedSearchCenter + down * 72, -Vector(16,16,16), Vector(16,16,16), useableContents, this, COLLISION_GROUP_NONE, &tr );
pObject = tr.m_pEnt;
count++;
}
float nearestDot = CONE_90_DEGREES;
if ( IsUseableEntity(pObject, 0) )
{
Vector delta = tr.endpos - tr.startpos;
float centerZ = CollisionProp()->WorldSpaceCenter().z;
delta.z = IntervalDistance( tr.endpos.z, centerZ + CollisionProp()->OBBMins().z, centerZ + CollisionProp()->OBBMaxs().z );
float dist = delta.Length();
if ( dist < PLAYER_USE_RADIUS )
{
#ifndef CLIENT_DLL
if ( pObject->MyNPCPointer() && pObject->MyNPCPointer()->IsPlayerAlly( this ) )
{
// If about to select an NPC, do a more thorough check to ensure
// that we're selecting the right one from a group.
pObject = DoubleCheckUseNPC( pObject, vTransformedSearchCenter, vTransformedForward );
}
#endif
return pObject;
}
}
// check ground entity first
// if you've got a useable ground entity, then shrink the cone of this search to 45 degrees
// otherwise, search out in a 90 degree cone (hemisphere)
if ( GetGroundEntity() && IsUseableEntity(GetGroundEntity(), FCAP_USE_ONGROUND) )
{
pNearest = GetGroundEntity();
nearestDot = CONE_45_DEGREES;
}
for ( CEntitySphereQuery sphere( vTransformedSearchCenter, PLAYER_USE_RADIUS ); ( pObject = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() )
{
if ( !pObject )
continue;
if ( !IsUseableEntity( pObject, FCAP_USE_IN_RADIUS ) )
continue;
// see if it's more roughly in front of the player than previous guess
Vector point;
pObject->CollisionProp()->CalcNearestPoint( vTransformedSearchCenter, &point );
Vector dir = point - vTransformedSearchCenter;
VectorNormalize(dir);
float dot = DotProduct( dir, vTransformedForward );
// Need to be looking at the object more or less
if ( dot < 0.8 )
continue;
if ( dot > nearestDot )
{
// Since this has purely been a radius search to this point, we now
// make sure the object isn't behind glass or a grate.
trace_t trCheckOccluded;
UTIL_TraceLine( vTransformedSearchCenter, point, useableContents, this, COLLISION_GROUP_NONE, &trCheckOccluded );
if ( trCheckOccluded.fraction == 1.0 || trCheckOccluded.m_pEnt == pObject )
{
pNearest = pObject;
nearestDot = dot;
}
}
}
#ifndef CLIENT_DLL
if ( !pNearest )
{
// Haven't found anything near the player to use, nor any NPC's at distance.
// Check to see if the player is trying to select an NPC through a rail, fence, or other 'see-though' volume.
trace_t trAllies;
UTIL_TraceLine( vTransformedSearchCenter, vTransformedSearchCenter + vTransformedForward * PLAYER_USE_RADIUS, MASK_OPAQUE_AND_NPCS, this, COLLISION_GROUP_NONE, &trAllies );
if ( trAllies.m_pEnt && IsUseableEntity( trAllies.m_pEnt, 0 ) && trAllies.m_pEnt->MyNPCPointer() && trAllies.m_pEnt->MyNPCPointer()->IsPlayerAlly( this ) )
{
// This is an NPC, take it!
pNearest = trAllies.m_pEnt;
}
}
if ( pNearest && pNearest->MyNPCPointer() && pNearest->MyNPCPointer()->IsPlayerAlly( this ) )
{
pNearest = DoubleCheckUseNPC( pNearest, vTransformedSearchCenter, vTransformedForward );
}
#endif
return pNearest;
}
#if 0
//==========================
// ANIMATION CODE
//==========================
// Below this many degrees, slow down turning rate linearly
#define FADE_TURN_DEGREES 45.0f
// After this, need to start turning feet
#define MAX_TORSO_ANGLE 90.0f
// Below this amount, don't play a turning animation/perform IK
#define MIN_TURN_ANGLE_REQUIRING_TURN_ANIMATION 15.0f
static ConVar tf2_feetyawrunscale( "tf2_feetyawrunscale", "2", FCVAR_REPLICATED, "Multiplier on tf2_feetyawrate to allow turning faster when running." );
extern ConVar sv_backspeed;
extern ConVar mp_feetyawrate;
extern ConVar mp_facefronttime;
extern ConVar mp_ik;
CPlayerAnimState::CPlayerAnimState( CPortal_Player *outer )
: m_pOuter( outer )
{
m_flGaitYaw = 0.0f;
m_flGoalFeetYaw = 0.0f;
m_flCurrentFeetYaw = 0.0f;
m_flCurrentTorsoYaw = 0.0f;
m_flLastYaw = 0.0f;
m_flLastTurnTime = 0.0f;
m_flTurnCorrectionTime = 0.0f;
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPlayerAnimState::Update()
{
m_angRender = GetOuter()->GetLocalAngles();
ComputePoseParam_BodyYaw();
ComputePoseParam_BodyPitch( GetOuter()->GetModelPtr() );
ComputePoseParam_BodyLookYaw();
ComputePlaybackRate();
#ifdef CLIENT_DLL
GetOuter()->UpdateLookAt();
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPlayerAnimState::ComputePlaybackRate()
{
// Determine ideal playback rate
Vector vel;
GetOuterAbsVelocity( vel );
float speed = vel.Length2D();
bool isMoving = ( speed > 0.5f ) ? true : false;
float maxspeed = GetOuter()->GetSequenceGroundSpeed( GetOuter()->GetSequence() );
if ( isMoving && ( maxspeed > 0.0f ) )
{
float flFactor = 1.0f;
// Note this gets set back to 1.0 if sequence changes due to ResetSequenceInfo below
GetOuter()->SetPlaybackRate( ( speed * flFactor ) / maxspeed );
// BUG BUG:
// This stuff really should be m_flPlaybackRate = speed / m_flGroundSpeed
}
else
{
GetOuter()->SetPlaybackRate( 1.0f );
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : CBasePlayer
//-----------------------------------------------------------------------------
CPortal_Player *CPlayerAnimState::GetOuter()
{
return m_pOuter;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : dt -
//-----------------------------------------------------------------------------
void CPlayerAnimState::EstimateYaw( void )
{
float dt = gpGlobals->frametime;
if ( !dt )
{
return;
}
Vector est_velocity;
QAngle angles;
GetOuterAbsVelocity( est_velocity );
angles = GetOuter()->GetLocalAngles();
if ( est_velocity[1] == 0 && est_velocity[0] == 0 )
{
float flYawDiff = angles[YAW] - m_flGaitYaw;
flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360;
if (flYawDiff > 180)
flYawDiff -= 360;
if (flYawDiff < -180)
flYawDiff += 360;
if (dt < 0.25)
flYawDiff *= dt * 4;
else
flYawDiff *= dt;
m_flGaitYaw += flYawDiff;
m_flGaitYaw = m_flGaitYaw - (int)(m_flGaitYaw / 360) * 360;
}
else
{
m_flGaitYaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI);
if (m_flGaitYaw > 180)
m_flGaitYaw = 180;
else if (m_flGaitYaw < -180)
m_flGaitYaw = -180;
}
}
//-----------------------------------------------------------------------------
// Purpose: Override for backpeddling
// Input : dt -
//-----------------------------------------------------------------------------
void CPlayerAnimState::ComputePoseParam_BodyYaw( void )
{
int iYaw = GetOuter()->LookupPoseParameter( "move_yaw" );
if ( iYaw < 0 )
return;
// view direction relative to movement
float flYaw;
EstimateYaw();
QAngle angles = GetOuter()->GetLocalAngles();
float ang = angles[ YAW ];
if ( ang > 180.0f )
{
ang -= 360.0f;
}
else if ( ang < -180.0f )
{
ang += 360.0f;
}
// calc side to side turning
flYaw = ang - m_flGaitYaw;
// Invert for mapping into 8way blend
flYaw = -flYaw;
flYaw = flYaw - (int)(flYaw / 360) * 360;
if (flYaw < -180)
{
flYaw = flYaw + 360;
}
else if (flYaw > 180)
{
flYaw = flYaw - 360;
}
GetOuter()->SetPoseParameter( iYaw, flYaw );
#ifndef CLIENT_DLL
//Adrian: Make the model's angle match the legs so the hitboxes match on both sides.
GetOuter()->SetLocalAngles( QAngle( GetOuter()->GetAnimEyeAngles().x, m_flCurrentFeetYaw, 0 ) );
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPlayerAnimState::ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr )
{
// Get pitch from v_angle
float flPitch = GetOuter()->GetLocalAngles()[ PITCH ];
if ( flPitch > 180.0f )
{
flPitch -= 360.0f;
}
flPitch = clamp( flPitch, -90, 90 );
QAngle absangles = GetOuter()->GetAbsAngles();
absangles.x = 0.0f;
m_angRender = absangles;
// See if we have a blender for pitch
GetOuter()->SetPoseParameter( pStudioHdr, "aim_pitch", -flPitch );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : goal -
// maxrate -
// dt -
// current -
// Output : int
//-----------------------------------------------------------------------------
int CPlayerAnimState::ConvergeAngles( float goal,float maxrate, float dt, float& current )
{
int direction = TURN_NONE;
float anglediff = goal - current;
float anglediffabs = fabs( anglediff );
anglediff = AngleNormalize( anglediff );
float scale = 1.0f;
if ( anglediffabs <= FADE_TURN_DEGREES )
{
scale = anglediffabs / FADE_TURN_DEGREES;
// Always do at least a bit of the turn ( 1% )
scale = clamp( scale, 0.01f, 1.0f );
}
float maxmove = maxrate * dt * scale;
if ( fabs( anglediff ) < maxmove )
{
current = goal;
}
else
{
if ( anglediff > 0 )
{
current += maxmove;
direction = TURN_LEFT;
}
else
{
current -= maxmove;
direction = TURN_RIGHT;
}
}
current = AngleNormalize( current );
return direction;
}
void CPlayerAnimState::ComputePoseParam_BodyLookYaw( void )
{
QAngle absangles = GetOuter()->GetAbsAngles();
absangles.y = AngleNormalize( absangles.y );
m_angRender = absangles;
// See if we even have a blender for pitch
int upper_body_yaw = GetOuter()->LookupPoseParameter( "aim_yaw" );
if ( upper_body_yaw < 0 )
{
return;
}
// Assume upper and lower bodies are aligned and that we're not turning
float flGoalTorsoYaw = 0.0f;
int turning = TURN_NONE;
float turnrate = 360.0f;
Vector vel;
GetOuterAbsVelocity( vel );
bool isMoving = ( vel.Length() > 1.0f ) ? true : false;
if ( !isMoving )
{
// Just stopped moving, try and clamp feet
if ( m_flLastTurnTime <= 0.0f )
{
m_flLastTurnTime = gpGlobals->curtime;
m_flLastYaw = GetOuter()->GetAnimEyeAngles().y;
// Snap feet to be perfectly aligned with torso/eyes
m_flGoalFeetYaw = GetOuter()->GetAnimEyeAngles().y;
m_flCurrentFeetYaw = m_flGoalFeetYaw;
m_nTurningInPlace = TURN_NONE;
}
// If rotating in place, update stasis timer
if ( m_flLastYaw != GetOuter()->GetAnimEyeAngles().y )
{
m_flLastTurnTime = gpGlobals->curtime;
m_flLastYaw = GetOuter()->GetAnimEyeAngles().y;
}
if ( m_flGoalFeetYaw != m_flCurrentFeetYaw )
{
m_flLastTurnTime = gpGlobals->curtime;
}
turning = ConvergeAngles( m_flGoalFeetYaw, turnrate, gpGlobals->frametime, m_flCurrentFeetYaw );
QAngle eyeAngles = GetOuter()->GetAnimEyeAngles();
QAngle vAngle = GetOuter()->GetLocalAngles();
// See how far off current feetyaw is from true yaw
float yawdelta = GetOuter()->GetAnimEyeAngles().y - m_flCurrentFeetYaw;
yawdelta = AngleNormalize( yawdelta );
bool rotated_too_far = false;
float yawmagnitude = fabs( yawdelta );
// If too far, then need to turn in place
if ( yawmagnitude > 45 )
{
rotated_too_far = true;
}
// Standing still for a while, rotate feet around to face forward
// Or rotated too far
// FIXME: Play an in place turning animation
if ( rotated_too_far ||
( gpGlobals->curtime > m_flLastTurnTime + mp_facefronttime.GetFloat() ) )
{
m_flGoalFeetYaw = GetOuter()->GetAnimEyeAngles().y;
m_flLastTurnTime = gpGlobals->curtime;
/* float yd = m_flCurrentFeetYaw - m_flGoalFeetYaw;
if ( yd > 0 )
{
m_nTurningInPlace = TURN_RIGHT;
}
else if ( yd < 0 )
{
m_nTurningInPlace = TURN_LEFT;
}
else
{
m_nTurningInPlace = TURN_NONE;
}
turning = ConvergeAngles( m_flGoalFeetYaw, turnrate, gpGlobals->frametime, m_flCurrentFeetYaw );
yawdelta = GetOuter()->GetAnimEyeAngles().y - m_flCurrentFeetYaw;*/
}
// Snap upper body into position since the delta is already smoothed for the feet
flGoalTorsoYaw = yawdelta;
m_flCurrentTorsoYaw = flGoalTorsoYaw;
}
else
{
m_flLastTurnTime = 0.0f;
m_nTurningInPlace = TURN_NONE;
m_flCurrentFeetYaw = m_flGoalFeetYaw = GetOuter()->GetAnimEyeAngles().y;
flGoalTorsoYaw = 0.0f;
m_flCurrentTorsoYaw = GetOuter()->GetAnimEyeAngles().y - m_flCurrentFeetYaw;
}
if ( turning == TURN_NONE )
{
m_nTurningInPlace = turning;
}
if ( m_nTurningInPlace != TURN_NONE )
{
// If we're close to finishing the turn, then turn off the turning animation
if ( fabs( m_flCurrentFeetYaw - m_flGoalFeetYaw ) < MIN_TURN_ANGLE_REQUIRING_TURN_ANIMATION )
{
m_nTurningInPlace = TURN_NONE;
}
}
// Rotate entire body into position
absangles = GetOuter()->GetAbsAngles();
absangles.y = m_flCurrentFeetYaw;
m_angRender = absangles;
GetOuter()->SetPoseParameter( upper_body_yaw, clamp( m_flCurrentTorsoYaw, -60.0f, 60.0f ) );
/*
// FIXME: Adrian, what is this?
int body_yaw = GetOuter()->LookupPoseParameter( "body_yaw" );
if ( body_yaw >= 0 )
{
GetOuter()->SetPoseParameter( body_yaw, 30 );
}
*/
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : activity -
// Output : Activity
//-----------------------------------------------------------------------------
Activity CPlayerAnimState::BodyYawTranslateActivity( Activity activity )
{
// Not even standing still, sigh
if ( activity != ACT_IDLE )
return activity;
// Not turning
switch ( m_nTurningInPlace )
{
default:
case TURN_NONE:
return activity;
/*
case TURN_RIGHT:
return ACT_TURNRIGHT45;
case TURN_LEFT:
return ACT_TURNLEFT45;
*/
case TURN_RIGHT:
case TURN_LEFT:
return mp_ik.GetBool() ? ACT_TURN : activity;
}
Assert( 0 );
return activity;
}
const QAngle& CPlayerAnimState::GetRenderAngles()
{
return m_angRender;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CPlayerAnimState::Teleport( Vector *pOldOrigin, QAngle *pOldAngles )
{
QAngle absangles = GetOuter()->GetAbsAngles();
absangles.x = 0.0f;
m_angRender = absangles;
m_flCurrentFeetYaw = m_flGoalFeetYaw = m_flLastYaw = m_angRender.y;
m_flLastTurnTime = 0.0f;
m_nTurningInPlace = TURN_NONE;
}
void CPlayerAnimState::GetOuterAbsVelocity( Vector& vel )
{
#if defined( CLIENT_DLL )
GetOuter()->EstimateAbsVelocity( vel );
#else
vel = GetOuter()->GetAbsVelocity();
#endif
}
#endif // #if 0
+38
View File
@@ -0,0 +1,38 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#ifndef PORTAL_PLAYER_SHARED_H
#define PORTAL_PLAYER_SHARED_H
#pragma once
#define PORTAL_PUSHAWAY_THINK_INTERVAL (1.0f / 20.0f)
#include "studio.h"
enum
{
PLAYER_SOUNDS_CITIZEN = 0,
PLAYER_SOUNDS_COMBINESOLDIER,
PLAYER_SOUNDS_METROPOLICE,
PLAYER_SOUNDS_MAX,
};
enum
{
CONCEPT_CHELL_IDLE,
CONCEPT_CHELL_DEAD,
};
extern const char *g_pszChellConcepts[];
int GetChellConceptIndexFromString( const char *pszConcept );
#if defined( CLIENT_DLL )
#define CPortal_Player C_Portal_Player
#endif
#endif //PORTAL_PLAYER_SHARED_h
@@ -0,0 +1,310 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "tier0/vprof.h"
#include "animation.h"
#include "studio.h"
#include "apparent_velocity_helper.h"
#include "utldict.h"
#include "portal_playeranimstate.h"
#include "base_playeranimstate.h"
#ifdef CLIENT_DLL
#include "c_portal_player.h"
#include "c_weapon_portalgun.h"
#else
#include "portal_player.h"
#include "weapon_portalgun.h"
#endif
#define PORTAL_RUN_SPEED 320.0f
#define PORTAL_CROUCHWALK_SPEED 110.0f
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pPlayer -
// Output : CMultiPlayerAnimState*
//-----------------------------------------------------------------------------
CPortalPlayerAnimState* CreatePortalPlayerAnimState( CPortal_Player *pPlayer )
{
// Setup the movement data.
MultiPlayerMovementData_t movementData;
movementData.m_flBodyYawRate = 720.0f;
movementData.m_flRunSpeed = PORTAL_RUN_SPEED;
movementData.m_flWalkSpeed = -1;
movementData.m_flSprintSpeed = -1.0f;
// Create animation state for this player.
CPortalPlayerAnimState *pRet = new CPortalPlayerAnimState( pPlayer, movementData );
// Specific Portal player initialization.
pRet->InitPortal( pPlayer );
return pRet;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : -
//-----------------------------------------------------------------------------
CPortalPlayerAnimState::CPortalPlayerAnimState()
{
m_pPortalPlayer = NULL;
// Don't initialize Portal specific variables here. Init them in InitPortal()
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pPlayer -
// &movementData -
//-----------------------------------------------------------------------------
CPortalPlayerAnimState::CPortalPlayerAnimState( CBasePlayer *pPlayer, MultiPlayerMovementData_t &movementData )
: CMultiPlayerAnimState( pPlayer, movementData )
{
m_pPortalPlayer = NULL;
// Don't initialize Portal specific variables here. Init them in InitPortal()
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : -
//-----------------------------------------------------------------------------
CPortalPlayerAnimState::~CPortalPlayerAnimState()
{
}
//-----------------------------------------------------------------------------
// Purpose: Initialize Portal specific animation state.
// Input : *pPlayer -
//-----------------------------------------------------------------------------
void CPortalPlayerAnimState::InitPortal( CPortal_Player *pPlayer )
{
m_pPortalPlayer = pPlayer;
m_bInAirWalk = false;
m_flHoldDeployedPoseUntilTime = 0.0f;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPortalPlayerAnimState::ClearAnimationState( void )
{
m_bInAirWalk = false;
BaseClass::ClearAnimationState();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : actDesired -
// Output : Activity
//-----------------------------------------------------------------------------
Activity CPortalPlayerAnimState::TranslateActivity( Activity actDesired )
{
Activity translateActivity = BaseClass::TranslateActivity( actDesired );
if ( GetPortalPlayer()->GetActiveWeapon() )
{
translateActivity = GetPortalPlayer()->GetActiveWeapon()->ActivityOverride( translateActivity, NULL );
}
return translateActivity;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : event -
//-----------------------------------------------------------------------------
void CPortalPlayerAnimState::DoAnimationEvent( PlayerAnimEvent_t event, int nData )
{
Activity iWeaponActivity = ACT_INVALID;
switch( event )
{
case PLAYERANIMEVENT_ATTACK_PRIMARY:
case PLAYERANIMEVENT_ATTACK_SECONDARY:
{
CPortal_Player *pPlayer = GetPortalPlayer();
if ( !pPlayer )
return;
CWeaponPortalBase *pWpn = pPlayer->GetActivePortalWeapon();
if ( pWpn )
{
// Weapon primary fire.
if ( GetBasePlayer()->GetFlags() & FL_DUCKING )
{
RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_ATTACK_CROUCH_PRIMARYFIRE );
}
else
{
RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_ATTACK_STAND_PRIMARYFIRE );
}
iWeaponActivity = ACT_VM_PRIMARYATTACK;
}
else // unarmed player
{
}
break;
}
default:
{
BaseClass::DoAnimationEvent( event, nData );
break;
}
}
#ifdef CLIENT_DLL
// Make the weapon play the animation as well
if ( iWeaponActivity != ACT_INVALID )
{
CBaseCombatWeapon *pWeapon = GetPortalPlayer()->GetActiveWeapon();
if ( pWeapon )
{
pWeapon->SendWeaponAnim( iWeaponActivity );
}
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPortalPlayerAnimState::Teleport( const Vector *pNewOrigin, const QAngle *pNewAngles, CPortal_Player* pPlayer )
{
QAngle absangles = pPlayer->GetAbsAngles();
m_angRender = absangles;
m_angRender.x = m_angRender.z = 0.0f;
if ( pPlayer )
{
// Snap the yaw pose parameter lerping variables to face new angles.
m_flCurrentFeetYaw = m_flGoalFeetYaw = m_flEyeYaw = pPlayer->EyeAngles()[YAW];
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *idealActivity -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CPortalPlayerAnimState::HandleMoving( Activity &idealActivity )
{
float flSpeed = GetOuterXYSpeed();
// If we move, cancel the deployed anim hold
if ( flSpeed > MOVING_MINIMUM_SPEED )
{
m_flHoldDeployedPoseUntilTime = 0.0;
idealActivity = ACT_MP_RUN;
}
else if ( m_flHoldDeployedPoseUntilTime > gpGlobals->curtime )
{
// Unless we move, hold the deployed pose for a number of seconds after being deployed
idealActivity = ACT_MP_DEPLOYED_IDLE;
}
else
{
return BaseClass::HandleMoving( idealActivity );
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *idealActivity -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CPortalPlayerAnimState::HandleDucking( Activity &idealActivity )
{
if ( GetBasePlayer()->m_Local.m_bDucking || GetBasePlayer()->m_Local.m_bDucked )
{
if ( GetOuterXYSpeed() < MOVING_MINIMUM_SPEED )
{
idealActivity = ACT_MP_CROUCH_IDLE;
}
else
{
idealActivity = ACT_MP_CROUCHWALK;
}
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
bool CPortalPlayerAnimState::HandleJumping( Activity &idealActivity )
{
Vector vecVelocity;
GetOuterAbsVelocity( vecVelocity );
if ( ( vecVelocity.z > 300.0f || m_bInAirWalk ) )
{
// Check to see if we were in an airwalk and now we are basically on the ground.
if ( GetBasePlayer()->GetFlags() & FL_ONGROUND )
{
m_bInAirWalk = false;
RestartMainSequence();
RestartGesture( GESTURE_SLOT_JUMP, ACT_MP_JUMP_LAND );
}
else
{
// In an air walk.
idealActivity = ACT_MP_AIRWALK;
m_bInAirWalk = true;
}
}
// Jumping.
else
{
if ( m_bJumping )
{
if ( m_bFirstJumpFrame )
{
m_bFirstJumpFrame = false;
RestartMainSequence(); // Reset the animation.
}
// Don't check if he's on the ground for a sec.. sometimes the client still has the
// on-ground flag set right when the message comes in.
else if ( gpGlobals->curtime - m_flJumpStartTime > 0.2f )
{
if ( GetBasePlayer()->GetFlags() & FL_ONGROUND )
{
m_bJumping = false;
RestartMainSequence();
RestartGesture( GESTURE_SLOT_JUMP, ACT_MP_JUMP_LAND );
}
}
// if we're still jumping
if ( m_bJumping )
{
idealActivity = ACT_MP_JUMP_START;
}
}
}
if ( m_bJumping || m_bInAirWalk )
return true;
return false;
}
@@ -0,0 +1,85 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef PORTAL_PLAYERANIMSTATE_H
#define PORTAL_PLAYERANIMSTATE_H
#ifdef _WIN32
#pragma once
#endif
#include "convar.h"
#include "multiplayer_animstate.h"
#if defined( CLIENT_DLL )
class C_Portal_Player;
#define CPortal_Player C_Portal_Player
#else
class CPortal_Player;
#endif
//enum PlayerAnimEvent_t
//{
// PLAYERANIMEVENT_FIRE_GUN=0,
// PLAYERANIMEVENT_THROW_GRENADE,
// PLAYERANIMEVENT_ROLL_GRENADE,
// PLAYERANIMEVENT_JUMP,
// PLAYERANIMEVENT_RELOAD,
// PLAYERANIMEVENT_SECONDARY_ATTACK,
//
// PLAYERANIMEVENT_HS_NONE,
// PLAYERANIMEVENT_CANCEL_GESTURES, // cancel current gesture
//
// PLAYERANIMEVENT_COUNT
//};
// ------------------------------------------------------------------------------------------------ //
// CPlayerAnimState declaration.
// ------------------------------------------------------------------------------------------------ //
class CPortalPlayerAnimState : public CMultiPlayerAnimState
{
public:
DECLARE_CLASS( CPortalPlayerAnimState, CMultiPlayerAnimState );
CPortalPlayerAnimState();
CPortalPlayerAnimState( CBasePlayer *pPlayer, MultiPlayerMovementData_t &movementData );
~CPortalPlayerAnimState();
void InitPortal( CPortal_Player *pPlayer );
CPortal_Player *GetPortalPlayer( void ) { return m_pPortalPlayer; }
virtual void ClearAnimationState();
virtual Activity TranslateActivity( Activity actDesired );
void DoAnimationEvent( PlayerAnimEvent_t event, int nData = 0 );
void Teleport( const Vector *pNewOrigin, const QAngle *pNewAngles, CPortal_Player* pPlayer );
bool HandleMoving( Activity &idealActivity );
bool HandleJumping( Activity &idealActivity );
bool HandleDucking( Activity &idealActivity );
private:
CPortal_Player *m_pPortalPlayer;
bool m_bInAirWalk;
float m_flHoldDeployedPoseUntilTime;
};
CPortalPlayerAnimState* CreatePortalPlayerAnimState( CPortal_Player *pPlayer );
// If this is set, then the game code needs to make sure to send player animation events
// to the local player if he's the one being watched.
extern ConVar cl_showanimstate;
#endif // PORTAL_PLAYERANIMSTATE_H
+13
View File
@@ -0,0 +1,13 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "portal_shareddefs.h"
char *g_ppszPortalPassThroughMaterials[] =
{
"lights/light_orange001",
NULL,
};
+79
View File
@@ -0,0 +1,79 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef PORTAL_SHAREDDEFS_H
#define PORTAL_SHAREDDEFS_H
#ifdef _WIN32
#pragma once
#endif
#define PORTAL_HALF_WIDTH 32.0f
#define PORTAL_HALF_HEIGHT 54.0f
#define PORTAL_HALF_DEPTH 2.0f
#define PORTAL_BUMP_FORGIVENESS 2.0f
#define PORTAL_ANALOG_SUCCESS_NO_BUMP 1.0f
#define PORTAL_ANALOG_SUCCESS_BUMPED 0.3f
#define PORTAL_ANALOG_SUCCESS_CANT_FIT 0.1f
#define PORTAL_ANALOG_SUCCESS_CLEANSER 0.028f
#define PORTAL_ANALOG_SUCCESS_OVERLAP_LINKED 0.027f
#define PORTAL_ANALOG_SUCCESS_NEAR 0.0265f
#define PORTAL_ANALOG_SUCCESS_INVALID_VOLUME 0.026f
#define PORTAL_ANALOG_SUCCESS_INVALID_SURFACE 0.025f
#define PORTAL_ANALOG_SUCCESS_PASSTHROUGH_SURFACE 0.0f
#define MIN_FLING_SPEED 300
#define PORTAL_HIDE_PLAYER_RAGDOLL 1
enum PortalFizzleType_t
{
PORTAL_FIZZLE_SUCCESS = 0, // Placed fine (no fizzle)
PORTAL_FIZZLE_CANT_FIT,
PORTAL_FIZZLE_OVERLAPPED_LINKED,
PORTAL_FIZZLE_BAD_VOLUME,
PORTAL_FIZZLE_BAD_SURFACE,
PORTAL_FIZZLE_KILLED,
PORTAL_FIZZLE_CLEANSER,
PORTAL_FIZZLE_CLOSE,
PORTAL_FIZZLE_NEAR_BLUE,
PORTAL_FIZZLE_NEAR_RED,
PORTAL_FIZZLE_NONE,
NUM_PORTAL_FIZZLE_TYPES
};
enum PortalPlacedByType
{
PORTAL_PLACED_BY_FIXED = 0,
PORTAL_PLACED_BY_PEDESTAL,
PORTAL_PLACED_BY_PLAYER
};
enum PortalLevelStatType
{
PORTAL_LEVEL_STAT_NUM_PORTALS = 0,
PORTAL_LEVEL_STAT_NUM_STEPS,
PORTAL_LEVEL_STAT_NUM_SECONDS,
PORTAL_LEVEL_STAT_TOTAL
};
enum PortalChallengeType
{
PORTAL_CHALLENGE_NONE = 0,
PORTAL_CHALLENGE_PORTALS,
PORTAL_CHALLENGE_STEPS,
PORTAL_CHALLENGE_TIME,
PORTAL_CHALLENGE_TOTAL
};
extern char *g_ppszPortalPassThroughMaterials[];
#endif // PORTAL_SHAREDDEFS_H
@@ -0,0 +1,64 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "usermessages.h"
#include "shake.h"
#include "voice_gamemgr.h"
// NVNT include to register in haptic user messages
#include "haptics/haptic_msgs.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
void RegisterUserMessages()
{
//copy/paste from hl2
usermessages->Register( "Geiger", 1 );
usermessages->Register( "Train", 1 );
usermessages->Register( "HudText", -1 );
usermessages->Register( "SayText", -1 );
usermessages->Register( "SayText2", -1 );
usermessages->Register( "TextMsg", -1 );
usermessages->Register( "HudMsg", -1 );
usermessages->Register( "ResetHUD", 1); // called every respawn
usermessages->Register( "GameTitle", 0 );
usermessages->Register( "ItemPickup", -1 );
usermessages->Register( "ShowMenu", -1 );
usermessages->Register( "Shake", 13 );
usermessages->Register( "Fade", 10 );
usermessages->Register( "VGUIMenu", -1 ); // Show VGUI menu
usermessages->Register( "Rumble", 3 ); // Send a rumble to a controller
usermessages->Register( "Battery", 2 );
usermessages->Register( "Damage", 18 ); // BUG: floats are sent for coords, no variable bitfields in hud & fixed size Msg
usermessages->Register( "VoiceMask", VOICE_MAX_PLAYERS_DW*4 * 2 + 1 );
usermessages->Register( "RequestState", 0 );
usermessages->Register( "CloseCaption", -1 ); // Show a caption (by string id number)(duration in 10th of a second)
usermessages->Register( "HintText", -1 ); // Displays hint text display
usermessages->Register( "KeyHintText", -1 ); // Displays hint text display
usermessages->Register( "SquadMemberDied", 0 );
usermessages->Register( "AmmoDenied", 2 );
usermessages->Register( "CreditsMsg", 1 );
usermessages->Register( "CreditsPortalMsg", 1 );
usermessages->Register( "LogoTimeMsg", 4 );
usermessages->Register( "AchievementEvent", -1 );
//new stuff for portal
usermessages->Register( "EntityPortalled", sizeof( long ) + sizeof( long ) + sizeof( Vector ) + sizeof( QAngle ) ); //something got teleported through a portal
usermessages->Register( "KillCam", -1 );
// Voting
usermessages->Register( "CallVoteFailed", 1 );
usermessages->Register( "VoteStart", -1 );
usermessages->Register( "VotePass", -1 );
usermessages->Register( "VoteFailed", 2 );
usermessages->Register( "VoteSetup", -1 ); // Initiates client-side voting UI
// NVNT register haptic user messages
RegisterHapticMessages();
}
File diff suppressed because it is too large Load Diff
+103
View File
@@ -0,0 +1,103 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef PORTAL_UTIL_SHARED_H
#define PORTAL_UTIL_SHARED_H
#ifdef _WIN32
#pragma once
#endif
#include "engine/IEngineTrace.h"
extern bool g_bBulletPortalTrace;
#ifdef CLIENT_DLL
#include "client_class.h"
#include "interpolatedvar.h"
class C_Prop_Portal;
typedef C_Prop_Portal CProp_Portal;
class C_Beam;
typedef C_Beam CBeam;
#else
class CProp_Portal;
class CBeam;
#endif
Color UTIL_Portal_Color( int iPortal );
void UTIL_Portal_Trace_Filter( class CTraceFilterSimpleClassnameList *traceFilterPortalShot );
CProp_Portal* UTIL_Portal_FirstAlongRay( const Ray_t &ray, float &fMustBeCloserThan );
bool UTIL_Portal_TraceRay_Bullets( const CProp_Portal *pPortal, const Ray_t &ray, unsigned int fMask, ITraceFilter *pTraceFilter, trace_t *pTrace, bool bTraceHolyWall = true );
CProp_Portal* UTIL_Portal_TraceRay_Beam( const Ray_t &ray, unsigned int fMask, ITraceFilter *pTraceFilter, float *pfFraction );
bool UTIL_Portal_Trace_Beam( const CBeam *pBeam, Vector &vecStart, Vector &vecEnd, Vector &vecIntersectionStart, Vector &vecIntersectionEnd, ITraceFilter *pTraceFilter );
void UTIL_Portal_TraceRay_With( const CProp_Portal *pPortal, const Ray_t &ray, unsigned int fMask, ITraceFilter *pTraceFilter, trace_t *pTrace, bool bTraceHolyWall = true );
CProp_Portal* UTIL_Portal_TraceRay( const Ray_t &ray, unsigned int fMask, ITraceFilter *pTraceFilter, trace_t *pTrace, bool bTraceHolyWall = true ); //traces a ray normally, then sees if portals have anything to say about it
CProp_Portal* UTIL_Portal_TraceRay( const Ray_t &ray, unsigned int fMask, const IHandleEntity *ignore, int collisionGroup, trace_t *pTrace, bool bTraceHolyWall = true );
void UTIL_Portal_TraceRay( const CProp_Portal *pPortal, const Ray_t &ray, unsigned int fMask, ITraceFilter *pTraceFilter, trace_t *pTrace, bool bTraceHolyWall = true ); //traces against a specific portal's environment, does no *real* tracing
void UTIL_Portal_TraceRay( const CProp_Portal *pPortal, const Ray_t &ray, unsigned int fMask, const IHandleEntity *ignore, int collisionGroup, trace_t *pTrace, bool bTraceHolyWall = true );
void UTIL_PortalLinked_TraceRay( const CProp_Portal *pPortal, const Ray_t &ray, unsigned int fMask, ITraceFilter *pTraceFilter, trace_t *pTrace, bool bTraceHolyWall = true ); //traces against a specific portal's environment, does no *real* tracing
void UTIL_PortalLinked_TraceRay( const CProp_Portal *pPortal, const Ray_t &ray, unsigned int fMask, const IHandleEntity *ignore, int collisionGroup, trace_t *pTrace, bool bTraceHolyWall = true );
// tests if a ray's trace hits any portals
bool UTIL_DidTraceTouchPortals ( const Ray_t& ray, const trace_t& trace, CProp_Portal** pOutLocal = NULL, CProp_Portal** pOutRemote = NULL );
// Version of the TraceEntity functions which trace through portals
void UTIL_Portal_TraceEntity( CBaseEntity *pEntity, const Vector &vecAbsStart, const Vector &vecAbsEnd,
unsigned int mask, ITraceFilter *pFilter, trace_t *ptr );
void UTIL_Portal_PointTransform( const VMatrix matThisToLinked, const Vector &ptSource, Vector &ptTransformed );
void UTIL_Portal_VectorTransform( const VMatrix matThisToLinked, const Vector &vSource, Vector &vTransformed );
void UTIL_Portal_AngleTransform( const VMatrix matThisToLinked, const QAngle &qSource, QAngle &qTransformed );
void UTIL_Portal_RayTransform( const VMatrix matThisToLinked, const Ray_t &raySource, Ray_t &rayTransformed );
void UTIL_Portal_PlaneTransform( const VMatrix matThisToLinked, const cplane_t &planeSource, cplane_t &planeTransformed );
void UTIL_Portal_PlaneTransform( const VMatrix matThisToLinked, const VPlane &planeSource, VPlane &planeTransformed );
void UTIL_Portal_Triangles( const Vector &ptPortalCenter, const QAngle &qPortalAngles, Vector pvTri1[ 3 ], Vector pvTri2[ 3 ] );
void UTIL_Portal_Triangles( const CProp_Portal *pPortal, Vector pvTri1[ 3 ], Vector pvTri2[ 3 ] );
void UTIL_Portal_AABB( const CProp_Portal *pPortal, Vector &vMin, Vector &vMax );
float UTIL_Portal_DistanceThroughPortal( const CProp_Portal *pPortal, const Vector &vPoint1, const Vector &vPoint2 );
float UTIL_Portal_DistanceThroughPortalSqr( const CProp_Portal *pPortal, const Vector &vPoint1, const Vector &vPoint2 );
float UTIL_Portal_ShortestDistance( const Vector &vPoint1, const Vector &vPoint2, CProp_Portal **pShortestDistPortal_Out = NULL, bool bRequireStraightLine = false );
float UTIL_Portal_ShortestDistanceSqr( const Vector &vPoint1, const Vector &vPoint2, CProp_Portal **pShortestDistPortal_Out = NULL, bool bRequireStraightLine = false );
//-----------------------------------------------------------------------------
//
// UTIL_IntersectRayWithPortal
//
// Intersects a ray with a portal, returns distance t along ray.
// t will be less than zero if no intersection occurred
//
//-----------------------------------------------------------------------------
float UTIL_IntersectRayWithPortal( const Ray_t &ray, const CProp_Portal *pPortal );
bool UTIL_IntersectRayWithPortalOBB( const CProp_Portal *pPortal, const Ray_t &ray, trace_t *pTrace );
bool UTIL_IntersectRayWithPortalOBBAsAABB( const CProp_Portal *pPortal, const Ray_t &ray, trace_t *pTrace );
bool UTIL_IsBoxIntersectingPortal( const Vector &vecBoxCenter, const Vector &vecBoxExtents, const Vector &ptPortalCenter, const QAngle &qPortalAngles, float flTolerance = 0.0f );
bool UTIL_IsBoxIntersectingPortal( const Vector &vecBoxCenter, const Vector &vecBoxExtents, const CProp_Portal *pPortal, float flTolerance = 0.0f );
CProp_Portal *UTIL_IntersectEntityExtentsWithPortal( const CBaseEntity *pEntity );
void UTIL_Portal_NDebugOverlay( const Vector &ptPortalCenter, const QAngle &qPortalAngles, int r, int g, int b, int a, bool noDepthTest, float duration );
void UTIL_Portal_NDebugOverlay( const CProp_Portal *pPortal, int r, int g, int b, int a, bool noDepthTest, float duration );
bool FindClosestPassableSpace( CBaseEntity *pEntity, const Vector &vIndecisivePush, unsigned int fMask = MASK_SOLID ); //assumes the object is already in a mostly passable space
#ifdef CLIENT_DLL
void UTIL_TransformInterpolatedAngle( CInterpolatedVar< QAngle > &qInterped, matrix3x4_t matTransform, bool bSkipNewest );
void UTIL_TransformInterpolatedPosition( CInterpolatedVar< Vector > &vInterped, VMatrix matTransform, bool bSkipNewest );
#endif
bool UTIL_Portal_EntityIsInPortalHole( const CProp_Portal *pPortal, CBaseEntity *pEntity );
#endif //#ifndef PORTAL_UTIL_SHARED_H
@@ -0,0 +1,32 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include <KeyValues.h>
#include "portal_weapon_parse.h"
#include "ammodef.h"
FileWeaponInfo_t* CreateWeaponInfo()
{
return new CPortalSWeaponInfo;
}
CPortalSWeaponInfo::CPortalSWeaponInfo()
{
m_iPlayerDamage = 0;
}
void CPortalSWeaponInfo::Parse( KeyValues *pKeyValuesData, const char *szWeaponName )
{
BaseClass::Parse( pKeyValuesData, szWeaponName );
m_iPlayerDamage = pKeyValuesData->GetInt( "damage", 0 );
}
+35
View File
@@ -0,0 +1,35 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef PORTAL_WEAPON_PARSE_H
#define PORTAL_WEAPON_PARSE_H
#ifdef _WIN32
#pragma once
#endif
#include "weapon_parse.h"
#include "networkvar.h"
//--------------------------------------------------------------------------------------------------------
class CPortalSWeaponInfo : public FileWeaponInfo_t
{
public:
DECLARE_CLASS_GAMEROOT( CPortalSWeaponInfo, FileWeaponInfo_t );
CPortalSWeaponInfo();
virtual void Parse( ::KeyValues *pKeyValuesData, const char *szWeaponName );
public:
int m_iPlayerDamage;
};
#endif // PORTAL_WEAPON_PARSE_H
+80
View File
@@ -0,0 +1,80 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "prop_portal_shared.h"
#include "portal_shareddefs.h"
#ifdef CLIENT_DLL
#include "c_basedoor.h"
#endif
CUtlVector<CProp_Portal *> CProp_Portal_Shared::AllPortals;
const Vector CProp_Portal_Shared::vLocalMins( 0.0f, -PORTAL_HALF_WIDTH, -PORTAL_HALF_HEIGHT );
const Vector CProp_Portal_Shared::vLocalMaxs( 64.0f, PORTAL_HALF_WIDTH, PORTAL_HALF_HEIGHT );
void CProp_Portal_Shared::UpdatePortalTransformationMatrix( const matrix3x4_t &localToWorld, const matrix3x4_t &remoteToWorld, VMatrix *pMatrix )
{
VMatrix matPortal1ToWorldInv, matPortal2ToWorld, matRotation;
//inverse of this
MatrixInverseTR( localToWorld, matPortal1ToWorldInv );
//180 degree rotation about up
matRotation.Identity();
matRotation.m[0][0] = -1.0f;
matRotation.m[1][1] = -1.0f;
//final
matPortal2ToWorld = remoteToWorld;
*pMatrix = matPortal2ToWorld * matRotation * matPortal1ToWorldInv;
}
static char *g_pszPortalNonTeleportable[] =
{
"func_door",
"func_door_rotating",
"prop_door_rotating",
"func_tracktrain",
//"env_ghostanimating",
"physicsshadowclone"
};
bool CProp_Portal_Shared::IsEntityTeleportable( CBaseEntity *pEntity )
{
do
{
#ifdef CLIENT_DLL
//client
if( dynamic_cast<C_BaseDoor *>(pEntity) != NULL )
return false;
#else
//server
for( int i = 0; i != ARRAYSIZE(g_pszPortalNonTeleportable); ++i )
{
if( FClassnameIs( pEntity, g_pszPortalNonTeleportable[i] ) )
return false;
}
#endif
Assert( pEntity != pEntity->GetMoveParent() );
pEntity = pEntity->GetMoveParent();
} while( pEntity );
return true;
}
+49
View File
@@ -0,0 +1,49 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef PROP_PORTAL_SHARED_H
#define PROP_PORTAL_SHARED_H
#ifdef _WIN32
#pragma once
#endif
#include "cbase.h"
#ifdef CLIENT_DLL
#include "c_prop_portal.h"
#else
#include "prop_portal.h"
#endif
// CProp_Portal enum for the portal corners (if a user wants a specific corner)
enum PortalCorners_t { PORTAL_DOWN_RIGHT = 0, PORTAL_DOWN_LEFT, PORTAL_UP_RIGHT, PORTAL_UP_LEFT };
class CProp_Portal_Shared //defined as a class to make intellisense more intelligent
{
public:
static void UpdatePortalTransformationMatrix( const matrix3x4_t &localToWorld, const matrix3x4_t &remoteToWorld, VMatrix *pMatrix );
static bool IsEntityTeleportable( CBaseEntity *pEntity );
//static CProp_Portal *GetPortal1( bool bCreateIfNotFound = false );
//static CProp_Portal *GetPortal2( bool bCreateIfNotFound = false );
static const Vector vLocalMins;
static const Vector vLocalMaxs;
#ifdef CLIENT_DLL
static CUtlVector<C_Prop_Portal *> AllPortals; //an array of existing portal entities
#else
static CUtlVector<CProp_Portal *> AllPortals; //an array of existing portal entities
#endif //#ifdef CLIENT_DLL
};
#endif //#ifndef PROP_PORTAL_SHARED_H
+442
View File
@@ -0,0 +1,442 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "in_buttons.h"
#include "takedamageinfo.h"
#include "ammodef.h"
#include "portal_gamerules.h"
#ifdef CLIENT_DLL
extern IVModelInfoClient* modelinfo;
#else
extern IVModelInfo* modelinfo;
#endif
#if defined( CLIENT_DLL )
#include "vgui/ISurface.h"
#include "vgui_controls/Controls.h"
#include "c_portal_player.h"
#include "hud_crosshair.h"
#include "PortalRender.h"
#else
#include "portal_player.h"
#include "vphysics/constraints.h"
#endif
#include "weapon_portalbase.h"
// ----------------------------------------------------------------------------- //
// Global functions.
// ----------------------------------------------------------------------------- //
bool IsAmmoType( int iAmmoType, const char *pAmmoName )
{
return GetAmmoDef()->Index( pAmmoName ) == iAmmoType;
}
static const char * s_WeaponAliasInfo[] =
{
"none", // WEAPON_NONE = 0,
//Melee
"shotgun", //WEAPON_AMERKNIFE,
NULL, // end of list marker
};
// ----------------------------------------------------------------------------- //
// CWeaponPortalBase tables.
// ----------------------------------------------------------------------------- //
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponPortalBase, DT_WeaponPortalBase )
BEGIN_NETWORK_TABLE( CWeaponPortalBase, DT_WeaponPortalBase )
#ifdef CLIENT_DLL
#else
// world weapon models have no aminations
// SendPropExclude( "DT_AnimTimeMustBeFirst", "m_flAnimTime" ),
// SendPropExclude( "DT_BaseAnimating", "m_nSequence" ),
// SendPropExclude( "DT_LocalActiveWeaponData", "m_flTimeWeaponIdle" ),
#endif
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CWeaponPortalBase )
END_PREDICTION_DATA()
LINK_ENTITY_TO_CLASS( weapon_portal_base, CWeaponPortalBase );
#ifdef GAME_DLL
BEGIN_DATADESC( CWeaponPortalBase )
END_DATADESC()
#endif
// ----------------------------------------------------------------------------- //
// CWeaponPortalBase implementation.
// ----------------------------------------------------------------------------- //
CWeaponPortalBase::CWeaponPortalBase()
{
SetPredictionEligible( true );
AddSolidFlags( FSOLID_TRIGGER ); // Nothing collides with these but it gets touches.
m_flNextResetCheckTime = 0.0f;
}
bool CWeaponPortalBase::IsPredicted() const
{
return false;
}
void CWeaponPortalBase::WeaponSound( WeaponSound_t sound_type, float soundtime /* = 0.0f */ )
{
#ifdef CLIENT_DLL
// If we have some sounds from the weapon classname.txt file, play a random one of them
const char *shootsound = GetWpnData().aShootSounds[ sound_type ];
if ( !shootsound || !shootsound[0] )
return;
CBroadcastRecipientFilter filter; // this is client side only
if ( !te->CanPredict() )
return;
CBaseEntity::EmitSound( filter, GetPlayerOwner()->entindex(), shootsound, &GetPlayerOwner()->GetAbsOrigin() );
#else
BaseClass::WeaponSound( sound_type, soundtime );
#endif
}
CBasePlayer* CWeaponPortalBase::GetPlayerOwner() const
{
return dynamic_cast< CBasePlayer* >( GetOwner() );
}
CPortal_Player* CWeaponPortalBase::GetPortalPlayerOwner() const
{
return dynamic_cast< CPortal_Player* >( GetOwner() );
}
#ifdef CLIENT_DLL
void CWeaponPortalBase::OnDataChanged( DataUpdateType_t type )
{
BaseClass::OnDataChanged( type );
if ( GetPredictable() && !ShouldPredict() )
ShutdownPredictable();
}
int CWeaponPortalBase::DrawModel( int flags )
{
if ( !m_bReadyToDraw )
return 0;
if ( GetOwner() && (GetOwner() == C_BasePlayer::GetLocalPlayer()) && !g_pPortalRender->IsRenderingPortal() && !C_BasePlayer::ShouldDrawLocalPlayer() )
return 0;
//Sometimes the return value of ShouldDrawLocalPlayer() fluctuates too often to draw the correct model all the time, so this is a quick fix if it's changed too fast
int iOriginalIndex = GetModelIndex();
bool bChangeModelBack = false;
int iWorldModelIndex = GetWorldModelIndex();
if( iOriginalIndex != iWorldModelIndex )
{
SetModelIndex( iWorldModelIndex );
bChangeModelBack = true;
}
int iRetVal = BaseClass::DrawModel( flags );
if( bChangeModelBack )
SetModelIndex( iOriginalIndex );
return iRetVal;
}
bool CWeaponPortalBase::ShouldDraw( void )
{
if ( !GetOwner() || GetOwner() != C_BasePlayer::GetLocalPlayer() )
return true;
if ( !IsActiveByLocalPlayer() )
return false;
//if ( GetOwner() && GetOwner() == C_BasePlayer::GetLocalPlayer() && materials->GetRenderTarget() == 0 )
// return false;
return true;
}
bool CWeaponPortalBase::ShouldPredict()
{
if ( GetOwner() && GetOwner() == C_BasePlayer::GetLocalPlayer() )
return true;
return BaseClass::ShouldPredict();
}
//-----------------------------------------------------------------------------
// Purpose: Draw the weapon's crosshair
//-----------------------------------------------------------------------------
void CWeaponPortalBase::DrawCrosshair()
{
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
if ( !player )
return;
Color clr = gHUD.m_clrNormal;
CHudCrosshair *crosshair = GET_HUDELEMENT( CHudCrosshair );
if ( !crosshair )
return;
// Check to see if the player is in VGUI mode...
if (player->IsInVGuiInputMode())
{
CHudTexture *pArrow = gHUD.GetIcon( "arrow" );
crosshair->SetCrosshair( pArrow, gHUD.m_clrNormal );
return;
}
// Find out if this weapon's auto-aimed onto a target
bool bOnTarget = ( m_iState == WEAPON_IS_ONTARGET );
if ( player->GetFOV() >= 90 )
{
// normal crosshairs
if ( bOnTarget && GetWpnData().iconAutoaim )
{
clr[3] = 255;
crosshair->SetCrosshair( GetWpnData().iconAutoaim, clr );
}
else if ( GetWpnData().iconCrosshair )
{
clr[3] = 255;
crosshair->SetCrosshair( GetWpnData().iconCrosshair, clr );
}
else
{
crosshair->ResetCrosshair();
}
}
else
{
Color white( 255, 255, 255, 255 );
// zoomed crosshairs
if (bOnTarget && GetWpnData().iconZoomedAutoaim)
crosshair->SetCrosshair(GetWpnData().iconZoomedAutoaim, white);
else if ( GetWpnData().iconZoomedCrosshair )
crosshair->SetCrosshair( GetWpnData().iconZoomedCrosshair, white );
else
crosshair->ResetCrosshair();
}
}
void CWeaponPortalBase::DoAnimationEvents( CStudioHdr *pStudioHdr )
{
// HACK: Because this model renders view and world models in the same frame
// it's using the wrong studio model when checking the sequences.
C_BasePlayer *pPlayer = UTIL_PlayerByIndex( 1 );
if ( pPlayer && pPlayer->GetActiveWeapon() == this )
{
C_BaseViewModel *pViewModel = pPlayer->GetViewModel();
if ( pViewModel )
{
pStudioHdr = pViewModel->GetModelPtr();
}
}
if ( pStudioHdr )
{
BaseClass::DoAnimationEvents( pStudioHdr );
}
}
void CWeaponPortalBase::GetRenderBounds( Vector& theMins, Vector& theMaxs )
{
if ( IsRagdoll() )
{
m_pRagdoll->GetRagdollBounds( theMins, theMaxs );
}
else if ( GetModel() )
{
CStudioHdr *pStudioHdr = NULL;
// HACK: Because this model renders view and world models in the same frame
// it's using the wrong studio model when checking the sequences.
C_BasePlayer *pPlayer = UTIL_PlayerByIndex( 1 );
if ( pPlayer && pPlayer->GetActiveWeapon() == this )
{
C_BaseViewModel *pViewModel = pPlayer->GetViewModel();
if ( pViewModel )
{
pStudioHdr = pViewModel->GetModelPtr();
}
}
else
{
pStudioHdr = GetModelPtr();
}
if ( !pStudioHdr || !pStudioHdr->SequencesAvailable() || GetSequence() == -1 )
{
theMins = vec3_origin;
theMaxs = vec3_origin;
return;
}
if (!VectorCompare( vec3_origin, pStudioHdr->view_bbmin() ) || !VectorCompare( vec3_origin, pStudioHdr->view_bbmax() ))
{
// clipping bounding box
VectorCopy ( pStudioHdr->view_bbmin(), theMins);
VectorCopy ( pStudioHdr->view_bbmax(), theMaxs);
}
else
{
// movement bounding box
VectorCopy ( pStudioHdr->hull_min(), theMins);
VectorCopy ( pStudioHdr->hull_max(), theMaxs);
}
mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( GetSequence() );
VectorMin( seqdesc.bbmin, theMins, theMins );
VectorMax( seqdesc.bbmax, theMaxs, theMaxs );
}
else
{
theMins = vec3_origin;
theMaxs = vec3_origin;
}
}
#else
void CWeaponPortalBase::Spawn()
{
BaseClass::Spawn();
// Set this here to allow players to shoot dropped weapons
SetCollisionGroup( COLLISION_GROUP_WEAPON );
// Use less bloat for the collision box for this weapon. (bug 43800)
CollisionProp()->UseTriggerBounds( true, 20 );
}
void CWeaponPortalBase:: Materialize( void )
{
if ( IsEffectActive( EF_NODRAW ) )
{
// changing from invisible state to visible.
EmitSound( "AlyxEmp.Charge" );
RemoveEffects( EF_NODRAW );
DoMuzzleFlash();
}
if ( HasSpawnFlags( SF_NORESPAWN ) == false )
{
VPhysicsInitNormal( SOLID_BBOX, GetSolidFlags() | FSOLID_TRIGGER, false );
SetMoveType( MOVETYPE_VPHYSICS );
//PortalRules()->AddLevelDesignerPlacedObject( this );
}
if ( HasSpawnFlags( SF_NORESPAWN ) == false )
{
if ( GetOriginalSpawnOrigin() == vec3_origin )
{
m_vOriginalSpawnOrigin = GetAbsOrigin();
m_vOriginalSpawnAngles = GetAbsAngles();
}
}
SetPickupTouch();
SetThink (NULL);
}
#endif
const CPortalSWeaponInfo &CWeaponPortalBase::GetPortalWpnData() const
{
const FileWeaponInfo_t *pWeaponInfo = &GetWpnData();
const CPortalSWeaponInfo *pPortalInfo;
#ifdef _DEBUG
pPortalInfo = dynamic_cast< const CPortalSWeaponInfo* >( pWeaponInfo );
Assert( pPortalInfo );
#else
pPortalInfo = static_cast< const CPortalSWeaponInfo* >( pWeaponInfo );
#endif
return *pPortalInfo;
}
void CWeaponPortalBase::FireBullets( const FireBulletsInfo_t &info )
{
FireBulletsInfo_t modinfo = info;
modinfo.m_iPlayerDamage = GetPortalWpnData().m_iPlayerDamage;
BaseClass::FireBullets( modinfo );
}
#if defined( CLIENT_DLL )
#include "c_te_effect_dispatch.h"
#define NUM_MUZZLE_FLASH_TYPES 4
bool CWeaponPortalBase::OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options )
{
return BaseClass::OnFireEvent( pViewModel, origin, angles, event, options );
}
void UTIL_ClipPunchAngleOffset( QAngle &in, const QAngle &punch, const QAngle &clip )
{
QAngle final = in + punch;
//Clip each component
for ( int i = 0; i < 3; i++ )
{
if ( final[i] > clip[i] )
{
final[i] = clip[i];
}
else if ( final[i] < -clip[i] )
{
final[i] = -clip[i];
}
//Return the result
in[i] = final[i] - punch[i];
}
}
#endif
+132
View File
@@ -0,0 +1,132 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef WEAPON_PORTALBASE_H
#define WEAPON_PORTALBASE_H
#ifdef _WIN32
#pragma once
#endif
#include "basecombatweapon_shared.h"
#include "portal_weapon_parse.h"
#if defined( CLIENT_DLL )
#define CWeaponPortalBase C_WeaponPortalBase
void UTIL_ClipPunchAngleOffset( QAngle &in, const QAngle &punch, const QAngle &clip );
#endif
class CPortal_Player;
// These are the names of the ammo types that go in the CAmmoDefs and that the
// weapon script files reference.
// Given an ammo type (like from a weapon's GetPrimaryAmmoType()), this compares it
// against the ammo name you specify.
// MIKETODO: this should use indexing instead of searching and strcmp()'ing all the time.
bool IsAmmoType( int iAmmoType, const char *pAmmoName );
typedef enum
{
WEAPON_NONE = 0,
//Melee
WEAPON_CROWBAR,
//Special
WEAPON_PORTALGUN,
WEAPON_PHYSCANNON,
//Pistols
WEAPON_PISTOL,
WEAPON_357,
//Machineguns
WEAPON_SMG,
WEAPON_AR2,
//Grenades
WEAPON_FRAG,
WEAPON_BUGBAIT,
//Other
WEAPON_SHOTGUN,
WEAPON_CROSSBOW,
WEAPON_RPG,
WEAPON_MAX, // number of weapons weapon index
} PortalWeaponID;
class CWeaponPortalBase : public CBaseCombatWeapon
{
public:
DECLARE_CLASS( CWeaponPortalBase, CBaseCombatWeapon );
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
CWeaponPortalBase();
#ifdef GAME_DLL
DECLARE_DATADESC();
void SendReloadSoundEvent( void );
void Materialize( void );
#endif
// All predicted weapons need to implement and return true
virtual bool IsPredicted() const;
CBasePlayer* GetPlayerOwner() const;
CPortal_Player* GetPortalPlayerOwner() const;
// Get specific Portal weapon ID (ie: WEAPON_PORTALGUN, etc)
virtual PortalWeaponID GetWeaponID( void ) const { return WEAPON_NONE; }
void WeaponSound( WeaponSound_t sound_type, float soundtime = 0.0f );
CPortalSWeaponInfo const &GetPortalWpnData() const;
virtual void FireBullets( const FireBulletsInfo_t &info );
public:
#if defined( CLIENT_DLL )
virtual int DrawModel( int flags );
virtual bool ShouldDraw( void );
virtual bool ShouldDrawCrosshair( void ) { return true; }
virtual bool ShouldPredict();
virtual void OnDataChanged( DataUpdateType_t type );
virtual void DrawCrosshair();
virtual void DoAnimationEvents( CStudioHdr *pStudio );
virtual void GetRenderBounds( Vector& theMins, Vector& theMaxs );
virtual bool OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options );
#else
virtual void Spawn();
#endif
float m_flPrevAnimTime;
float m_flNextResetCheckTime;
Vector GetOriginalSpawnOrigin( void ) { return m_vOriginalSpawnOrigin; }
QAngle GetOriginalSpawnAngles( void ) { return m_vOriginalSpawnAngles; }
private:
CWeaponPortalBase( const CWeaponPortalBase & );
Vector m_vOriginalSpawnOrigin;
QAngle m_vOriginalSpawnAngles;
};
#endif // WEAPON_PORTALBASE_H
@@ -0,0 +1,422 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "weapon_portalbasecombatweapon.h"
#include "portal_player_shared.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
LINK_ENTITY_TO_CLASS( baseportalcombatweapon, CBasePortalCombatWeapon );
IMPLEMENT_NETWORKCLASS_ALIASED( BasePortalCombatWeapon , DT_BasePortalCombatWeapon )
BEGIN_NETWORK_TABLE( CBasePortalCombatWeapon , DT_BasePortalCombatWeapon )
#if !defined( CLIENT_DLL )
// SendPropInt( SENDINFO( m_bReflectViewModelAnimations ), 1, SPROP_UNSIGNED ),
#else
// RecvPropInt( RECVINFO( m_bReflectViewModelAnimations ) ),
#endif
END_NETWORK_TABLE()
#if !defined( CLIENT_DLL )
#include "globalstate.h"
//---------------------------------------------------------
// Save/Restore
//---------------------------------------------------------
BEGIN_DATADESC( CBasePortalCombatWeapon )
DEFINE_FIELD( m_bLowered, FIELD_BOOLEAN ),
DEFINE_FIELD( m_flRaiseTime, FIELD_TIME ),
DEFINE_FIELD( m_flHolsterTime, FIELD_TIME ),
END_DATADESC()
#endif
BEGIN_PREDICTION_DATA( CBasePortalCombatWeapon )
END_PREDICTION_DATA()
extern ConVar sk_auto_reload_time;
CBasePortalCombatWeapon::CBasePortalCombatWeapon( void )
{
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBasePortalCombatWeapon::ItemHolsterFrame( void )
{
BaseClass::ItemHolsterFrame();
// Must be player held
if ( GetOwner() && GetOwner()->IsPlayer() == false )
return;
// We can't be active
if ( GetOwner()->GetActiveWeapon() == this )
return;
// If it's been longer than three seconds, reload
if ( ( gpGlobals->curtime - m_flHolsterTime ) > sk_auto_reload_time.GetFloat() )
{
// Just load the clip with no animations
FinishReload();
m_flHolsterTime = gpGlobals->curtime;
}
}
bool CBasePortalCombatWeapon::CanLower()
{
if ( SelectWeightedSequence( ACT_VM_IDLE_LOWERED ) == ACTIVITY_NOT_AVAILABLE )
return false;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Drops the weapon into a lowered pose
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CBasePortalCombatWeapon::Lower( void )
{
//Don't bother if we don't have the animation
if ( SelectWeightedSequence( ACT_VM_IDLE_LOWERED ) == ACTIVITY_NOT_AVAILABLE )
return false;
m_bLowered = true;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Brings the weapon up to the ready position
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CBasePortalCombatWeapon::Ready( void )
{
//Don't bother if we don't have the animation
if ( SelectWeightedSequence( ACT_VM_LOWERED_TO_IDLE ) == ACTIVITY_NOT_AVAILABLE )
return false;
m_bLowered = false;
m_flRaiseTime = gpGlobals->curtime + 0.5f;
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CBasePortalCombatWeapon::Deploy( void )
{
// If we should be lowered, deploy in the lowered position
// We have to ask the player if the last time it checked, the weapon was lowered
if ( GetOwner() && GetOwner()->IsPlayer() )
{
CPortal_Player *pPlayer = assert_cast<CPortal_Player*>( GetOwner() );
if ( pPlayer->IsWeaponLowered() )
{
if ( SelectWeightedSequence( ACT_VM_IDLE_LOWERED ) != ACTIVITY_NOT_AVAILABLE )
{
if ( DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), ACT_VM_IDLE_LOWERED, (char*)GetAnimPrefix() ) )
{
m_bLowered = true;
// Stomp the next attack time to fix the fact that the lower idles are long
pPlayer->SetNextAttack( gpGlobals->curtime + 1.0 );
m_flNextPrimaryAttack = gpGlobals->curtime + 1.0;
m_flNextSecondaryAttack = gpGlobals->curtime + 1.0;
return true;
}
}
}
}
m_bLowered = false;
return BaseClass::Deploy();
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CBasePortalCombatWeapon::Holster( CBaseCombatWeapon *pSwitchingTo )
{
if ( BaseClass::Holster( pSwitchingTo ) )
{
m_flHolsterTime = gpGlobals->curtime;
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CBasePortalCombatWeapon::WeaponShouldBeLowered( void )
{
// Can't be in the middle of another animation
if ( GetIdealActivity() != ACT_VM_IDLE_LOWERED && GetIdealActivity() != ACT_VM_IDLE &&
GetIdealActivity() != ACT_VM_IDLE_TO_LOWERED && GetIdealActivity() != ACT_VM_LOWERED_TO_IDLE )
return false;
if ( m_bLowered )
return true;
#if !defined( CLIENT_DLL )
if ( GlobalEntity_GetState( "friendly_encounter" ) == GLOBAL_ON )
return true;
#endif
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Allows the weapon to choose proper weapon idle animation
//-----------------------------------------------------------------------------
void CBasePortalCombatWeapon::WeaponIdle( void )
{
//See if we should idle high or low
if ( WeaponShouldBeLowered() )
{
// Move to lowered position if we're not there yet
if ( GetActivity() != ACT_VM_IDLE_LOWERED && GetActivity() != ACT_VM_IDLE_TO_LOWERED
&& GetActivity() != ACT_TRANSITION )
{
SendWeaponAnim( ACT_VM_IDLE_LOWERED );
}
else if ( HasWeaponIdleTimeElapsed() )
{
// Keep idling low
SendWeaponAnim( ACT_VM_IDLE_LOWERED );
}
}
else
{
// See if we need to raise immediately
if ( m_flRaiseTime < gpGlobals->curtime && GetActivity() == ACT_VM_IDLE_LOWERED )
{
SendWeaponAnim( ACT_VM_IDLE );
}
else if ( HasWeaponIdleTimeElapsed() )
{
SendWeaponAnim( ACT_VM_IDLE );
}
}
}
#if defined( CLIENT_DLL )
#define HL2_BOB_CYCLE_MIN 1.0f
#define HL2_BOB_CYCLE_MAX 0.45f
#define HL2_BOB 0.002f
#define HL2_BOB_UP 0.5f
extern float g_lateralBob;
extern float g_verticalBob;
static ConVar cl_bobcycle( "cl_bobcycle","0.8" );
static ConVar cl_bob( "cl_bob","0.002" );
static ConVar cl_bobup( "cl_bobup","0.5" );
// Register these cvars if needed for easy tweaking
static ConVar v_iyaw_cycle( "v_iyaw_cycle", "2", FCVAR_REPLICATED | FCVAR_CHEAT );
static ConVar v_iroll_cycle( "v_iroll_cycle", "0.5", FCVAR_REPLICATED | FCVAR_CHEAT );
static ConVar v_ipitch_cycle( "v_ipitch_cycle", "1", FCVAR_REPLICATED | FCVAR_CHEAT );
static ConVar v_iyaw_level( "v_iyaw_level", "0.3", FCVAR_REPLICATED | FCVAR_CHEAT );
static ConVar v_iroll_level( "v_iroll_level", "0.1", FCVAR_REPLICATED | FCVAR_CHEAT );
static ConVar v_ipitch_level( "v_ipitch_level", "0.3", FCVAR_REPLICATED | FCVAR_CHEAT );
//-----------------------------------------------------------------------------
// Purpose:
// Output : float
//-----------------------------------------------------------------------------
float CBasePortalCombatWeapon::CalcViewmodelBob( void )
{
static float bobtime;
static float lastbobtime;
float cycle;
CBasePlayer *player = ToBasePlayer( GetOwner() );
//Assert( player );
//NOTENOTE: For now, let this cycle continue when in the air, because it snaps badly without it
if ( ( !gpGlobals->frametime ) || ( player == NULL ) )
{
//NOTENOTE: We don't use this return value in our case (need to restructure the calculation function setup!)
return 0.0f;// just use old value
}
//Find the speed of the player
float speed = player->GetLocalVelocity().Length2D();
//FIXME: This maximum speed value must come from the server.
// MaxSpeed() is not sufficient for dealing with sprinting - jdw
speed = clamp( speed, -320, 320 );
float bob_offset = RemapVal( speed, 0, 320, 0.0f, 1.0f );
bobtime += ( gpGlobals->curtime - lastbobtime ) * bob_offset;
lastbobtime = gpGlobals->curtime;
//Calculate the vertical bob
cycle = bobtime - (int)(bobtime/HL2_BOB_CYCLE_MAX)*HL2_BOB_CYCLE_MAX;
cycle /= HL2_BOB_CYCLE_MAX;
if ( cycle < HL2_BOB_UP )
{
cycle = M_PI * cycle / HL2_BOB_UP;
}
else
{
cycle = M_PI + M_PI*(cycle-HL2_BOB_UP)/(1.0 - HL2_BOB_UP);
}
g_verticalBob = speed*0.005f;
g_verticalBob = g_verticalBob*0.3 + g_verticalBob*0.7*sin(cycle);
g_verticalBob = clamp( g_verticalBob, -7.0f, 4.0f );
//Calculate the lateral bob
cycle = bobtime - (int)(bobtime/HL2_BOB_CYCLE_MAX*2)*HL2_BOB_CYCLE_MAX*2;
cycle /= HL2_BOB_CYCLE_MAX*2;
if ( cycle < HL2_BOB_UP )
{
cycle = M_PI * cycle / HL2_BOB_UP;
}
else
{
cycle = M_PI + M_PI*(cycle-HL2_BOB_UP)/(1.0 - HL2_BOB_UP);
}
g_lateralBob = speed*0.005f;
g_lateralBob = g_lateralBob*0.3 + g_lateralBob*0.7*sin(cycle);
g_lateralBob = clamp( g_lateralBob, -7.0f, 4.0f );
//NOTENOTE: We don't use this return value in our case (need to restructure the calculation function setup!)
return 0.0f;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &origin -
// &angles -
// viewmodelindex -
//-----------------------------------------------------------------------------
void CBasePortalCombatWeapon::AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles )
{
Vector forward, right;
AngleVectors( angles, &forward, &right, NULL );
CalcViewmodelBob();
// Apply bob, but scaled down to 40%
VectorMA( origin, g_verticalBob * 0.1f, forward, origin );
// Z bob a bit more
origin[2] += g_verticalBob * 0.1f;
// bob the angles
angles[ ROLL ] += g_verticalBob * 0.5f;
angles[ PITCH ] -= g_verticalBob * 0.4f;
angles[ YAW ] -= g_lateralBob * 0.3f;
VectorMA( origin, g_lateralBob * 0.8f, right, origin );
}
//-----------------------------------------------------------------------------
Vector CBasePortalCombatWeapon::GetBulletSpread( WeaponProficiency_t proficiency )
{
return BaseClass::GetBulletSpread( proficiency );
}
//-----------------------------------------------------------------------------
float CBasePortalCombatWeapon::GetSpreadBias( WeaponProficiency_t proficiency )
{
return BaseClass::GetSpreadBias( proficiency );
}
//-----------------------------------------------------------------------------
const WeaponProficiencyInfo_t *CBasePortalCombatWeapon::GetProficiencyValues()
{
return NULL;
}
#else
// Server stubs
float CBasePortalCombatWeapon::CalcViewmodelBob( void )
{
return 0.0f;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &origin -
// &angles -
// viewmodelindex -
//-----------------------------------------------------------------------------
void CBasePortalCombatWeapon::AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles )
{
}
//-----------------------------------------------------------------------------
Vector CBasePortalCombatWeapon::GetBulletSpread( WeaponProficiency_t proficiency )
{
Vector baseSpread = BaseClass::GetBulletSpread( proficiency );
const WeaponProficiencyInfo_t *pProficiencyValues = GetProficiencyValues();
float flModifier = (pProficiencyValues)[ proficiency ].spreadscale;
return ( baseSpread * flModifier );
}
//-----------------------------------------------------------------------------
float CBasePortalCombatWeapon::GetSpreadBias( WeaponProficiency_t proficiency )
{
const WeaponProficiencyInfo_t *pProficiencyValues = GetProficiencyValues();
return (pProficiencyValues)[ proficiency ].bias;
}
//-----------------------------------------------------------------------------
const WeaponProficiencyInfo_t *CBasePortalCombatWeapon::GetProficiencyValues()
{
return GetDefaultProficiencyValues();
}
//-----------------------------------------------------------------------------
const WeaponProficiencyInfo_t *CBasePortalCombatWeapon::GetDefaultProficiencyValues()
{
// Weapon proficiency table. Keep this in sync with WeaponProficiency_t enum in the header!!
static WeaponProficiencyInfo_t g_BaseWeaponProficiencyTable[] =
{
{ 2.50, 1.0 },
{ 2.00, 1.0 },
{ 1.50, 1.0 },
{ 1.25, 1.0 },
{ 1.00, 1.0 },
};
COMPILE_TIME_ASSERT( ARRAYSIZE(g_BaseWeaponProficiencyTable) == WEAPON_PROFICIENCY_PERFECT + 1);
return g_BaseWeaponProficiencyTable;
}
#endif
@@ -0,0 +1,69 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifdef CLIENT_DLL
#include "c_portal_player.h"
#else
#include "portal_player.h"
#endif
#include "weapon_portalbase.h"
#ifndef WEAPON_BASEPORTALCOMBATWEAPON_SHARED_H
#define WEAPON_BASEPORTALCOMBATWEAPON_SHARED_H
#ifdef _WIN32
#pragma once
#endif
#if defined( CLIENT_DLL )
#define CBasePortalCombatWeapon C_BasePortalCombatWeapon
#endif
class CBasePortalCombatWeapon : public CWeaponPortalBase
{
#if !defined( CLIENT_DLL )
DECLARE_DATADESC();
#endif
DECLARE_CLASS( CBasePortalCombatWeapon, CWeaponPortalBase );
public:
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
CBasePortalCombatWeapon();
virtual bool WeaponShouldBeLowered( void );
bool CanLower( void );
virtual bool Ready( void );
virtual bool Lower( void );
virtual bool Deploy( void );
virtual bool Holster( CBaseCombatWeapon *pSwitchingTo );
virtual void WeaponIdle( void );
virtual void AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles );
virtual float CalcViewmodelBob( void );
virtual Vector GetBulletSpread( WeaponProficiency_t proficiency );
virtual float GetSpreadBias( WeaponProficiency_t proficiency );
virtual const WeaponProficiencyInfo_t *GetProficiencyValues();
static const WeaponProficiencyInfo_t *GetDefaultProficiencyValues();
virtual void ItemHolsterFrame( void );
protected:
bool m_bLowered; // Whether the viewmodel is raised or lowered
float m_flRaiseTime; // If lowered, the time we should raise the viewmodel
float m_flHolsterTime; // When the weapon was holstered
private:
CBasePortalCombatWeapon( const CBasePortalCombatWeapon & );
};
#endif // WEAPON_BASEPORTALCOMBATWEAPON_SHARED_H
@@ -0,0 +1,456 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "weapon_portalgun_shared.h"
#include "npcevent.h"
#include "in_buttons.h"
#include "rumble_shared.h"
#include "prop_portal_shared.h"
#ifdef CLIENT_DLL
#define CWeaponPortalgun C_WeaponPortalgun
#endif //#ifdef CLIENT_DLL
acttable_t CWeaponPortalgun::m_acttable[] =
{
{ ACT_MP_STAND_IDLE, ACT_MP_STAND_PRIMARY, false },
{ ACT_MP_RUN, ACT_MP_RUN_PRIMARY, false },
{ ACT_MP_CROUCH_IDLE, ACT_MP_CROUCH_PRIMARY, false },
{ ACT_MP_CROUCHWALK, ACT_MP_CROUCHWALK_PRIMARY, false },
{ ACT_MP_JUMP_START, ACT_MP_JUMP_START_PRIMARY, false },
{ ACT_MP_JUMP_FLOAT, ACT_MP_JUMP_FLOAT_PRIMARY, false },
{ ACT_MP_JUMP_LAND, ACT_MP_JUMP_LAND_PRIMARY, false },
{ ACT_MP_AIRWALK, ACT_MP_AIRWALK_PRIMARY, false },
};
IMPLEMENT_ACTTABLE(CWeaponPortalgun);
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CWeaponPortalgun::CWeaponPortalgun( void )
{
m_bReloadsSingly = true;
// TODO: specify these in hammer instead of assuming every gun has blue chip
m_bCanFirePortal1 = true;
m_bCanFirePortal2 = false;
m_iLastFiredPortal = 0;
m_fCanPlacePortal1OnThisSurface = 1.0f;
m_fCanPlacePortal2OnThisSurface = 1.0f;
m_fMinRange1 = 0.0f;
m_fMaxRange1 = MAX_TRACE_LENGTH;
m_fMinRange2 = 0.0f;
m_fMaxRange2 = MAX_TRACE_LENGTH;
m_EffectState = (int)EFFECT_NONE;
}
void CWeaponPortalgun::Precache()
{
BaseClass::Precache();
PrecacheModel( PORTALGUN_BEAM_SPRITE );
PrecacheModel( PORTALGUN_BEAM_SPRITE_NOZ );
PrecacheModel( "models/portals/portal1.mdl" );
PrecacheModel( "models/portals/portal2.mdl" );
PrecacheScriptSound( "Portal.ambient_loop" );
PrecacheScriptSound( "Portal.open_blue" );
PrecacheScriptSound( "Portal.open_red" );
PrecacheScriptSound( "Portal.close_blue" );
PrecacheScriptSound( "Portal.close_red" );
PrecacheScriptSound( "Portal.fizzle_moved" );
PrecacheScriptSound( "Portal.fizzle_invalid_surface" );
PrecacheScriptSound( "Weapon_Portalgun.powerup" );
PrecacheScriptSound( "Weapon_PhysCannon.HoldSound" );
#ifndef CLIENT_DLL
PrecacheParticleSystem( "portal_1_projectile_stream" );
PrecacheParticleSystem( "portal_1_projectile_stream_pedestal" );
PrecacheParticleSystem( "portal_2_projectile_stream" );
PrecacheParticleSystem( "portal_2_projectile_stream_pedestal" );
PrecacheParticleSystem( "portal_1_charge" );
PrecacheParticleSystem( "portal_2_charge" );
#endif
}
PRECACHE_WEAPON_REGISTER(weapon_portalgun);
bool CWeaponPortalgun::ShouldDrawCrosshair( void )
{
return true;//( m_fCanPlacePortal1OnThisSurface > 0.5f || m_fCanPlacePortal2OnThisSurface > 0.5f );
}
//-----------------------------------------------------------------------------
// Purpose: Override so only reload one shell at a time
// Input :
// Output :
//-----------------------------------------------------------------------------
bool CWeaponPortalgun::Reload( void )
{
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Play finish reload anim and fill clip
// Input :
// Output :
//-----------------------------------------------------------------------------
void CWeaponPortalgun::FillClip( void )
{
CBaseCombatCharacter *pOwner = GetOwner();
if ( pOwner == NULL )
return;
// Add them to the clip
if ( pOwner->GetAmmoCount( m_iPrimaryAmmoType ) > 0 )
{
if ( Clip1() < GetMaxClip1() )
{
m_iClip1++;
pOwner->RemoveAmmo( 1, m_iPrimaryAmmoType );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//
//
//-----------------------------------------------------------------------------
void CWeaponPortalgun::DryFire( void )
{
WeaponSound(EMPTY);
SendWeaponAnim( ACT_VM_DRYFIRE );
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
}
void CWeaponPortalgun::SetCanFirePortal1( bool bCanFire /*= true*/ )
{
m_bCanFirePortal1 = bCanFire;
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
if ( pOwner == NULL )
return;
if ( !m_bOpenProngs )
{
DoEffect( EFFECT_HOLDING );
DoEffect( EFFECT_READY );
}
// TODO: Remove muzzle flash when there's an upgrade animation
pOwner->DoMuzzleFlash();
// Don't fire again until fire animation has completed
m_flNextPrimaryAttack = gpGlobals->curtime + 0.25f;
m_flNextSecondaryAttack = gpGlobals->curtime + 0.25f;
// player "shoot" animation
pOwner->SetAnimation( PLAYER_ATTACK1 );
pOwner->ViewPunch( QAngle( random->RandomFloat( -1, -0.5f ), random->RandomFloat( -1, 1 ), 0 ) );
EmitSound( "Weapon_Portalgun.powerup" );
}
void CWeaponPortalgun::SetCanFirePortal2( bool bCanFire /*= true*/ )
{
m_bCanFirePortal2 = bCanFire;
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
if ( pOwner == NULL )
return;
if ( !m_bOpenProngs )
{
DoEffect( EFFECT_HOLDING );
DoEffect( EFFECT_READY );
}
// TODO: Remove muzzle flash when there's an upgrade animation
pOwner->DoMuzzleFlash();
// Don't fire again until fire animation has completed
m_flNextPrimaryAttack = gpGlobals->curtime + 0.5f;
m_flNextSecondaryAttack = gpGlobals->curtime + 0.5f;
// player "shoot" animation
pOwner->SetAnimation( PLAYER_ATTACK1 );
pOwner->ViewPunch( QAngle( random->RandomFloat( -1, -0.5f ), random->RandomFloat( -1, 1 ), 0 ) );
EmitSound( "Weapon_Portalgun.powerup" );
}
//-----------------------------------------------------------------------------
// Purpose:
//
//
//-----------------------------------------------------------------------------
void CWeaponPortalgun::PrimaryAttack( void )
{
if ( !CanFirePortal1() )
return;
// Only the player fires this way so we can cast
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
if (!pPlayer)
{
return;
}
#ifndef CLIENT_DLL
inputdata_t inputdata;
inputdata.pActivator = this;
inputdata.pCaller = this;
inputdata.value;//null
FirePortal1( inputdata );
m_OnFiredPortal1.FireOutput( pPlayer, this );
pPlayer->RumbleEffect( RUMBLE_PORTALGUN_LEFT, 0, RUMBLE_FLAGS_NONE );
#endif
pPlayer->DoMuzzleFlash();
// Don't fire again until fire animation has completed
m_flNextPrimaryAttack = gpGlobals->curtime + 0.5f;//SequenceDuration();
m_flNextSecondaryAttack = gpGlobals->curtime + 0.5f;//SequenceDuration();
// player "shoot" animation
pPlayer->SetAnimation( PLAYER_ATTACK1 );
pPlayer->ViewPunch( QAngle( random->RandomFloat( -1, -0.5f ), random->RandomFloat( -1, 1 ), 0 ) );
}
//-----------------------------------------------------------------------------
// Purpose:
//
//
//-----------------------------------------------------------------------------
void CWeaponPortalgun::SecondaryAttack( void )
{
if ( !CanFirePortal2() )
return;
// Only the player fires this way so we can cast
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
if (!pPlayer)
{
return;
}
#ifndef CLIENT_DLL
inputdata_t inputdata;
inputdata.pActivator = this;
inputdata.pCaller = this;
inputdata.value;//null
FirePortal2( inputdata );
m_OnFiredPortal2.FireOutput( pPlayer, this );
pPlayer->RumbleEffect( RUMBLE_PORTALGUN_RIGHT, 0, RUMBLE_FLAGS_NONE );
#endif
pPlayer->DoMuzzleFlash();
// Don't fire again until fire animation has completed
m_flNextPrimaryAttack = gpGlobals->curtime + 0.5f;//SequenceDuration();
m_flNextSecondaryAttack = gpGlobals->curtime + 0.5f;//SequenceDuration();
// player "shoot" animation
pPlayer->SetAnimation( PLAYER_ATTACK1 );
pPlayer->ViewPunch( QAngle( random->RandomFloat( -1, -0.5f ), random->RandomFloat( -1, 1 ), 0 ) );
}
void CWeaponPortalgun::DelayAttack( float fDelay )
{
m_flNextPrimaryAttack = gpGlobals->curtime + fDelay;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponPortalgun::ItemHolsterFrame( void )
{
// Must be player held
if ( GetOwner() && GetOwner()->IsPlayer() == false )
return;
// We can't be active
if ( GetOwner()->GetActiveWeapon() == this )
return;
// If it's been longer than three seconds, reload
if ( ( gpGlobals->curtime - m_flHolsterTime ) > sk_auto_reload_time.GetFloat() )
{
// Reset the timer
m_flHolsterTime = gpGlobals->curtime;
if ( GetOwner() == NULL )
return;
if ( m_iClip1 == GetMaxClip1() )
return;
// Just load the clip with no animations
int ammoFill = MIN( (GetMaxClip1() - m_iClip1), GetOwner()->GetAmmoCount( GetPrimaryAmmoType() ) );
GetOwner()->RemoveAmmo( ammoFill, GetPrimaryAmmoType() );
m_iClip1 += ammoFill;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CWeaponPortalgun::Holster( CBaseCombatWeapon *pSwitchingTo )
{
DestroyEffects();
return BaseClass::Holster( pSwitchingTo );
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CWeaponPortalgun::Deploy( void )
{
DoEffect( EFFECT_READY );
bool bReturn = BaseClass::Deploy();
m_flNextSecondaryAttack = m_flNextPrimaryAttack = gpGlobals->curtime;
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
if ( pOwner )
{
pOwner->SetNextAttack( gpGlobals->curtime );
#ifndef CLIENT_DLL
if( GameRules()->IsMultiplayer() )
{
m_iPortalLinkageGroupID = pOwner->entindex();
Assert( (m_iPortalLinkageGroupID >= 0) && (m_iPortalLinkageGroupID < 256) );
}
#endif
}
return bReturn;
}
void CWeaponPortalgun::WeaponIdle( void )
{
//See if we should idle high or low
if ( WeaponShouldBeLowered() )
{
// Move to lowered position if we're not there yet
if ( GetActivity() != ACT_VM_IDLE_LOWERED && GetActivity() != ACT_VM_IDLE_TO_LOWERED
&& GetActivity() != ACT_TRANSITION )
{
SendWeaponAnim( ACT_VM_IDLE_LOWERED );
}
else if ( HasWeaponIdleTimeElapsed() )
{
// Keep idling low
SendWeaponAnim( ACT_VM_IDLE_LOWERED );
}
}
else
{
// See if we need to raise immediately
if ( m_flRaiseTime < gpGlobals->curtime && GetActivity() == ACT_VM_IDLE_LOWERED )
{
SendWeaponAnim( ACT_VM_IDLE );
}
else if ( HasWeaponIdleTimeElapsed() )
{
SendWeaponAnim( ACT_VM_IDLE );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponPortalgun::StopEffects( bool stopSound )
{
// Turn off our effect state
DoEffect( EFFECT_NONE );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : effectType -
//-----------------------------------------------------------------------------
void CWeaponPortalgun::DoEffect( int effectType, Vector *pos )
{
m_EffectState = effectType;
#ifdef CLIENT_DLL
// Save predicted state
m_nOldEffectState = m_EffectState;
#endif
switch( effectType )
{
case EFFECT_READY:
DoEffectReady();
break;
case EFFECT_HOLDING:
DoEffectHolding();
break;
default:
case EFFECT_NONE:
DoEffectNone();
break;
}
}
//-----------------------------------------------------------------------------
// Purpose: Restore
//-----------------------------------------------------------------------------
void CWeaponPortalgun::OnRestore()
{
BaseClass::OnRestore();
// Portalgun effects disappear through level transition, so
// just recreate any effects here
if ( m_EffectState != EFFECT_NONE )
{
DoEffect( m_EffectState, NULL );
}
}
//-----------------------------------------------------------------------------
// On Remove
//-----------------------------------------------------------------------------
void CWeaponPortalgun::UpdateOnRemove(void)
{
DestroyEffects();
BaseClass::UpdateOnRemove();
}
@@ -0,0 +1,42 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef WEAPON_PORTALGUN_SHARED_H
#define WEAPON_PORTALGUN_SHARED_H
#ifdef _WIN32
#pragma once
#endif
#include "cbase.h"
#ifdef CLIENT_DLL
#include "c_weapon_portalgun.h"
#else
#include "weapon_portalgun.h"
#endif
#define PORTALGUN_BEAM_SPRITE "sprites/grav_beam.vmt"
#define PORTALGUN_BEAM_SPRITE_NOZ "sprites/grav_beam_noz.vmt"
#define PORTALGUN_GLOW_SPRITE "sprites/glow04_noz"
#define PORTALGUN_ENDCAP_SPRITE "sprites/grav_flare"
#define PORTALGUN_GRAV_ACTIVE_GLOW "sprites/grav_light"
#define PORTALGUN_PORTAL1_FIRED_LAST_GLOW "sprites/bluelight"
#define PORTALGUN_PORTAL2_FIRED_LAST_GLOW "sprites/orangelight"
#define PORTALGUN_PORTAL_MUZZLE_GLOW_SPRITE "sprites/portalgun_effects"
#define PORTALGUN_PORTAL_TUBE_BEAM_SPRITE "sprites/portalgun_effects"
enum
{
EFFECT_NONE,
EFFECT_READY,
EFFECT_HOLDING,
};
extern ConVar sk_auto_reload_time;
#endif // WEAPON_PORTALGUN_SHARED_H