area51/Support/Trigger/Trigger_Spatial_Object.cpp
Andrew Sampson 431f72b93a source
2021-08-27 19:22:41 -07:00

1179 lines
36 KiB
C++

//=========================================================================
//
// Trigger_Object.cpp
//
//=========================================================================
//=========================================================================
// INCLUDES
//=========================================================================
#include "Trigger\Trigger_Spatial_Object.hpp"
#include "Trigger\Trigger_Manager.hpp"
#include "Entropy.hpp"
#include "Render\editor_icons.hpp"
#include "Objects\BaseProjectile.hpp"
#include "Objects\Player.hpp"
#include "characters\character.hpp"
#include "..\MiscUtils\SimpleUtils.hpp"
#include "..\Support\Inputmgr\GamePad.hpp"
//=========================================================================
// STATIC DEFINITIONS AND CONSTS
//=========================================================================
static f32 s_InitDimValue = 100.0f;
static f32 s_SphereRadius = 100.0f;
static sphere s_EditSphere(vector3(0,0,0), s_SphereRadius);
static xcolor s_ColorAdd(0,0,0);
//=========================================================================
// Spatial type table
trigger_spatial_object::spatial_pair trigger_spatial_object::s_SpatialPairTable[] =
{
spatial_pair("RAY", trigger_spatial_object::TYPE_RAY),
spatial_pair("PLANE", trigger_spatial_object::TYPE_PLANE),
//spatial_pair("CUBIC", trigger_spatial_object::TYPE_CUBIC), //UNIMPLEMENTED
spatial_pair("AXIS_CUBE", trigger_spatial_object::TYPE_AXIS_CUBE),
spatial_pair("SPHERICAL", trigger_spatial_object::TYPE_SPHERICAL),
spatial_pair( k_EnumEndStringConst, trigger_spatial_object::SPATIAL_TYPES_INVALID), //**MUST BE LAST**//
};
trigger_spatial_object::spatial_table trigger_spatial_object::s_SpatialEnumTable(s_SpatialPairTable);
//=========================================================================
// Activation type table
trigger_spatial_object::activation_pair trigger_spatial_object::s_ActivationPairTable[] =
{
activation_pair("BY_OVERRIDE_TYPE", trigger_spatial_object::ACTIVATE_ON_BY_OVERRIDE_TYPE),
activation_pair("PLAYER", trigger_spatial_object::ACTIVATE_ON_PLAYER),
activation_pair("NPC", trigger_spatial_object::ACTIVATE_ON_NPC),
activation_pair("BULLET", trigger_spatial_object::ACTIVATE_ON_BULLET),
activation_pair("NPC_OR_PLAYER", trigger_spatial_object::ACTIVATE_ON_NPC_OR_PLAYER),
activation_pair("ON_USE", trigger_spatial_object::ACTIVATE_ON_USE_EVENT),
activation_pair( k_EnumEndStringConst, trigger_spatial_object::ACTIVATION_TYPES_INVALID), //**MUST BE LAST**//
};
trigger_spatial_object::activation_table trigger_spatial_object::s_ActivationEnumTable(s_ActivationPairTable);
//=========================================================================
// Tesponse type table
trigger_spatial_object::response_pair trigger_spatial_object::s_ResponsePairTable[] =
{
response_pair("IF_STILL_INSIDE", trigger_spatial_object::RESPONSE_IF_STILL_INSIDE),
response_pair("RETURN_TO_SLEEP", trigger_spatial_object::RESPONSE_RETURN_TO_SLEEP),
response_pair("PERMANENT_ON", trigger_spatial_object::RESPONSE_PERMANENT_ON),
response_pair("PERMANENT_OFF", trigger_spatial_object::RESPONSE_PERMANENT_OFF),
response_pair( k_EnumEndStringConst, trigger_spatial_object::ACTIVATION_RESPONSE_TYPE_INVALID), //**MUST BE LAST**//
};
trigger_spatial_object::response_table trigger_spatial_object::s_ResponseEnumTable(s_ResponsePairTable);
//=========================================================================
// OBJECT DESCRIPTION
//=========================================================================
static struct trigger_spatial_object_desc : public object_desc
{
trigger_spatial_object_desc( void ) : object_desc(
object::TYPE_SPATIAL_TRIGGER,
"Spatial Trigger",
"SCRIPT",
object::ATTR_SPACIAL_ENTRY |
object::ATTR_COLLISION_PERMEABLE,
FLAGS_IS_DYNAMIC ) {}
//-------------------------------------------------------------------------
virtual object* Create ( void )
{
return new trigger_spatial_object;
}
//-------------------------------------------------------------------------
#ifdef X_EDITOR
virtual s32 OnEditorRender( object& Object ) const
{
object_desc::OnEditorRender( Object );
draw_Label( Object.GetPosition(), XCOLOR_RED, "<<OBSOLETE>>" );
return EDITOR_ICON_TRIGGER;
}
#endif // X_EDITOR
} s_TriggerSpatialObjectDesc;
//=========================================================================
const object_desc& trigger_spatial_object::GetTypeDesc( void ) const
{
return s_TriggerSpatialObjectDesc;
}
//=========================================================================
const object_desc& trigger_spatial_object::GetObjectType( void )
{
return s_TriggerSpatialObjectDesc;
}
//=========================================================================
//=========================================================================
// TRIGGER_SPATIAL_OBJECT
//=========================================================================
trigger_spatial_object::trigger_spatial_object(void) : trigger_object() ,
m_IsActivated(FALSE),
m_ActivationType(ACTIVATE_ON_PLAYER),
m_SpatialType(TYPE_AXIS_CUBE),
m_ResponseType(RESPONSE_RETURN_TO_SLEEP),
m_TriggerActor(NULL),
m_EventPollingStarted(FALSE),
m_HasPressed(FALSE)
{
for (s32 i = 0; i < MAX_DIMENSIONS_PARAMS; i++)
m_Dimensions[i] = s_InitDimValue;
}
//=========================================================================
trigger_spatial_object::~trigger_spatial_object(void)
{}
//=========================================================================
bbox trigger_spatial_object::GetLocalBBox( void ) const
{
bbox BBox;
switch ( m_SpatialType )
{
case TYPE_RAY:
{
vector3 Min(0,0,0);
vector3 Max(0,0,m_Dimensions[0]);
BBox.Set( Min, Max );
}
break;
case TYPE_PLANE:
{
f32 HalfWidth = m_Dimensions[0]/2;
f32 HalfHeight = m_Dimensions[1]/2;
const f32 MIN_LENGTH = 10;
vector3 Min( -HalfWidth, -HalfHeight, -MIN_LENGTH );
vector3 Max( HalfWidth, HalfHeight, MIN_LENGTH );
BBox.Set( Min, Max );
}
break;
case TYPE_CUBIC:
{
f32 HalfWidth = m_Dimensions[0]/2;
f32 HalfHeight = m_Dimensions[1]/2;
f32 HalfLength = m_Dimensions[2]/2;
vector3 Min( -HalfWidth, -HalfHeight, -HalfLength );
vector3 Max( HalfWidth, HalfHeight, HalfLength );
BBox.Set( Min, Max );
}
break;
case TYPE_AXIS_CUBE:
{
f32 HalfWidth = m_Dimensions[0]/2;
f32 HalfHeight = m_Dimensions[1]/2;
f32 HalfLength = m_Dimensions[2]/2;
vector3 Min( -HalfWidth, -HalfHeight, -HalfLength );
vector3 Max( HalfWidth, HalfHeight, HalfLength );
BBox.Set( Min, Max );
}
break;
case TYPE_SPHERICAL:
{
vector3 Min( -m_Dimensions[0], -m_Dimensions[0], -m_Dimensions[0] );
vector3 Max( m_Dimensions[0], m_Dimensions[0], m_Dimensions[0] );
BBox.Set( Min, Max );
}
break;
default:
ASSERT(0);
break;
}
#ifdef TARGET_PC
vector3 size = BBox.GetSize();
if ( size == vector3(0,0,0) )
BBox = s_EditSphere.GetBBox();
#endif
return BBox;
}
//==============================================================================
#ifndef X_RETAIL
void trigger_spatial_object::OnDebugRender ( void )
{
trigger_object::OnDebugRender();
xcolor DrawColor = m_CurrentColor;
if( GetAttrBits() & ATTR_EDITOR_SELECTED )
{
DrawColor = xcolor(255,0,0);
}
switch ( m_SpatialType )
{
case TYPE_RAY:
{
vector3 vEndpoint(0,0,m_Dimensions[0]);
const matrix4 M = GetL2W();
vEndpoint = M*vEndpoint;
draw_Line( object::GetPosition(), vEndpoint, DrawColor );
}
break;
case TYPE_PLANE:
{
const s32 NumPoints = 6;
vector3 vPoints[NumPoints];
f32 HalfWidth = m_Dimensions[0]/2;
f32 HalfHeight = m_Dimensions[1]/2;
vPoints[0] = vector3( HalfWidth, HalfHeight,0);
vPoints[1] = vector3( HalfWidth, -HalfHeight,0);
vPoints[2] = vector3( -HalfWidth, -HalfHeight,0);
vPoints[3] = vector3( -HalfWidth, HalfHeight,0);
vPoints[4] = vector3( HalfWidth, HalfHeight,0);
vPoints[5] = vector3( -HalfWidth, -HalfHeight,0);
const matrix4 M = GetL2W();
M.Transform( vPoints, vPoints, NumPoints );
// Renders a wire polygon
SMP_UTIL_draw_Polygon( vPoints, NumPoints, DrawColor, TRUE );
}
break;
case TYPE_CUBIC:
{
vector3 Halves( m_Dimensions[0]/2, m_Dimensions[1]/2, m_Dimensions[2]/2 );
const matrix4 M = GetL2W();
// Renders a wire polygon
SMP_UTIL_draw_Cube ( Halves, M, DrawColor );
// Renders a volume given a BBox
draw_Volume ( GetBBox(), DrawColor);
}
break;
case TYPE_AXIS_CUBE:
{
if( GetAttrBits() & ATTR_EDITOR_SELECTED )
{
// Renders a volume given a BBox
draw_Volume ( GetBBox(), xcolor(DrawColor.R, DrawColor.G,DrawColor.B, 50));
}
draw_BBox( GetBBox(), DrawColor);
}
break;
case TYPE_SPHERICAL:
draw_Sphere( object::GetPosition(), m_Dimensions[0], DrawColor );
break;
default:
ASSERT(0);
break;
}
}
#endif // X_RETAIL
//=============================================================================
void trigger_spatial_object::OnInit ( void )
{
trigger_object::OnInit();
//starts in sleeping state...
SetTriggerState(STATE_SLEEPING);
//set this to its default..
m_ActivationType = ACTIVATE_ON_PLAYER;
}
//=============================================================================
void trigger_spatial_object::OnKill ( void )
{
trigger_object::OnKill();
}
//=============================================================================
void trigger_spatial_object::OnColCheck ( void )
{
switch ( m_SpatialType )
{
case TYPE_RAY:
{
vector3 vEndpoint(0,0,m_Dimensions[0]);
const matrix4 M = GetL2W();
vEndpoint = M*vEndpoint;
g_CollisionMgr.StartApply( GetGuid() );
//collision is facing senestivie so we use tris facing both sides..
g_CollisionMgr.ApplyTriangle (
GetPosition(),
vEndpoint,
vEndpoint );
g_CollisionMgr.ApplyTriangle (
vEndpoint,
vEndpoint,
GetPosition() );
g_CollisionMgr.EndApply();
}
break;
case TYPE_PLANE:
{
const s32 NumPoints = 4;
vector3 vPoints[NumPoints];
f32 HalfWidth = m_Dimensions[0]/2;
f32 HalfHeight = m_Dimensions[1]/2;
vPoints[0] = vector3( HalfWidth, HalfHeight,0);
vPoints[1] = vector3( HalfWidth, -HalfHeight,0);
vPoints[2] = vector3( -HalfWidth, -HalfHeight,0);
vPoints[3] = vector3( -HalfWidth, HalfHeight,0);
const matrix4 M = GetL2W();
M.Transform( vPoints, vPoints, NumPoints );
g_CollisionMgr.StartApply( GetGuid() );
//collision is facing senestivie so we use tris facing both sides..
g_CollisionMgr.ApplyTriangle (
vPoints[0],
vPoints[1],
vPoints[2] );
g_CollisionMgr.ApplyTriangle (
vPoints[0],
vPoints[2],
vPoints[3] );
g_CollisionMgr.ApplyTriangle (
vPoints[2],
vPoints[1],
vPoints[0] );
g_CollisionMgr.ApplyTriangle (
vPoints[3],
vPoints[2],
vPoints[0] );
g_CollisionMgr.EndApply();
}
break;
case TYPE_CUBIC:
{
//TODO
}
break;
case TYPE_AXIS_CUBE:
{
g_CollisionMgr.StartApply( GetGuid() );
g_CollisionMgr.ApplyAABBox( GetBBox() );
g_CollisionMgr.EndApply();
}
break;
case TYPE_SPHERICAL:
{
g_CollisionMgr.StartApply( GetGuid() );
g_CollisionMgr.ApplySphere( GetPosition(),
m_Dimensions[0] );
g_CollisionMgr.EndApply();
}
break;
default:
ASSERT(0);
break;
}
object::OnColCheck();
}
//=============================================================================
void trigger_spatial_object::OnColNotify( object& Object )
{
if (m_OnActivate)
{
switch ( m_ActivationType )
{
case ACTIVATE_ON_PLAYER:
{
if ( Object.IsKindOf( player::GetRTTI() ) == TRUE )
{
ActivateTrigger();
m_TriggerActor = Object.GetGuid();
}
}
break;
case ACTIVATE_ON_NPC:
{
if ( Object.IsKindOf( character::GetRTTI() ) == TRUE )
{
ActivateTrigger();
m_TriggerActor = Object.GetGuid();
}
}
break;
case ACTIVATE_ON_BULLET:
{
if ( Object.IsKindOf( base_projectile::GetRTTI() ) == TRUE )
{
ActivateTrigger();
m_TriggerActor = Object.GetGuid();
}
}
break;
case ACTIVATE_ON_NPC_OR_PLAYER:
{
if ( Object.IsKindOf( character::GetRTTI() ) == TRUE ||
Object.IsKindOf( player::GetRTTI() ) == TRUE )
{
ActivateTrigger();
m_TriggerActor = Object.GetGuid();
}
}
break;
case ACTIVATE_ON_USE_EVENT:
{
if ( Object.IsKindOf( player::GetRTTI() ) == TRUE )
{
StartPlayerPolling();
m_TriggerActor = Object.GetGuid();
}
}
break;
case ACTIVATE_ON_BY_OVERRIDE_TYPE:
{
//no-op
}
break;
default:
ASSERT(0);
break; break;
}
}
object::OnColNotify(Object);
}
//=============================================================================
void trigger_spatial_object::ActivateTrigger ( void )
{
//the m_IsActivated flag is used to prevent multiple activation events to cause the trigger
//to udpate faster than its natural update rate and also prevent multiple triggering of actions.
if (m_IsActivated)
return;
ForceNextUpdate();
//ExecuteAllActions( PRE_ACTIVATE_ACTION_FLAG );
m_CurrentColor = xcolor(255,0,0);
SetTriggerState(STATE_CHECKING);
m_IsActivated = TRUE;
m_EventPollingStarted = FALSE;
m_HasPressed = FALSE;
}
//=============================================================================
void trigger_spatial_object::DeactivateTrigger ( void )
{
if (!m_IsActivated)
return;
SetTriggerState(STATE_SLEEPING);
//ExecuteAllActions( POST_ACTIVATE_ACTION_FLAG );
m_IsActivated = FALSE;
m_EventPollingStarted = FALSE;
m_HasPressed = FALSE;
}
//=============================================================================
void trigger_spatial_object::StartPlayerPolling ( void )
{
//the m_IsActivated flag is used to prevent multiple activation events to cause the trigger
//to udpate faster than its natural update rate and also prevent multiple triggering of actions.
if ( m_IsActivated && m_HasPressed == FALSE )
return;
//ExecuteAllActions( PRE_ACTIVATE_ACTION_FLAG );
ForceNextUpdate();
SetTriggerState(STATE_CHECKING);
m_IsActivated = TRUE;
m_EventPollingStarted = TRUE;
m_HasPressed = FALSE;
}
//=============================================================================
void trigger_spatial_object::ExecuteLogic ( f32 DeltaTime )
{
TRIGGER_CONTEXT("trigger_spatial_object::ExecuteLogic");
//Logic for spatial triggers..
// -Only activated once spatial conditions are meet
// -Only allows for 1 execution loop before it executes its logic
// -If the state isnt checking state after calling parents trigger_object::ExecuteLogic
// it waits for the state to return back to checking before it checks its logic..
// -Its logic can be of type :
// -RESPONSE_IF_STILL_INSIDE : checks volume to see if object is still inside, turns off if not
// -RESPONSE_RETURN_TO_SLEEP : goes back to sleep
// -RESPONSE_PERMANENT_ON : stays on forever after that
// -RESPONSE_PERMANENT_OFF : destroys itself
//m_OnActivate controls whether the object is alive or not..
if (!m_OnActivate)
return;
//Event polling uses it own logic loop overriding the default logic loop...
if (m_EventPollingStarted)
{
if (ExecutePlayerPolling( DeltaTime )==FALSE)
return;
}
trigger_object::ExecuteLogic( DeltaTime );
if (m_IsActivated)
{
if ( GetTriggerState() == STATE_CHECKING )
{
switch(m_ResponseType)
{
case RESPONSE_IF_STILL_INSIDE:
{
//do check to see if the object were intrested in is still inside of our volume
switch ( m_SpatialType )
{
case TYPE_RAY:case TYPE_PLANE: case TYPE_CUBIC://these types dont support this response type
{
DeactivateTrigger();
}
break;
case TYPE_AXIS_CUBE:case TYPE_SPHERICAL:
{
switch ( m_ActivationType )
{
case ACTIVATE_ON_PLAYER:
{
if (QueryPlayerInVolume() == FALSE)
{
DeactivateTrigger();
}
}
break;
case ACTIVATE_ON_NPC:
{
if (QueryNpcInVolume() == FALSE)
{
DeactivateTrigger();
}
}
break;
case ACTIVATE_ON_NPC_OR_PLAYER:
{
if (QueryNpcInVolume() == FALSE && QueryPlayerInVolume() == FALSE)
{
DeactivateTrigger();
}
}
break;
case ACTIVATE_ON_BULLET:
{
if (QueryBulletInVolume() == FALSE)
{
DeactivateTrigger();
}
}
break;
case ACTIVATE_ON_USE_EVENT:
{
//as long as the player is inside the volume we poll, the
//volume check is done within ExecutePlayerPolling, so we just
//return to that state..
if (QueryPlayerInVolume() == FALSE)
{
DeactivateTrigger();
}
else
{
StartPlayerPolling();
}
}
break;
case ACTIVATE_ON_BY_OVERRIDE_TYPE:
{
//no-op
}
break;
default:
ASSERT(0);
break; break;
}
}
break;
default:
ASSERT(0);
break;
}
}
break;
case RESPONSE_RETURN_TO_SLEEP:
//goes back to sleep after activating..
DeactivateTrigger();
break;
case RESPONSE_PERMANENT_ON:
if (m_ActivationType == ACTIVATE_ON_USE_EVENT)
{
StartPlayerPolling();
}
break;
case RESPONSE_PERMANENT_OFF:
KillTrigger();
break;
default:
ASSERT(0);
break;
}
}
}
}
//=============================================================================
xbool trigger_spatial_object::ExecutePlayerPolling ( f32 DeltaTime )
{
//Player event polling uses it own logic loop overriding the default logic loop of ExecuteLogic
//There are 3 ways we can leave the event polling state.
// -player leaves the volume
// -player uses the use key..
// -we are using an invalid spatial type..
//if the player has pressed the button no need to poll as our activation condition has been meet..
if ( m_HasPressed )
return TRUE;
//update at our natural update rate...
if ( CanUpdate(DeltaTime) == FALSE )
return FALSE;
switch ( m_SpatialType )
{
case TYPE_RAY:case TYPE_PLANE: case TYPE_CUBIC://these types dont support this state
{
DeactivateTrigger();
}
break;
case TYPE_AXIS_CUBE:case TYPE_SPHERICAL:
{
if (QueryPlayerInVolume() == FALSE)
{
DeactivateTrigger();
}
else
{
//watch for use event here, if there is one activate the trigger
if (CheckForUseEvent())
{
m_HasPressed = TRUE;
ForceNextUpdate();
return TRUE;
}
}
}
break;
default:
break;
}
return FALSE;
}
//=============================================================================
//This function checks the logic of spatial triggers activated by on voulme, once it
//awakes during an OnActivate call..
void trigger_spatial_object::LogicCheckOnActivate ( void )
{
TRIGGER_CONTEXT("trigger_spatial_object::ForceLogicCheckOnActivate");
if (!m_OnActivate)
return;
switch(m_ResponseType)
{
case RESPONSE_IF_STILL_INSIDE: case RESPONSE_RETURN_TO_SLEEP: case RESPONSE_PERMANENT_ON:case RESPONSE_PERMANENT_OFF:
{
//do check to see if the object were intrested in is still inside of our volume
switch ( m_SpatialType )
{
case TYPE_RAY:case TYPE_PLANE: case TYPE_CUBIC://these types dont support this response type
//no-op
break;
case TYPE_AXIS_CUBE:case TYPE_SPHERICAL:
{
switch ( m_ActivationType )
{
case ACTIVATE_ON_PLAYER:
{
if (QueryPlayerInVolume() == TRUE)
{
ActivateTrigger();
}
}
break;
case ACTIVATE_ON_NPC:
{
if (QueryNpcInVolume() == TRUE)
{
ActivateTrigger();
}
}
break;
case ACTIVATE_ON_NPC_OR_PLAYER:
{
if (QueryNpcInVolume() == TRUE || QueryPlayerInVolume() == TRUE)
{
ActivateTrigger();
}
}
break;
case ACTIVATE_ON_BULLET:
{
if (QueryBulletInVolume() == TRUE)
{
ActivateTrigger();
}
}
break;
case ACTIVATE_ON_USE_EVENT:
{
if (QueryPlayerInVolume() == TRUE)
{
StartPlayerPolling();
}
}
break;
case ACTIVATE_ON_BY_OVERRIDE_TYPE:
{
//no-op
}
break;;
default:
ASSERT(0);
break; break;
}
}
break;
default:
ASSERT(0);
break;
}
}
break;
default:
ASSERT(0);
break;
}
}
//=============================================================================
void trigger_spatial_object::OnEnumProp ( prop_enum& rPropList )
{
trigger_object::OnEnumProp( rPropList );
rPropList.AddHeader ( "Spatial Trigger", "Select the type of condition to add.", PROP_TYPE_HEADER);
rPropList.AddEnum ( "Spatial Trigger\\Type",
s_SpatialEnumTable.BuildString(),
"Types of spatial triggers.", PROP_TYPE_MUST_ENUM );
rPropList.AddEnum ( "Spatial Trigger\\Activation Triggers",
s_ActivationEnumTable.BuildString(),
"Things which will activate this spatial trigger.", PROP_TYPE_MUST_ENUM );
rPropList.AddEnum ( "Spatial Trigger\\Response Type",
s_ResponseEnumTable.BuildString(),
"Things which will activate this spatial trigger.", PROP_TYPE_MUST_ENUM );
switch ( m_SpatialType )
{
case TYPE_RAY:
rPropList.AddFloat ( "Spatial Trigger\\Ray Length", "The length of the ray." );
break;
case TYPE_PLANE:
rPropList.AddFloat ( "Spatial Trigger\\Plane Width", "The width of the plane." );
rPropList.AddFloat ( "Spatial Trigger\\Plane Height", "The height of the plane." );
break;
case TYPE_CUBIC:
rPropList.AddFloat ( "Spatial Trigger\\Cube Width", "The width of the cube." );
rPropList.AddFloat ( "Spatial Trigger\\Cube Height", "The height of the cube." );
rPropList.AddFloat ( "Spatial Trigger\\Cube Length", "The length of the cube." );
break;
case TYPE_AXIS_CUBE:
rPropList.AddFloat ( "Spatial Trigger\\Cube Width", "The width of the cube." );
rPropList.AddFloat ( "Spatial Trigger\\Cube Height", "The height of the cube." );
rPropList.AddFloat ( "Spatial Trigger\\Cube Length", "The length of the cube." );
break;
case TYPE_SPHERICAL:
rPropList.AddFloat ( "Spatial Trigger\\Sphere Radius", "The radius of the sphere." );
break;
default:
ASSERT(0);
break;
}
}
//=============================================================================
xbool trigger_spatial_object::OnProperty ( prop_query& rPropQuery )
{
SetAttrBits( GetAttrBits() | FLAGS_DIRTY_TRANSLATION );
if( trigger_object::OnProperty( rPropQuery ) )
return TRUE;
if ( SMP_UTIL_IsEnumVar<spatial_types,spatial_types>(rPropQuery, "Spatial Trigger\\Type",
m_SpatialType, s_SpatialEnumTable ) )
return TRUE;
if ( SMP_UTIL_IsEnumVar<activation_types,activation_types>(rPropQuery, "Spatial Trigger\\Activation Triggers",
m_ActivationType, s_ActivationEnumTable ) )
return TRUE;
if ( SMP_UTIL_IsEnumVar<activation_response_type,activation_response_type>(rPropQuery, "Spatial Trigger\\Response Type",
m_ResponseType, s_ResponseEnumTable ) )
return TRUE;
if ( rPropQuery.VarFloat ( "Spatial Trigger\\Ray Length", m_Dimensions[0] ) )
return TRUE;
if ( rPropQuery.VarFloat ( "Spatial Trigger\\Plane Width", m_Dimensions[0] ) )
return TRUE;
if ( rPropQuery.VarFloat ( "Spatial Trigger\\Plane Height", m_Dimensions[1] ) )
return TRUE;
if ( rPropQuery.VarFloat ( "Spatial Trigger\\Cube Width", m_Dimensions[0] ) )
return TRUE;
if ( rPropQuery.VarFloat ( "Spatial Trigger\\Cube Height", m_Dimensions[1] ) )
return TRUE;
if ( rPropQuery.VarFloat ( "Spatial Trigger\\Cube Length", m_Dimensions[2] ) )
return TRUE;
if ( rPropQuery.VarFloat ( "Spatial Trigger\\Sphere Radius", m_Dimensions[0] ) )
return TRUE;
return FALSE;
}
//=============================================================================
// ALL THE QUERY VOULME CALLS CURRENTLY USE SIMPLE BOUNDING VOULME CHECKS ....
xbool trigger_spatial_object::QueryPlayerInVolume ( void )
{
//Query for the player...
slot_id SlotID = g_ObjMgr.GetFirst( object::TYPE_PLAYER );
xbool bVal = FALSE;
while( SlotID != SLOT_NULL )
{
object* pObject = g_ObjMgr.GetObjectBySlot( SlotID );
if( pObject != NULL )
bVal |= QueryObjectInVolume(pObject);
SlotID = g_ObjMgr.GetNext( SlotID );
}
return bVal;
}
//=============================================================================
xbool trigger_spatial_object::QueryNpcInVolume ( void )
{
slot_id SlotID = g_ObjMgr.GetFirst( object::TYPE_HAZMAT );
xbool bVal = FALSE;
while( SlotID != SLOT_NULL )
{
object* pObject = g_ObjMgr.GetObjectBySlot( SlotID );
if( pObject != NULL )
bVal |= QueryObjectInVolume(pObject);
SlotID = g_ObjMgr.GetNext( SlotID );
}
SlotID = g_ObjMgr.GetFirst( object::TYPE_GRUNT );
while( SlotID != SLOT_NULL )
{
object* pObject = g_ObjMgr.GetObjectBySlot( SlotID );
if( pObject != NULL )
bVal |= QueryObjectInVolume(pObject);
SlotID = g_ObjMgr.GetNext( SlotID );
}
SlotID = g_ObjMgr.GetFirst( object::TYPE_FRIENDLY_SCIENTIST );
while( SlotID != SLOT_NULL )
{
object* pObject = g_ObjMgr.GetObjectBySlot( SlotID );
if( pObject != NULL )
bVal |= QueryObjectInVolume(pObject);
SlotID = g_ObjMgr.GetNext( SlotID );
}
return bVal;
}
//=============================================================================
xbool trigger_spatial_object::QueryBulletInVolume ( void )
{
//Query for bullets in the volume...
slot_id SlotID = g_ObjMgr.GetFirst( object::TYPE_BULLET_PROJECTILE );
xbool bVal = FALSE;
while( SlotID != SLOT_NULL )
{
object* pObject = g_ObjMgr.GetObjectBySlot( SlotID );
if( pObject != NULL )
bVal |= QueryObjectInVolume(pObject);
SlotID = g_ObjMgr.GetNext( SlotID );
}
return bVal;
}
//=============================================================================
xbool trigger_spatial_object::QueryObjectInVolume( object* pObject )
{
switch ( m_SpatialType )
{
case TYPE_RAY: case TYPE_PLANE:
return FALSE; //These types don't support voulme queries..
break;
case TYPE_CUBIC:
return FALSE; //TODO
break;
case TYPE_AXIS_CUBE:
{
bbox PlayerBox = pObject->GetBBox();
bbox ObjectBox = GetBBox();
if (ObjectBox.Intersect(PlayerBox))
return TRUE;
else
return FALSE;
}
break;
case TYPE_SPHERICAL:
{
bbox PlayerBox = pObject->GetBBox();
if (PlayerBox.Intersect(GetPosition(), m_Dimensions[0]))
return TRUE;
else
return FALSE;
}
break;
default:
ASSERT(0);
break;
}
return FALSE;
}
//=============================================================================
xbool trigger_spatial_object::CheckForUseEvent( void )
{
//This functions watches the player inputs and waits for a use event...
object* pObj = g_ObjMgr.GetObjectByGuid( m_TriggerActor );
if( pObj->GetType() == object::TYPE_PLAYER )
{
player& Player = player::GetSafeType( *pObj );
if( g_IngamePad[ Player.GetActivePlayerPad() ].GetLogical( ingame_pad::ACTION_USE ).WasValue )
{
return TRUE;
}
}
return FALSE;
}
//=============================================================================
void trigger_spatial_object::OnActivate( xbool Flag )
{
trigger_object::OnActivate( Flag );
//work around for volume spatial checks, becuase its failing for entites already inside
//the volume when the trigger is activated
if ( Flag == TRUE )
LogicCheckOnActivate();
}
//=============================================================================
void trigger_spatial_object::Setup(
activation_types ActivateType,
spatial_types SpatialType,
activation_response_type ResponseType,
const f32* Dimensions )
{
m_ActivationType = ActivateType;
m_SpatialType = SpatialType;
m_ResponseType = ResponseType;
Setup( Dimensions );
}
//=============================================================================
void trigger_spatial_object::Setup( const f32* Dimensions )
{
m_Dimensions[0] = Dimensions[0];
m_Dimensions[1] = Dimensions[1];
m_Dimensions[2] = Dimensions[2];
}