mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 08:11:10 +02:00
587 lines
14 KiB
C++
587 lines
14 KiB
C++
#include "precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#include "prey_local.h"
|
|
|
|
CLASS_DECLARATION( idDoor, hhDoor )
|
|
EVENT( EV_Mover_ReturnToPos1, hhDoor::Event_ReturnToPos1 )
|
|
EVENT( EV_ReachedPos, hhDoor::Event_Reached_BinaryMover )
|
|
EVENT( EV_SetBuddiesShaderParm, hhDoor::Event_SetBuddiesShaderParm )
|
|
EVENT( EV_Touch, hhDoor::Event_Touch )
|
|
END_CLASS
|
|
|
|
//--------------------------------
|
|
// hhDoor::Spawn
|
|
//--------------------------------
|
|
void hhDoor::Spawn() {
|
|
airlockMaster = NULL;
|
|
|
|
airlockTeam.SetOwner( this );
|
|
airlockTeamName = spawnArgs.GetString( "airlockTeam" );
|
|
spawnArgs.GetFloat( "airlockwait", "3", airLockSndWait );
|
|
airLockSndWait *= 1000.0f; // Convert from seconds to ms
|
|
|
|
idEntity* master = DetermineTeamMaster( GetAirLockTeamName() );
|
|
if( master ) {
|
|
airlockMaster = static_cast<hhDoor*>( master );
|
|
if( airlockMaster != this ) {
|
|
JoinAirLockTeam( airlockMaster );
|
|
}
|
|
}
|
|
|
|
if( spawnArgs.GetBool("start_open") ) {
|
|
VerifyAirlockTeamStatus();
|
|
}
|
|
|
|
if( moveMaster != this ) {
|
|
CopyTeamInfoToMoveMaster( static_cast<hhDoor*>(moveMaster) );
|
|
}
|
|
|
|
// We only open when dead if we have health to start with
|
|
openWhenDead = health > 0;
|
|
forcedOpen = false;
|
|
nextAirLockSnd = 0;
|
|
|
|
bShuttleDoors = spawnArgs.GetBool( "shuttle_doors" );
|
|
}
|
|
|
|
void hhDoor::Save(idSaveGame *savefile) const {
|
|
savefile->WriteString(airlockTeamName);
|
|
savefile->WriteObject(airlockMaster);
|
|
savefile->WriteBool(openWhenDead);
|
|
savefile->WriteBool(forcedOpen);
|
|
savefile->WriteFloat(airLockSndWait);
|
|
}
|
|
|
|
void hhDoor::Restore( idRestoreGame *savefile ) {
|
|
savefile->ReadString(airlockTeamName);
|
|
savefile->ReadObject( reinterpret_cast<idClass *&>(airlockMaster) );
|
|
savefile->ReadBool(openWhenDead);
|
|
savefile->ReadBool(forcedOpen);
|
|
savefile->ReadFloat(airLockSndWait);
|
|
|
|
airlockTeam.SetOwner( this );
|
|
if( airlockMaster && airlockMaster != this ) {
|
|
JoinAirLockTeam( airlockMaster );
|
|
}
|
|
|
|
nextAirLockSnd = 0;
|
|
|
|
bShuttleDoors = spawnArgs.GetBool( "shuttle_doors" );
|
|
}
|
|
|
|
//--------------------------------
|
|
// hhDoor::~hhDoor
|
|
//--------------------------------
|
|
hhDoor::~hhDoor() {
|
|
airlockTeam.Remove();
|
|
}
|
|
|
|
//--------------------------------
|
|
// hhDoor::Killed
|
|
//--------------------------------
|
|
void hhDoor::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
|
|
|
|
// Only can really be killed if we can be damaged
|
|
if ( openWhenDead ) {
|
|
Open();
|
|
|
|
fl.takedamage = false;
|
|
forcedOpen = true;
|
|
}
|
|
} // Killed( idEntity *, idEntity *, int, const idVec3 &, int )
|
|
|
|
//--------------------------------
|
|
// hhDoor::Use_BinaryMover
|
|
//--------------------------------
|
|
void hhDoor::Use_BinaryMover( idEntity *activator ) {
|
|
if ( airlockMaster && activator && !activator->IsType( idPlayer::Type ) ) {
|
|
return; // Don't allow anyone but the player to affect airlock doors
|
|
}
|
|
|
|
// only the master should be used
|
|
if ( moveMaster != this ) {
|
|
moveMaster->Use_BinaryMover( activator );
|
|
return;
|
|
}
|
|
|
|
if ( !enabled ) {
|
|
return;
|
|
}
|
|
|
|
if ( moverState == MOVER_POS1 || moverState == MOVER_2TO1 ) {
|
|
GotoPosition2();
|
|
}
|
|
else if ( moverState == MOVER_POS2 || moverState == MOVER_1TO2 ) {
|
|
GotoPosition1();
|
|
}
|
|
}
|
|
|
|
//--------------------------------
|
|
// hhDoor::GotoPosition1
|
|
//
|
|
// CloseDoor
|
|
//--------------------------------
|
|
void hhDoor::GotoPosition1() {
|
|
GotoPosition1( spawnArgs.GetBool("toggle") ? 0.0f : wait );
|
|
}
|
|
|
|
//--------------------------------
|
|
// hhDoor::GotoPosition1
|
|
//
|
|
// CloseDoor
|
|
//--------------------------------
|
|
void hhDoor::GotoPosition1( float wait ) {
|
|
idMover_Binary* slave = NULL;
|
|
int partial = 0;
|
|
|
|
//HUMANHEAD: aob - airlock stuff
|
|
if( !CanClose() ) {
|
|
return;
|
|
}
|
|
//HUMNAHEAD END
|
|
|
|
if ( moverState == MOVER_POS2 ) {
|
|
SetGuiStates( guiBinaryMoverStates[MOVER_2TO1] );
|
|
|
|
CancelReturnToPos1();
|
|
|
|
if( wait > 0 ) {
|
|
//HUMANHEAD: aob
|
|
PostEventSec( &EV_Mover_ReturnToPos1, wait );
|
|
//HUMANHEAD END
|
|
} else {
|
|
ProcessEvent( &EV_Mover_ReturnToPos1 );
|
|
}
|
|
}
|
|
|
|
else
|
|
|
|
// only partway up before reversing
|
|
if ( moverState == MOVER_1TO2 ) {
|
|
// use the physics times because this might be executed during the physics simulation
|
|
partial = physicsObj.GetLinearEndTime() - physicsObj.GetTime();
|
|
MatchActivateTeam( MOVER_2TO1, physicsObj.GetTime() - partial );
|
|
}
|
|
}
|
|
|
|
//--------------------------------
|
|
// hhDoor::GotoPosition2
|
|
//
|
|
// OpenDoor
|
|
//--------------------------------
|
|
void hhDoor::GotoPosition2() {
|
|
GotoPosition2( 0.0f );
|
|
}
|
|
|
|
//--------------------------------
|
|
// hhDoor::GotoPosition2
|
|
//
|
|
// OpenDoor
|
|
//--------------------------------
|
|
void hhDoor::GotoPosition2( float wait ) {
|
|
int partial = 0;
|
|
hhDoor *airlockMaster = GetAirLockMaster();
|
|
|
|
//HUMANHEAD: aob - airlock stuff
|
|
if( !CanOpen() && airlockMaster ) {
|
|
ForceAirLockTeamClosed();
|
|
if( gameLocal.time > nextAirLockSnd ) {
|
|
int length;
|
|
StartSound( "snd_airlock", SND_CHANNEL_BODY, 0, false, &length );
|
|
nextAirLockSnd = gameLocal.time + length + airLockSndWait;
|
|
}
|
|
return;
|
|
}
|
|
//HUMNAHEAD END
|
|
|
|
if ( moverState == MOVER_POS1 ) {
|
|
ActivatePrefixed("triggerStartOpen", GetActivator());
|
|
|
|
SetGuiStates( guiBinaryMoverStates[MOVER_1TO2] );
|
|
|
|
MatchActivateTeam( MOVER_1TO2, gameLocal.time );
|
|
|
|
// open areaportal
|
|
ProcessEvent( &EV_Mover_OpenPortal );
|
|
}
|
|
else if ( moverState == MOVER_2TO1 ) { // only partway up before reversing
|
|
// use the physics times because this might be executed during the physics simulation
|
|
partial = physicsObj.GetLinearEndTime() - physicsObj.GetTime();
|
|
MatchActivateTeam( MOVER_1TO2, physicsObj.GetTime() - partial );
|
|
}
|
|
|
|
if( airlockMaster ) {
|
|
// Mark the other team members as locked
|
|
for( hhDoor* node = airlockMaster->airlockTeam.ListHead()->Owner(); node != NULL; node = node->airlockTeam.Next() ) {
|
|
|
|
// Skip this door and it's buddies
|
|
if( node == this || buddyNames.Find( node->name ) ) {
|
|
continue;
|
|
}
|
|
|
|
// Don't change doors that are really locked
|
|
if( node->IsLocked() ) {
|
|
continue;
|
|
}
|
|
|
|
// Mark as locked
|
|
node->SetBuddiesShaderParm( SHADERPARM_MISC, 1.0f );
|
|
}
|
|
|
|
// This prevents the our shader from being set as locked from the player moving too quickly between airlock doors
|
|
SetBuddiesShaderParm( SHADERPARM_MISC, 0.0f );
|
|
}
|
|
}
|
|
|
|
//--------------------------------
|
|
// hhDoor::Open
|
|
//--------------------------------
|
|
void hhDoor::Open( void ) {
|
|
GotoPosition2( wait );
|
|
}
|
|
|
|
//--------------------------------
|
|
// hhDoor::Close
|
|
//--------------------------------
|
|
void hhDoor::Close( void ) {
|
|
// HUMANHEAD nla
|
|
if ( ForcedOpen() ) { return; }
|
|
// HUMANHEAD
|
|
|
|
GotoPosition1( 0.0f );
|
|
}
|
|
|
|
//--------------------------------
|
|
// hhDoor::CanOpen
|
|
//--------------------------------
|
|
bool hhDoor::CanOpen() const {
|
|
if( !GetAirLockMaster() ) {
|
|
return true;
|
|
}
|
|
|
|
for( hhDoor* node = GetAirLockMaster()->airlockTeam.ListHead()->Owner(); node != NULL; node = node->airlockTeam.Next() ) {
|
|
if( node == this ) {
|
|
continue;
|
|
}
|
|
|
|
if( OnMyMoveTeam(node) ) {
|
|
continue;
|
|
}
|
|
|
|
if( node->IsOpen() ) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//--------------------------------
|
|
// hhDoor::CanClose
|
|
//--------------------------------
|
|
bool hhDoor::CanClose() const {
|
|
return true;
|
|
}
|
|
|
|
//--------------------------------
|
|
// hhDoor::OnMyMoveTeam
|
|
//--------------------------------
|
|
bool hhDoor::OnMyMoveTeam( hhDoor* doorPiece ) const {
|
|
for( const idMover_Binary* localDoorPiece = this; localDoorPiece != NULL; localDoorPiece = localDoorPiece->GetActivateChain() ) {
|
|
if( localDoorPiece == doorPiece ) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//--------------------------------
|
|
// hhDoor::CopyTeamInfoToMoveMaster
|
|
//--------------------------------
|
|
void hhDoor::CopyTeamInfoToMoveMaster( hhDoor* master ) {
|
|
if( !master ) {
|
|
return;
|
|
}
|
|
|
|
for( int ix = buddies.Num() - 1; ix >= 0; --ix ) {
|
|
master->buddies.AddUnique( buddies[ix] );
|
|
}
|
|
|
|
for( int ix = buddyNames.Num() - 1; ix >= 0; --ix ) {
|
|
master->buddyNames.AddUnique( buddyNames[ix] );
|
|
}
|
|
}
|
|
|
|
//--------------------------------
|
|
// hhDoor::DetermineTeamMaster
|
|
//--------------------------------
|
|
idEntity* hhDoor::DetermineTeamMaster( const char* teamName ) {
|
|
idEntity* ent = NULL;
|
|
|
|
if ( teamName && teamName[0] ) {
|
|
// find the first entity spawned on this team (which could be us)
|
|
for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
|
|
if (ent->IsType(hhModelDoor::Type) && !idStr::Icmp( static_cast<hhModelDoor *>(ent)->GetAirLockTeamName(), teamName )) {
|
|
return ent;
|
|
}
|
|
if (ent->IsType(hhDoor::Type) && !idStr::Icmp( static_cast<hhDoor *>(ent)->GetAirLockTeamName(), teamName )) {
|
|
return ent;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//--------------------------------
|
|
// hhDoor::JoinAirLockTeam
|
|
//--------------------------------
|
|
void hhDoor::JoinAirLockTeam( hhDoor *master ) {
|
|
assert( master );
|
|
|
|
airlockTeam.AddToEnd( master->airlockTeam );
|
|
}
|
|
|
|
//--------------------------------
|
|
// hhDoor::VerifyAirlockTeamStatus
|
|
//--------------------------------
|
|
void hhDoor::VerifyAirlockTeamStatus() {
|
|
if( !GetAirLockMaster() ) {
|
|
return;
|
|
}
|
|
|
|
for( hhDoor* node = GetAirLockMaster()->airlockTeam.ListHead()->Owner(); node != NULL; node = node->airlockTeam.Next() ) {
|
|
if( node == this ) {
|
|
continue;
|
|
}
|
|
|
|
if( OnMyMoveTeam(node) ) {
|
|
continue;
|
|
}
|
|
|
|
if( !node->IsClosed() ) {
|
|
gameLocal.Warning( "Airlock team '%s' has more than one member starting open", GetAirLockTeamName() );
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------
|
|
// hhDoor::IsClosed
|
|
//--------------------------------
|
|
bool hhDoor::IsClosed() const {
|
|
return ( moverState == MOVER_POS1 );
|
|
}
|
|
|
|
//--------------------------------
|
|
// hhDoor::ForceAirLockTeamClosed
|
|
//--------------------------------
|
|
void hhDoor::ForceAirLockTeamClosed() {
|
|
hhDoor* localMoveMaster = NULL;
|
|
|
|
if( !GetAirLockMaster() ) {
|
|
return;
|
|
}
|
|
|
|
for( hhDoor* node = GetAirLockMaster()->airlockTeam.ListHead()->Owner(); node != NULL; node = node->airlockTeam.Next() ) {
|
|
if( node == this ) {
|
|
continue;
|
|
}
|
|
|
|
if( !node->moveMaster->IsType(hhDoor::Type) ) {
|
|
continue;
|
|
}
|
|
|
|
localMoveMaster = static_cast<hhDoor*>( node->moveMaster );
|
|
//if( node != localMoveMaster ) {
|
|
// continue;
|
|
//}
|
|
|
|
localMoveMaster->CancelReturnToPos1();
|
|
if( !localMoveMaster->IsClosed() ) {
|
|
localMoveMaster->Close();
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------
|
|
// hhDoor::ForceAirLockTeamOpen
|
|
//--------------------------------
|
|
void hhDoor::ForceAirLockTeamOpen() {
|
|
hhDoor* localMoveMaster = NULL;
|
|
|
|
if( !GetAirLockMaster() ) {
|
|
return;
|
|
}
|
|
|
|
for( hhDoor* node = GetAirLockMaster()->airlockTeam.ListHead()->Owner(); node != NULL; node = node->airlockTeam.Next() ) {
|
|
if( node == this ) {
|
|
continue;
|
|
}
|
|
|
|
if( !node->moveMaster->IsType(hhDoor::Type) ) {
|
|
continue;
|
|
}
|
|
|
|
localMoveMaster = static_cast<hhDoor*>( node->moveMaster );
|
|
//if( node != localMoveMaster ) {
|
|
// continue;
|
|
//}
|
|
|
|
localMoveMaster->CancelReturnToPos1();
|
|
if( !localMoveMaster->IsOpen() ) {
|
|
localMoveMaster->Open();
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------
|
|
// hhDoor::CancelReturnToPos1
|
|
//--------------------------------
|
|
void hhDoor::CancelReturnToPos1() {
|
|
for( idMover_Binary* slave = this; slave != NULL; slave = slave->GetActivateChain() ) {
|
|
slave->CancelEvents( &EV_Mover_ReturnToPos1 );
|
|
}
|
|
}
|
|
|
|
//--------------------------------
|
|
// hhDoor::SetBuddiesShaderParm
|
|
//--------------------------------
|
|
void hhDoor::SetBuddiesShaderParm( int parm, float value ) {
|
|
idEntity* buddy = NULL;
|
|
|
|
for( int ix = buddyNames.Num() - 1; ix >= 0; --ix ) {
|
|
if( !buddyNames[ix].Length() ) {
|
|
continue;
|
|
}
|
|
|
|
buddy = gameLocal.FindEntity( buddyNames[ix].c_str() );
|
|
if( !buddy ) {
|
|
continue;
|
|
}
|
|
|
|
buddy->SetShaderParm( parm, value );
|
|
}
|
|
}
|
|
|
|
//--------------------------------
|
|
// hhDoor::ToggleBuddiesShaderParm
|
|
//--------------------------------
|
|
void hhDoor::ToggleBuddiesShaderParm( int parm, float firstValue, float secondValue, float toggleDelay) {
|
|
SetBuddiesShaderParm( parm, firstValue );
|
|
PostEventMS( &EV_SetBuddiesShaderParm, toggleDelay, parm, secondValue );
|
|
}
|
|
|
|
//--------------------------------
|
|
// hhDoor::Event_SetBuddiesShaderParm
|
|
//--------------------------------
|
|
void hhDoor::Event_SetBuddiesShaderParm( int parm, float value ) {
|
|
SetBuddiesShaderParm( parm, value );
|
|
}
|
|
|
|
//--------------------------------
|
|
// hhDoor::Event_ReturnToPos1
|
|
//--------------------------------
|
|
void hhDoor::Event_ReturnToPos1( void ) {
|
|
|
|
if ( !ForcedOpen() ) {
|
|
idDoor::Event_ReturnToPos1();
|
|
}
|
|
|
|
} // Event_ReturnToPos1()
|
|
|
|
//--------------------------------
|
|
// hhDoor::Event_Reached_BinaryMover
|
|
//--------------------------------
|
|
void hhDoor::Event_Reached_BinaryMover( void ) {
|
|
if ( moverState == MOVER_2TO1 ) {
|
|
SetBlocked(false);
|
|
ActivatePrefixed("triggerClosed", this);
|
|
} else if (moverState == MOVER_1TO2) {
|
|
ActivatePrefixed("triggerOpened", this);
|
|
}
|
|
|
|
if ( moverState == MOVER_1TO2 ) {
|
|
// reached pos2
|
|
idThread::ObjectMoveDone( move_thread, this );
|
|
move_thread = 0;
|
|
|
|
// HUMANHEAD aob - removed
|
|
//if ( moveMaster == this ) {
|
|
//StartSound( "snd_opened", SND_CHANNEL_ANY );
|
|
//}
|
|
//HUMANHEAD END
|
|
|
|
SetMoverState( MOVER_POS2, gameLocal.time );
|
|
|
|
SetGuiStates( guiBinaryMoverStates[MOVER_POS2] );
|
|
|
|
UpdateBuddies(1);
|
|
|
|
if( enabled && wait >= 0 && !spawnArgs.GetBool("toggle") ) {
|
|
// return to pos1 after a delay
|
|
//HUMANHEAD: aob
|
|
CancelReturnToPos1();
|
|
//HUMANHEAD END
|
|
PostEventSec( &EV_Mover_ReturnToPos1, wait );
|
|
}
|
|
|
|
// fire targets
|
|
ActivateTargets( moveMaster->GetActivator() );
|
|
} else if ( moverState == MOVER_2TO1 ) {
|
|
// reached pos1
|
|
idThread::ObjectMoveDone( move_thread, this );
|
|
move_thread = 0;
|
|
|
|
SetMoverState( MOVER_POS1, gameLocal.time );
|
|
|
|
SetGuiStates( guiBinaryMoverStates[MOVER_POS1] );
|
|
|
|
UpdateBuddies(0);
|
|
|
|
// close areaportals
|
|
if ( moveMaster == this ) {
|
|
ProcessEvent( &EV_Mover_ClosePortal );
|
|
}
|
|
|
|
if( GetAirLockMaster() ) {
|
|
// Mark the other team members as unlocked
|
|
for( hhDoor* node = GetAirLockMaster()->airlockTeam.ListHead()->Owner(); node != NULL; node = node->airlockTeam.Next() ) {
|
|
|
|
// Skip this door and it's buddies
|
|
if( node == this || buddyNames.Find( node->name ) ) {
|
|
continue;
|
|
}
|
|
|
|
// Don't change doors that are really locked
|
|
if( node->IsLocked() ) {
|
|
continue;
|
|
}
|
|
|
|
// Mark as unlocked when door closes
|
|
node->SetBuddiesShaderParm( SHADERPARM_MISC, 0.0f );
|
|
}
|
|
}
|
|
} else {
|
|
gameLocal.Error( "Event_Reached_BinaryMover: bad moverState" );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
hhDoor::Event_Touch
|
|
================
|
|
*/
|
|
void hhDoor::Event_Touch( idEntity *other, trace_t *trace ) {
|
|
if ( bShuttleDoors && ( ! other->IsType( idActor::Type ) || ! reinterpret_cast<idActor *> ( other )->InVehicle() ) ) {
|
|
if ( gameLocal.time > nextSndTriggerTime ) {
|
|
StartSound( "snd_locked", SND_CHANNEL_ANY, 0, false, NULL );
|
|
nextSndTriggerTime = gameLocal.time + 10000;
|
|
}
|
|
return;
|
|
}
|
|
|
|
idDoor::Event_Touch( other, trace );
|
|
}
|