783 lines
21 KiB
C++
783 lines
21 KiB
C++
|
/*
|
||
|
** Command & Conquer Renegade(tm)
|
||
|
** Copyright 2025 Electronic Arts Inc.
|
||
|
**
|
||
|
** This program is free software: you can redistribute it and/or modify
|
||
|
** it under the terms of the GNU General Public License as published by
|
||
|
** the Free Software Foundation, either version 3 of the License, or
|
||
|
** (at your option) any later version.
|
||
|
**
|
||
|
** This program is distributed in the hope that it will be useful,
|
||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
** GNU General Public License for more details.
|
||
|
**
|
||
|
** You should have received a copy of the GNU General Public License
|
||
|
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
/***********************************************************************************************
|
||
|
*** Confidential - Westwood Studios ***
|
||
|
***********************************************************************************************
|
||
|
* *
|
||
|
* Project Name : Commando *
|
||
|
* *
|
||
|
* $Archive:: /Commando/Code/Combat/doors.cpp $*
|
||
|
* *
|
||
|
* $Author:: Steve_t $*
|
||
|
* *
|
||
|
* $Modtime:: 1/15/02 3:07p $*
|
||
|
* *
|
||
|
* $Revision:: 47 $*
|
||
|
* *
|
||
|
*---------------------------------------------------------------------------------------------*
|
||
|
* Functions: *
|
||
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||
|
|
||
|
#include "doors.h"
|
||
|
#include "simpledefinitionfactory.h"
|
||
|
#include "persistfactory.h"
|
||
|
#include "wwphysids.h"
|
||
|
#include "debug.h"
|
||
|
#include "hanim.h"
|
||
|
#include "wwhack.h"
|
||
|
#include "combat.h"
|
||
|
#include "smartgameobj.h"
|
||
|
#include "gameobjmanager.h"
|
||
|
#include "soldier.h"
|
||
|
#include "wwaudio.h"
|
||
|
#include "wwprofile.h"
|
||
|
#include "bitpackids.h"
|
||
|
#include "diaglog.h"
|
||
|
#include "vehicle.h"
|
||
|
|
||
|
|
||
|
DECLARE_FORCE_LINK( doorphys );
|
||
|
|
||
|
/*
|
||
|
** DoorPhysDefClass
|
||
|
*/
|
||
|
SimplePersistFactoryClass<DoorPhysDefClass, PHYSICS_CHUNKID_DOORPHYSDEF> _DoorPhysDefPersistFactory;
|
||
|
|
||
|
DECLARE_DEFINITION_FACTORY(DoorPhysDefClass, CLASSID_DOORPHYSDEF, "DoorPhys") _DoorPhysDefDefFactory;
|
||
|
|
||
|
DoorPhysDefClass::DoorPhysDefClass( void ) :
|
||
|
AccessiblePhysDefClass(),
|
||
|
CloseDelay( 2 ),
|
||
|
TriggerZone1( Vector3( 0,0,0), Vector3( 1,1,1 ) ),
|
||
|
TriggerZone2( Vector3( 0,0,0), Vector3( 1,1,1 ) ),
|
||
|
OpenSoundDefID( 0 ),
|
||
|
CloseSoundDefID( 0 ),
|
||
|
UnlockSoundDefID( 0 ),
|
||
|
AccessDeniedSoundDefID( 0 ),
|
||
|
DoorOpensForVehicles( false )
|
||
|
{
|
||
|
ZONE_PARAM(DoorPhysDefClass, TriggerZone1, "TriggerZone1" );
|
||
|
ZONE_PARAM(DoorPhysDefClass, TriggerZone2, "TriggerZone2" );
|
||
|
EDITABLE_PARAM(DoorPhysDefClass, ParameterClass::TYPE_FLOAT, CloseDelay );
|
||
|
EDITABLE_PARAM(DoorPhysDefClass, ParameterClass::TYPE_SOUNDDEFINITIONID, OpenSoundDefID);
|
||
|
EDITABLE_PARAM(DoorPhysDefClass, ParameterClass::TYPE_SOUNDDEFINITIONID, CloseSoundDefID);
|
||
|
EDITABLE_PARAM(DoorPhysDefClass, ParameterClass::TYPE_SOUNDDEFINITIONID, UnlockSoundDefID);
|
||
|
EDITABLE_PARAM(DoorPhysDefClass, ParameterClass::TYPE_SOUNDDEFINITIONID, AccessDeniedSoundDefID);
|
||
|
EDITABLE_PARAM(DoorPhysDefClass, ParameterClass::TYPE_BOOL, DoorOpensForVehicles);
|
||
|
}
|
||
|
|
||
|
uint32 DoorPhysDefClass::Get_Class_ID (void) const
|
||
|
{
|
||
|
return CLASSID_DOORPHYSDEF;
|
||
|
}
|
||
|
|
||
|
bool DoorPhysDefClass::Is_Type(const char * type_name)
|
||
|
{
|
||
|
if (stricmp(type_name,DoorPhysDefClass::Get_Type_Name()) == 0) {
|
||
|
return true;
|
||
|
} else {
|
||
|
return AccessiblePhysDefClass::Is_Type(type_name);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PersistClass * DoorPhysDefClass::Create( void ) const
|
||
|
{
|
||
|
DoorPhysClass * door = new DoorPhysClass;
|
||
|
door->Init( *this );
|
||
|
return door;
|
||
|
}
|
||
|
|
||
|
enum {
|
||
|
CHUNKID_DEF_OLD_PARENT = 320001902,
|
||
|
CHUNKID_DEF_VARIABLES,
|
||
|
CHUNKID_DEF_PARENT,
|
||
|
|
||
|
XXXMICROCHUNKID_DEF_TRIGGER_RADIUS = 1,
|
||
|
MICROCHUNKID_DEF_CLOSE_DELAY,
|
||
|
MICROCHUNKID_DEF_TRIGGER_ZONE1,
|
||
|
MICROCHUNKID_DEF_OLD_LOCK_CODE,
|
||
|
MICROCHUNKID_DEF_OPEN_SOUND_DEF_ID,
|
||
|
MICROCHUNKID_DEF_CLOSE_SOUND_DEF_ID,
|
||
|
MICROCHUNKID_DEF_UNLOCK_SOUND_DEF_ID,
|
||
|
MICROCHUNKID_DEF_ACCESS_DENIED_SOUND_DEF_ID,
|
||
|
MICROCHUNKID_DEF_TRIGGER_ZONE2,
|
||
|
MICROCHUNKID_DEF_DOOR_OPENS_FOR_VEHICLES,
|
||
|
};
|
||
|
|
||
|
bool DoorPhysDefClass::Save( ChunkSaveClass & csave )
|
||
|
{
|
||
|
csave.Begin_Chunk( CHUNKID_DEF_PARENT );
|
||
|
AccessiblePhysDefClass::Save( csave );
|
||
|
csave.End_Chunk();
|
||
|
|
||
|
csave.Begin_Chunk( CHUNKID_DEF_VARIABLES );
|
||
|
// WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_TRIGGER_RADIUS, TriggerRadius );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_CLOSE_DELAY, CloseDelay );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_TRIGGER_ZONE1, TriggerZone1 );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_TRIGGER_ZONE2, TriggerZone2 );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_OPEN_SOUND_DEF_ID, OpenSoundDefID );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_CLOSE_SOUND_DEF_ID, CloseSoundDefID );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_UNLOCK_SOUND_DEF_ID, UnlockSoundDefID );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_ACCESS_DENIED_SOUND_DEF_ID, AccessDeniedSoundDefID );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_DOOR_OPENS_FOR_VEHICLES, DoorOpensForVehicles );
|
||
|
csave.End_Chunk();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool DoorPhysDefClass::Load( ChunkLoadClass &cload )
|
||
|
{
|
||
|
while (cload.Open_Chunk()) {
|
||
|
switch(cload.Cur_Chunk_ID()) {
|
||
|
|
||
|
case CHUNKID_DEF_OLD_PARENT:
|
||
|
StaticAnimPhysDefClass::Load( cload );
|
||
|
break;
|
||
|
|
||
|
case CHUNKID_DEF_PARENT:
|
||
|
AccessiblePhysDefClass::Load( cload );
|
||
|
break;
|
||
|
|
||
|
case CHUNKID_DEF_VARIABLES:
|
||
|
while (cload.Open_Micro_Chunk()) {
|
||
|
switch(cload.Cur_Micro_Chunk_ID()) {
|
||
|
// READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_TRIGGER_RADIUS, TriggerRadius );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_CLOSE_DELAY, CloseDelay );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_TRIGGER_ZONE1, TriggerZone1 );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_TRIGGER_ZONE2, TriggerZone2 );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_OLD_LOCK_CODE, LockCode );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_OPEN_SOUND_DEF_ID, OpenSoundDefID );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_CLOSE_SOUND_DEF_ID, CloseSoundDefID );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_UNLOCK_SOUND_DEF_ID, UnlockSoundDefID );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_ACCESS_DENIED_SOUND_DEF_ID, AccessDeniedSoundDefID );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_DOOR_OPENS_FOR_VEHICLES, DoorOpensForVehicles );
|
||
|
|
||
|
default:
|
||
|
Debug_Say(( "Unrecognized DoorPhys Variable chunkID\n" ));
|
||
|
break;
|
||
|
}
|
||
|
cload.Close_Micro_Chunk();
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
Debug_Say(( "Unrecognized DoorPhys chunkID\n" ));
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
cload.Close_Chunk();
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
const PersistFactoryClass & DoorPhysDefClass::Get_Factory (void) const
|
||
|
{
|
||
|
return _DoorPhysDefPersistFactory;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
**
|
||
|
*/
|
||
|
SimplePersistFactoryClass<DoorPhysClass, PHYSICS_CHUNKID_DOORPHYS> _DoorPhysPersistFactory;
|
||
|
|
||
|
const PersistFactoryClass & DoorPhysClass::Get_Factory (void) const
|
||
|
{
|
||
|
return _DoorPhysPersistFactory;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
**
|
||
|
*/
|
||
|
DoorPhysClass::DoorPhysClass( void ) :
|
||
|
Timer( 0 ),
|
||
|
CheckTimer( 0 ),
|
||
|
State( STATE_CLOSED_DOOR ),
|
||
|
LockState( false ),
|
||
|
OpenRequestPending( false )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
DoorPhysClass::~DoorPhysClass( void )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void DoorPhysClass::Init( const DoorPhysDefClass & def )
|
||
|
{
|
||
|
AccessiblePhysClass::Init(def);
|
||
|
AnimManager.Set_Animation_Mode( AnimCollisionManagerClass::ANIMATE_TARGET );
|
||
|
AnimManager.Set_Target_Frame( 0 );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Save and Load
|
||
|
*/
|
||
|
enum {
|
||
|
CHUNKID_OLD_PARENT = 320002202,
|
||
|
CHUNKID_VARIABLES,
|
||
|
CHUNKID_PARENT,
|
||
|
|
||
|
XXXMICROCHUNKID_ = 1,
|
||
|
MICROCHUNKID_STATE = 2,
|
||
|
MICROCHUNKID_TIMER = 3,
|
||
|
MICROCHUNKID_CHECK_TIMER = 4,
|
||
|
MICROCHUNKID_OPEN_REQUEST_PENDING = 5,
|
||
|
};
|
||
|
|
||
|
bool DoorPhysClass::Save( ChunkSaveClass & csave )
|
||
|
{
|
||
|
csave.Begin_Chunk( CHUNKID_PARENT );
|
||
|
AccessiblePhysClass::Save( csave );
|
||
|
csave.End_Chunk();
|
||
|
|
||
|
csave.Begin_Chunk( CHUNKID_VARIABLES );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STATE, State );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_TIMER, Timer );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_CHECK_TIMER, CheckTimer );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_OPEN_REQUEST_PENDING, OpenRequestPending );
|
||
|
csave.End_Chunk();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool DoorPhysClass::Load( ChunkLoadClass &cload )
|
||
|
{
|
||
|
while (cload.Open_Chunk()) {
|
||
|
switch(cload.Cur_Chunk_ID()) {
|
||
|
|
||
|
case CHUNKID_OLD_PARENT:
|
||
|
StaticAnimPhysClass::Load( cload );
|
||
|
break;
|
||
|
|
||
|
case CHUNKID_PARENT:
|
||
|
AccessiblePhysClass::Load( cload );
|
||
|
break;
|
||
|
|
||
|
case CHUNKID_VARIABLES:
|
||
|
while (cload.Open_Micro_Chunk()) {
|
||
|
switch(cload.Cur_Micro_Chunk_ID()) {
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_STATE, State );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_TIMER, Timer );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_CHECK_TIMER, CheckTimer );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_OPEN_REQUEST_PENDING, OpenRequestPending );
|
||
|
default:
|
||
|
Debug_Say(( "Unrecognized DoorPhys Variable chunkID\n" ));
|
||
|
break;
|
||
|
}
|
||
|
cload.Close_Micro_Chunk();
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
Debug_Say(( "Unrecognized DoorPhys chunkID\n" ));
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
cload.Close_Chunk();
|
||
|
}
|
||
|
|
||
|
AnimManager.Set_Animation_Mode( AnimCollisionManagerClass::ANIMATE_TARGET );
|
||
|
AnimManager.Set_Target_Frame( 0 );
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void DoorPhysClass::Save_State( ChunkSaveClass & csave )
|
||
|
{
|
||
|
csave.Begin_Chunk( CHUNKID_PARENT );
|
||
|
AccessiblePhysClass::Save_State( csave );
|
||
|
csave.End_Chunk();
|
||
|
|
||
|
csave.Begin_Chunk( CHUNKID_VARIABLES );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STATE, State );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_TIMER, Timer );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_CHECK_TIMER, CheckTimer );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_OPEN_REQUEST_PENDING, OpenRequestPending );
|
||
|
csave.End_Chunk();
|
||
|
}
|
||
|
|
||
|
#define LEGACY_STATICANIMPHYS_CHUNK_ANIMMANAGER 0x01170012
|
||
|
|
||
|
void DoorPhysClass::Load_State( ChunkLoadClass &cload )
|
||
|
{
|
||
|
while (cload.Open_Chunk()) {
|
||
|
switch(cload.Cur_Chunk_ID()) {
|
||
|
|
||
|
case CHUNKID_OLD_PARENT:
|
||
|
StaticAnimPhysClass::Load_State( cload );
|
||
|
break;
|
||
|
|
||
|
case CHUNKID_PARENT:
|
||
|
AccessiblePhysClass::Load_State( cload );
|
||
|
break;
|
||
|
|
||
|
case CHUNKID_VARIABLES:
|
||
|
while (cload.Open_Micro_Chunk()) {
|
||
|
switch(cload.Cur_Micro_Chunk_ID()) {
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_STATE, State );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_TIMER, Timer );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_CHECK_TIMER, CheckTimer );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_OPEN_REQUEST_PENDING, OpenRequestPending );
|
||
|
default:
|
||
|
Debug_Say(( "Unrecognized DoorPhys Variable chunkID\n" ));
|
||
|
break;
|
||
|
}
|
||
|
cload.Close_Micro_Chunk();
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case LEGACY_STATICANIMPHYS_CHUNK_ANIMMANAGER:
|
||
|
AnimManager.Load(cload);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
Debug_Say(( "Unrecognized DoorPhys chunkID\n" ));
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
cload.Close_Chunk();
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void DoorPhysClass::Timestep( float dt )
|
||
|
{
|
||
|
AccessiblePhysClass::Timestep( dt );
|
||
|
|
||
|
{
|
||
|
WWPROFILE("DoorPhys::Timestep");
|
||
|
|
||
|
//
|
||
|
// If we are configured correctly with an animation,
|
||
|
// then evaluate our state and determine if we need to
|
||
|
// do anything.
|
||
|
//
|
||
|
if ( AnimManager.Peek_Animation() != NULL ) {
|
||
|
Update_State( dt );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Reset the open request flag
|
||
|
//
|
||
|
OpenRequestPending = false;
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
bool DoorPhysClass::Set_State( int new_state )
|
||
|
{
|
||
|
bool retval = false;
|
||
|
|
||
|
if ( State != new_state ) {
|
||
|
|
||
|
switch ( new_state )
|
||
|
{
|
||
|
case STATE_OPENING_DOOR:
|
||
|
{
|
||
|
//
|
||
|
// Did someone just unlock the door?
|
||
|
//
|
||
|
if ( Get_DoorPhysDef()->LockCode != 0 ) {
|
||
|
WWAudioClass::Get_Instance()->Create_Instant_Sound( Get_DoorPhysDef()->UnlockSoundDefID, Get_Transform() );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Play the 'door-opening' sound
|
||
|
//
|
||
|
WWAudioClass::Get_Instance()->Create_Instant_Sound( Get_DoorPhysDef()->OpenSoundDefID, Get_Transform() );
|
||
|
|
||
|
//
|
||
|
// Open the door
|
||
|
//
|
||
|
AnimManager.Set_Animation_Mode( AnimCollisionManagerClass::ANIMATE_TARGET );
|
||
|
AnimManager.Set_Target_Frame( AnimManager.Peek_Animation()->Get_Num_Frames() - 1 );
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case STATE_CLOSING_DOOR:
|
||
|
{
|
||
|
//
|
||
|
// Play the 'door-closing' sound
|
||
|
//
|
||
|
WWAudioClass::Get_Instance()->Create_Instant_Sound( Get_DoorPhysDef()->CloseSoundDefID, Get_Transform() );
|
||
|
|
||
|
//
|
||
|
// Close the door
|
||
|
//
|
||
|
AnimManager.Set_Animation_Mode( AnimCollisionManagerClass::ANIMATE_TARGET );
|
||
|
AnimManager.Set_Target_Frame( 0 );
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case STATE_OPENED_DOOR:
|
||
|
{
|
||
|
//
|
||
|
// Set a timer that we can use to close the door
|
||
|
//
|
||
|
Timer = Get_DoorPhysDef()->CloseDelay;
|
||
|
|
||
|
//
|
||
|
// Make sure the door is open (net games, may not see the "opening" state)
|
||
|
//
|
||
|
// Clients *must* see the opening - it's a guaranteed packet. ST - 1/15/2002 12:59PM
|
||
|
//
|
||
|
AnimManager.Set_Animation_Mode( AnimCollisionManagerClass::ANIMATE_TARGET );
|
||
|
AnimManager.Set_Target_Frame( AnimManager.Peek_Animation()->Get_Num_Frames() - 1 );
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case STATE_CLOSED_DOOR:
|
||
|
|
||
|
//
|
||
|
// Make sure the door is closed (in net games, we may not get
|
||
|
// the "closing" state)
|
||
|
//
|
||
|
AnimManager.Set_Animation_Mode( AnimCollisionManagerClass::ANIMATE_TARGET );
|
||
|
AnimManager.Set_Target_Frame( 0 );
|
||
|
|
||
|
break;
|
||
|
|
||
|
case STATE_ACCESS_DENIED:
|
||
|
{
|
||
|
//
|
||
|
// Play the 'access denied' sound
|
||
|
//
|
||
|
WWAudioClass::Get_Instance()->Create_Instant_Sound( Get_DoorPhysDef()->AccessDeniedSoundDefID, Get_Transform() );
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
State = new_state;
|
||
|
retval = true;
|
||
|
}
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
|
||
|
enum
|
||
|
{
|
||
|
DOOR_OPEN_OK = 0,
|
||
|
DOOR_OPEN_LOCKED,
|
||
|
DOOR_OPEN_NOONE
|
||
|
};
|
||
|
|
||
|
|
||
|
void DoorPhysClass::Update_State( float dt )
|
||
|
{
|
||
|
switch ( State )
|
||
|
{
|
||
|
case STATE_OPENING_DOOR:
|
||
|
{
|
||
|
//
|
||
|
// Has the door finished opening?
|
||
|
//
|
||
|
if (AnimManager.Get_Current_Frame() == AnimManager.Peek_Animation()->Get_Num_Frames() - 1) {
|
||
|
Set_State( STATE_OPENED_DOOR );
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case STATE_OPENED_DOOR:
|
||
|
{
|
||
|
//
|
||
|
// Has the door been in 'opened' state long enough?
|
||
|
//
|
||
|
// Client shouldn't be able to close his own door unless he hears from the server. ST - 1/15/2002 12:58PM
|
||
|
//
|
||
|
if ( CombatManager::I_Am_Server() ) {
|
||
|
Timer -= dt;
|
||
|
if ( Timer < 0 &&
|
||
|
LockState == false &&
|
||
|
OpenRequestPending == false &&
|
||
|
Can_Open_Door() != DOOR_OPEN_OK)
|
||
|
{
|
||
|
//
|
||
|
// Switch to closing state
|
||
|
//
|
||
|
Set_State( STATE_CLOSING_DOOR );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case STATE_CLOSING_DOOR:
|
||
|
{
|
||
|
//
|
||
|
// Has the door finished closing?
|
||
|
//
|
||
|
if ( AnimManager.Get_Current_Frame() == 0 ) {
|
||
|
Set_State( STATE_CLOSED_DOOR );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
case STATE_CLOSED_DOOR:
|
||
|
case STATE_ACCESS_DENIED:
|
||
|
{
|
||
|
//
|
||
|
// We only do this if we are the server
|
||
|
//
|
||
|
if ( CombatManager::I_Am_Server() ) {
|
||
|
|
||
|
//
|
||
|
// Should we check to see if someone wants to open the door?
|
||
|
//
|
||
|
CheckTimer -= dt;
|
||
|
if ( CheckTimer <= 0 ) {
|
||
|
CheckTimer = 0.3f; // Check every 1/3 second
|
||
|
|
||
|
//
|
||
|
// Check to see if we should open the door
|
||
|
//
|
||
|
if ( LockState == false ) {
|
||
|
bool update_clients = false;
|
||
|
int result = Can_Open_Door();
|
||
|
if ( OpenRequestPending || result == DOOR_OPEN_OK ) {
|
||
|
update_clients = Set_State( STATE_OPENING_DOOR );
|
||
|
} else if ( result == DOOR_OPEN_LOCKED ) {
|
||
|
update_clients = Set_State( STATE_ACCESS_DENIED );
|
||
|
} else if ( State == STATE_ACCESS_DENIED ) {
|
||
|
update_clients = Set_State( STATE_CLOSED_DOOR );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If the server has decided on a new state, then
|
||
|
// notify the clients
|
||
|
//
|
||
|
if ( update_clients ) {
|
||
|
Enable_Is_State_Dirty( true );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
void DoorPhysClass::Lock_Door_Open( bool onoff )
|
||
|
{
|
||
|
if ( CombatManager::I_Am_Server() ) {
|
||
|
|
||
|
//
|
||
|
// Force the door open...
|
||
|
//
|
||
|
if ( onoff && Set_State( STATE_OPENING_DOOR ) ) {
|
||
|
Enable_Is_State_Dirty( true );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Lock the state
|
||
|
//
|
||
|
LockState = onoff;
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
int DoorPhysClass::Can_Open_Door( void )
|
||
|
{
|
||
|
//
|
||
|
// Transform both trigger zones into world space
|
||
|
//
|
||
|
OBBoxClass trigger_zone1;
|
||
|
OBBoxClass trigger_zone2;
|
||
|
OBBoxClass::Transform( Get_Transform(), Get_DoorPhysDef()->TriggerZone1, &trigger_zone1 );
|
||
|
OBBoxClass::Transform( Get_Transform(), Get_DoorPhysDef()->TriggerZone2, &trigger_zone2 );
|
||
|
|
||
|
//
|
||
|
// Check the zone's to see if we should open the door
|
||
|
//
|
||
|
int result1 = Check_Door_Trigger( trigger_zone1 );
|
||
|
int result2 = DOOR_OPEN_NOONE;
|
||
|
if (result1 != DOOR_OPEN_OK) {
|
||
|
result2 = Check_Door_Trigger( trigger_zone2 );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now determine what information to return about the trigger check
|
||
|
//
|
||
|
int result = DOOR_OPEN_NOONE;
|
||
|
if ( result1 == DOOR_OPEN_OK || result2 == DOOR_OPEN_OK ) {
|
||
|
result = DOOR_OPEN_OK;
|
||
|
} else if ( result1 == DOOR_OPEN_LOCKED || result2 == DOOR_OPEN_LOCKED ) {
|
||
|
result = DOOR_OPEN_LOCKED;
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
int DoorPhysClass::Check_Door_Trigger( const OBBoxClass &trigger_zone )
|
||
|
{
|
||
|
int result = DOOR_OPEN_NOONE;
|
||
|
|
||
|
|
||
|
#if 0
|
||
|
//
|
||
|
// Get the list of all the players in the world
|
||
|
//
|
||
|
SList<SoldierGameObj> *player_list = GameObjManager::Get_Star_Game_Obj_List();
|
||
|
|
||
|
//
|
||
|
// Loop over each player
|
||
|
//
|
||
|
SLNode<SoldierGameObj> *objnode;
|
||
|
for ( objnode = player_list->Head(); objnode; objnode = objnode->Next()) {
|
||
|
SoldierGameObj *soldier = objnode->Data();
|
||
|
if ( soldier != NULL ) {
|
||
|
|
||
|
//
|
||
|
// Is this player inside the trigger zone?
|
||
|
//
|
||
|
Vector3 pos;
|
||
|
soldier->Get_Position( &pos );
|
||
|
if ( CollisionMath::Overlap_Test( trigger_zone, pos ) == CollisionMath::INSIDE ) {
|
||
|
|
||
|
//
|
||
|
// Is the door locked?
|
||
|
//
|
||
|
if ( Get_DoorPhysDef()->LockCode != 0 ) {
|
||
|
|
||
|
if ( soldier == COMBAT_STAR ) {
|
||
|
Vector3 pos;
|
||
|
soldier->Get_Position( &pos );
|
||
|
const char * desc = soldier->Has_Key( Get_DoorPhysDef()->LockCode ) ? "KEUS" : "KEDE";
|
||
|
DIAG_LOG(( desc, "%1.2f; %1.2f; %1.2f; %d; %d", pos.X, pos.Y, pos.Z, Get_ID(), Get_DoorPhysDef()->LockCode ));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Can the soldier unlock this door?
|
||
|
//
|
||
|
if ( soldier->Has_Key( Get_DoorPhysDef()->LockCode ) ) {
|
||
|
result = DOOR_OPEN_OK;
|
||
|
break;
|
||
|
} else {
|
||
|
result = DOOR_OPEN_LOCKED;
|
||
|
}
|
||
|
} else {
|
||
|
result = DOOR_OPEN_OK;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
|
||
|
NonRefPhysListClass obj_list;
|
||
|
WWASSERT(PhysicsSceneClass::Get_Instance() != NULL);
|
||
|
PhysicsSceneClass::Get_Instance()->Collect_Objects(trigger_zone,false,true,&obj_list);
|
||
|
NonRefPhysListIterator it(&obj_list);
|
||
|
|
||
|
while (!it.Is_Done() && result == DOOR_OPEN_NOONE) {
|
||
|
|
||
|
CombatPhysObserverClass * observer = (CombatPhysObserverClass *)it.Peek_Obj()->Get_Observer();
|
||
|
//WWASSERT(observer != NULL);
|
||
|
//if (observer->As_PhysicalGameObj()) {
|
||
|
if (observer != NULL && observer->As_PhysicalGameObj()) {
|
||
|
SoldierGameObj * soldier = observer->As_PhysicalGameObj()->As_SoldierGameObj();
|
||
|
VehicleGameObj * vehicle = observer->As_PhysicalGameObj()->As_VehicleGameObj();
|
||
|
|
||
|
//
|
||
|
// Check if this is a soldier who can open the door
|
||
|
//
|
||
|
if ((soldier != NULL) && soldier->Is_Human_Controlled()) {
|
||
|
|
||
|
WWASSERT(Get_DoorPhysDef() != NULL);
|
||
|
if ( Get_DoorPhysDef()->LockCode == 0 ) {
|
||
|
|
||
|
result = DOOR_OPEN_OK;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
if (Can_Unlock_Me(soldier)) {
|
||
|
result = DOOR_OPEN_OK;
|
||
|
break;
|
||
|
} else {
|
||
|
result = DOOR_OPEN_LOCKED;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check if this is a vehicle that is allowed to open the door
|
||
|
//
|
||
|
WWASSERT(Get_DoorPhysDef() != NULL);
|
||
|
if ((vehicle != NULL) && (Get_DoorPhysDef()->DoorOpensForVehicles)) {
|
||
|
|
||
|
if ( Get_DoorPhysDef()->LockCode == 0 ) {
|
||
|
|
||
|
result = DOOR_OPEN_OK;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
SoldierGameObj * driver = vehicle->Get_Driver();
|
||
|
if ((driver != NULL) && (Can_Unlock_Me(driver))) {
|
||
|
result = DOOR_OPEN_OK;
|
||
|
break;
|
||
|
} else {
|
||
|
result = DOOR_OPEN_LOCKED;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
it.Next();
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
bool DoorPhysClass::Can_Unlock_Me(SoldierGameObj * soldier) const
|
||
|
{
|
||
|
if ( soldier == COMBAT_STAR ) {
|
||
|
Vector3 pos;
|
||
|
soldier->Get_Position( &pos );
|
||
|
const char * desc = soldier->Has_Key( Get_DoorPhysDef()->LockCode ) ? "KEUS" : "KEDE";
|
||
|
DIAG_LOG(( desc, "%1.2f; %1.2f; %1.2f; %d; %d", pos.X, pos.Y, pos.Z, Get_ID(), Get_DoorPhysDef()->LockCode ));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Can the soldier unlock this door?
|
||
|
//
|
||
|
return (Get_DoorPhysDef()->LockCode == 0) || (soldier->Has_Key( Get_DoorPhysDef()->LockCode ));
|
||
|
}
|
||
|
|
||
|
|
||
|
void DoorPhysClass::Set_Precision(void)
|
||
|
{
|
||
|
cEncoderList::Set_Precision( BITPACK_DOOR_STATE, 0, (int)STATE_MAX );
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool DoorPhysClass::Is_Door_Open( void ) const
|
||
|
{
|
||
|
return (State == STATE_OPENED_DOOR);
|
||
|
}
|