mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-07 17:29:36 +00:00
add hl1,portal,dod source code
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user