Files
DoomRTX/neo/prey/Prey/game_proxdoor.cpp
2026-05-05 15:01:01 -07:00

1164 lines
34 KiB
C++

#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
const idEventDef EV_PollForExit("<pollforexit>", NULL);
const float proxDoorRefreshMS = 50.f; //refresh rate of door while open (controls how frequently to check if someone is still close enough)
ABSTRACT_DECLARATION( idEntity, hhProxDoorSection )
END_CLASS
void hhProxDoorSection::Spawn( void ) {
fl.networkSync = true;
proximity = 0.0f;
hasNetData = false;
proxyParent = NULL;
}
void hhProxDoorSection::ClientPredictionThink( void ) {
Show();
idEntity::ClientPredictionThink();
}
void hhProxDoorSection::WriteToSnapshot( idBitMsgDelta &msg ) const {
WriteBindToSnapshot(msg);
GetPhysics()->WriteToSnapshot(msg);
}
void hhProxDoorSection::ReadFromSnapshot( const idBitMsgDelta &msg ) {
ReadBindFromSnapshot(msg);
GetPhysics()->ReadFromSnapshot(msg);
if (msg.HasChanged()) {
Show();
UpdateVisuals();
Present();
GetPhysics()->LinkClip();
}
}
//-------------------------------------------------------------------------------------------------
// hhProxDoor.
//-------------------------------------------------------------------------------------------------
CLASS_DECLARATION( idEntity, hhProxDoor )
EVENT( EV_Touch, hhProxDoor::Event_Touch )
EVENT( EV_PollForExit, hhProxDoor::Event_PollForExit )
EVENT( EV_PostSpawn, hhProxDoor::Event_PostSpawn )
EVENT( EV_Activate, hhProxDoor::Event_Activate )
END_CLASS
//--------------------------------
// hhProxDoor::hhProxDoor
//--------------------------------
hhProxDoor::hhProxDoor() {
areaPortal = 0;
proxState = PROXSTATE_Inactive;
doorTrigger = NULL;
aas_area_closed = false;
hasNetData = false;
sndTrigger = NULL;
nextSndTriggerTime = 0;
//HUMANHEAD PCF rww 06/06/06 - fix for snappy prox doors
lastAmount = 0.0f;
//HUMANHEAD END
}
//--------------------------------
// hhProxDoor::hhProxDoor
//--------------------------------
hhProxDoor::~hhProxDoor() {
if (doorTrigger) {
doorTrigger->Unlink();
delete doorTrigger;
doorTrigger = NULL;
}
if ( sndTrigger ) {
sndTrigger->Unlink();
delete sndTrigger;
sndTrigger = NULL;
}
}
//--------------------------------
// hhProxDoor::Spawn
//--------------------------------
void hhProxDoor::Spawn() {
proxState = PROXSTATE_Inactive;
doorSndState = PDOORSND_Closed;
spawnArgs.GetBool( "startlocked", "0", doorLocked );
SetShaderParm( SHADERPARM_MODE, GetDoorShaderParm( doorLocked, true ) ); // 2=locked, 1=unlocked, 0=never locked
if( !spawnArgs.GetFloat("trigger_distance", "0.0", maxDistance) ) {
common->Warning( "No 'trigger_distance' specified for entityDef '%s'", this->GetEntityDefName() );
}
if( !spawnArgs.GetFloat("movement_distance", "0.0", movementDistance) ) {
common->Warning( "No 'movement_distance' specified for entityDef '%s'", this->GetEntityDefName() );
}
lastDistance = movementDistance + 1.0f; // Safe default -mdl
if( !spawnArgs.GetFloat("stop_distance", "0.0", stopDistance) ) {
common->Warning( "No 'stop_distance' specificed for entityDef '%s'", this->GetEntityDefName() );
}
spawnArgs.GetBool( "openForMonsters", "1", openForMonsters );
spawnArgs.GetFloat( "damage", "1", damage );
//Find any portal boundary we are on
areaPortal = gameRenderWorld->FindPortal( GetPhysics()->GetAbsBounds() );
if (gameLocal.isMultiplayer) {
fl.networkSync = true;
if (gameLocal.isClient) {
doorTrigger = new idClipModel( idTraceModel(idBounds(vec3_origin).Expand(maxDistance)) );
doorTrigger->Link( gameLocal.clip, this, 255, GetOrigin(), GetAxis() );
doorTrigger->SetContents( CONTENTS_TRIGGER );
SetAASAreaState( doorLocked ); //close the area state if we are locked...
SetDoorState( PROXSTATE_Inactive );
}
else {
PostEventMS( &EV_PostSpawn, 50 ); //rww - this must be delayed or it will happen on the first server frame and we DON'T want that.
}
}
else { //just call it now. some sp maps might target a door piece in the spawn function of an entity or something crazy like that.
Event_PostSpawn();
}
}
//--------------------------------
// hhProxDoor::Event_PostSpawn
//--------------------------------
void hhProxDoor::Event_PostSpawn( void ) {
int numSubObjs;
int i;
const char* objDef;
//Parse and spawn our door sections
numSubObjs = spawnArgs.GetInt( "num_doorobjs", "0" );
for( i = 0; i < numSubObjs; i++ ) {
if( !spawnArgs.GetString( va("doorobject%i", i+1), "", &objDef ) ) {
common->Warning( "failed to find doorobject%i", i+1 );
}
else {
//Set our default rotation/origin.
idDict args;
args.SetVector( "origin", this->GetOrigin() );
args.SetMatrix( "rotation", this->GetAxis() );
hhProxDoorSection* ent = static_cast<hhProxDoorSection*> ( gameLocal.SpawnObject(objDef, &args) );
if( !ent ) {
common->Warning( "failed to spawn doorobject%i for entityDef '%s'", i+1, GetEntityDefName() );
}
else {
ent->proxyParent = this;
doorPieces.Append( ent );
}
}
}
//Spawn our trigger and link it up
// if( doorLocked && !spawnArgs.GetBool("locktrigger") ) {
//we would never be able to open the door, so don't spawn a trigger
// }
// else {
doorTrigger = new idClipModel( idTraceModel(idBounds(vec3_origin).Expand(maxDistance)) );
doorTrigger->Link( gameLocal.clip, this, 255, GetOrigin(), GetAxis() );
doorTrigger->SetContents( CONTENTS_TRIGGER );
// }
SpawnSoundTrigger();
SetAASAreaState( doorLocked ); //close the area state if we are locked...
SetDoorState( PROXSTATE_Inactive );
}
void hhProxDoor::SpawnSoundTrigger() {
idBounds bounds,localbounds;
int i;
int best;
// Since models bounds are overestimated, we need to use the bounds from the
// clipmodel, which was set before the over-estimation
localbounds = GetPhysics()->GetBounds();
// find the thinnest axis, which will be the one we expand
best = 0;
for ( i = 1 ; i < 3 ; i++ ) {
if ( localbounds[1][ i ] - localbounds[0][ i ] < localbounds[1][ best ] - localbounds[0][ best ] ) {
best = i;
}
}
localbounds[1][ best ] += 50;
localbounds[0][ best ] -= 50;
// Now transform into absolute coordintates
if ( GetPhysics()->GetAxis().IsRotated() ) {
bounds.FromTransformedBounds( localbounds, GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() );
}
else {
bounds[0] = localbounds[0] + GetPhysics()->GetOrigin();
bounds[1] = localbounds[1] + GetPhysics()->GetOrigin();
}
bounds[0] -= GetPhysics()->GetOrigin();
bounds[1] -= GetPhysics()->GetOrigin();
// create a trigger clip model
sndTrigger = new idClipModel( idTraceModel( bounds ) );
sndTrigger->Link( gameLocal.clip, this, 254, GetPhysics()->GetOrigin(), mat3_identity );
sndTrigger->SetContents( CONTENTS_TRIGGER );
}
void hhProxDoor::Save(idSaveGame *savefile) const {
int i;
savefile->WriteInt( proxState );
savefile->WriteInt( doorSndState );
savefile->WriteInt( doorPieces.Num() ); // idList<class hhProxDoorSection*>
for (i=0; i<doorPieces.Num(); i++) {
//savefile->WriteObject( doorPieces[i] );
doorPieces[i].Save(savefile);
}
savefile->WriteClipModel( doorTrigger );
savefile->WriteFloat( entDistanceSq );
savefile->WriteFloat( maxDistance );
savefile->WriteFloat( movementDistance );
savefile->WriteFloat( stopDistance );
savefile->WriteInt( areaPortal );
if ( areaPortal ) {
savefile->WriteInt( gameRenderWorld->GetPortalState( areaPortal ) );
}
savefile->WriteBool( doorLocked );
savefile->WriteFloat( lastAmount );
savefile->WriteBool( openForMonsters );
savefile->WriteBool( aas_area_closed );
savefile->WriteFloat( lastDistance );
savefile->WriteClipModel( sndTrigger );
savefile->WriteInt( nextSndTriggerTime );
}
void hhProxDoor::Restore( idRestoreGame *savefile ) {
int i, num;
savefile->ReadInt( (int &)proxState );
savefile->ReadInt( (int &)doorSndState );
doorPieces.Clear();
savefile->ReadInt( num ); // idList<class hhProxDoorSection*>
doorPieces.SetNum( num );
for (i=0; i<num; i++) {
//savefile->ReadObject( reinterpret_cast<idClass *&>(doorPieces[i]) );
doorPieces[i].Restore(savefile);
}
savefile->ReadClipModel( doorTrigger );
savefile->ReadFloat( entDistanceSq );
savefile->ReadFloat( maxDistance );
savefile->ReadFloat( movementDistance );
savefile->ReadFloat( stopDistance );
savefile->ReadInt( (int &)areaPortal );
if ( areaPortal ) {
int portalState;
savefile->ReadInt( portalState );
gameLocal.SetPortalState( areaPortal, portalState );
}
savefile->ReadBool( doorLocked );
savefile->ReadFloat( lastAmount );
savefile->ReadBool( openForMonsters );
savefile->ReadBool( aas_area_closed );
savefile->ReadFloat( lastDistance );
SetAASAreaState( aas_area_closed );
spawnArgs.GetFloat( "damage", "1", damage );
savefile->ReadClipModel( sndTrigger );
savefile->ReadInt( nextSndTriggerTime );
}
void hhProxDoor::ClientPredictionThink( void ) {
Think();
}
void hhProxDoor::WriteToSnapshot( idBitMsgDelta &msg ) const {
WriteBindToSnapshot(msg);
GetPhysics()->WriteToSnapshot(msg);
msg.WriteBits(doorPieces.Num(), 8);
for (int i = 0; i < doorPieces.Num(); i++) {
msg.WriteBits(doorPieces[i].GetSpawnId(), 32);
}
msg.WriteBits(proxState, 8);
msg.WriteFloat(lastAmount);
msg.WriteBits(aas_area_closed, 1);
//don't need this, predicting door movement.
//msg.WriteBits(doorSndState, 8);
}
void hhProxDoor::ReadFromSnapshot( const idBitMsgDelta &msg ) {
ReadBindFromSnapshot(msg);
GetPhysics()->ReadFromSnapshot(msg);
int num = msg.ReadBits(8);
doorPieces.SetNum(num);
for (int i = 0; i < num; i++) {
int spawnId = msg.ReadBits(32);
if (!spawnId) {
doorPieces[i] = NULL;
}
else {
doorPieces[i].SetSpawnId(spawnId);
}
}
EProxState newProxState = (EProxState)msg.ReadBits(8);
if (proxState != newProxState) {
SetDoorState(newProxState);
}
lastAmount = msg.ReadFloat();
bool closed = !!msg.ReadBits(1);
if (aas_area_closed != closed) {
SetAASAreaState(closed);
}
/*
EPDoorSound newSndState = (EPDoorSound)msg.ReadBits(8);
if (newSndState != doorSndState) {
UpdateSoundState(newSndState);
}
*/
hasNetData = true;
}
//--------------------------------
// hhProxDoor::Think
//--------------------------------
void hhProxDoor::Ticker( void ) {
int i;
float bestDistSq, bestDist = idMath::INFINITY, amount;
//HUMANHEAD PCF mdl 04/27/06 - Locked doors are forced inactive
if ( doorLocked && proxState == PROXSTATE_Active ) {
proxState = PROXSTATE_GoingInactive;
}
if ( proxState == PROXSTATE_GoingInactive ) {
float fullyOpen = (movementDistance - stopDistance) / movementDistance;
//HUMANHEAD PCF mdl 04/27/06 - Added 30 HZ multiplier
float step = (0.2f * ( 1.0f / ( 1000.0f / 60.0f ) ) ) * (60.0f * USERCMD_ONE_OVER_HZ);
float low = idMath::ClampFloat( 0.0f, 1.0f, lastAmount - step );
float high = idMath::ClampFloat( 0.0f, 1.0f, lastAmount + step );
amount = idMath::ClampFloat( low, high, 0.0f );
//HUMANHEAD PCF mdl 04/27/06 - Removed old lock code that was here
for( i = 0; i < doorPieces.Num(); i++ ) {
if (doorPieces[i].IsValid()) { //rww - added in case something decides to remove one of the pieces externally.
if (gameLocal.isClient && areaPortal && gameRenderWorld->GetPortalState(areaPortal) != PS_BLOCK_NONE) {
amount = 0.0f; //rww - hax for portal state sync'ing on client and server
}
doorPieces[ i ]->SetProximity( amount );
}
}
if ( amount == 0.0f ) {
SetDoorState( PROXSTATE_Inactive );
UpdateSoundState( PDOORSND_Closed );
} else {
UpdateSoundState( PDOORSND_Closing );
}
} else {
bestDist = movementDistance;
bestDistSq = PollClosestEntity();
if( bestDistSq >= 0.f ) {
bestDist = idMath::Sqrt( bestDistSq );
}
if ( bestDistSq == -1.0f ) {
SetDoorState( PROXSTATE_GoingInactive );
return;
}
// Set the default amount to no change
amount = lastAmount;
if( bestDist < movementDistance ) {
float fullyOpen = (movementDistance - stopDistance) / movementDistance;
amount = idMath::ClampFloat( 0.f, fullyOpen, (1.f - ( bestDist / movementDistance )) );
//HUMANHEAD PCF mdl 04/27/06 - Added 30 HZ multiplier
float step = (0.2f * ( 1.0f / ( 1000.0f / 60.0f ) ) ) * (60.0f * USERCMD_ONE_OVER_HZ);
float low = idMath::ClampFloat( 0.0f, 1.0f, lastAmount - step );
float high = idMath::ClampFloat( 0.0f, 1.0f, lastAmount + step );
amount = idMath::ClampFloat( low, high, amount );
if ( doorLocked ) {
for( i = 0; i < doorPieces.Num(); i++ ) {
if (doorPieces[i].IsValid()) {
doorPieces[ i ]->SetProximity( 0.0f );
}
}
} else {
for( i = 0; i < doorPieces.Num(); i++ ) {
if (doorPieces[i].IsValid()) { //rww - added in case something decides to remove one of the pieces externally.
if (gameLocal.isClient && areaPortal && gameRenderWorld->GetPortalState(areaPortal) != PS_BLOCK_NONE) {
amount = 0.0f; //rww - hax for portal state sync'ing on client and server
}
doorPieces[ i ]->SetProximity( amount );
}
}
}
if( lastAmount == -1 && amount >= 0.f ) { //was closed, just starting to open
UpdateSoundState( PDOORSND_Opened );
}
else if( lastAmount > amount ) { //closing
UpdateSoundState( PDOORSND_Closing );
}
else if( lastAmount < amount ) { //opening
UpdateSoundState( PDOORSND_Opening );
}
else if( amount == fullyOpen ) { //fully open
UpdateSoundState( PDOORSND_FullyOpened );
}
else { //stop sounds, since we aren't moving
UpdateSoundState( PDOORSND_Stopped );
}
}
else {
SetDoorState( PROXSTATE_GoingInactive );
UpdateSoundState( PDOORSND_Closing );
}
}
// If we're closing and 75% closed or more, crush anything unlucky enough to be inside us (don't do this on the client -rww)
if ( !gameLocal.isClient && lastAmount < 0.25f && lastAmount != -1.0f && amount != -1.0f && amount < lastAmount ) {
CrushEntities();
}
lastAmount = amount;
lastDistance = bestDist;
}
void hhProxDoor::UpdateSoundState( EPDoorSound newState ) {
if( doorSndState == newState ) {
return;
}
switch( newState ) {
case PDOORSND_Opening:
StopSound( SND_CHANNEL_BODY );
StartSound( "snd_closing", SND_CHANNEL_BODY );
break;
case PDOORSND_Closing:
StopSound( SND_CHANNEL_BODY );
StartSound( "snd_opening", SND_CHANNEL_BODY );
break;
case PDOORSND_Closed:
StopSound( SND_CHANNEL_BODY2 );
StopSound( SND_CHANNEL_BODY );
StartSound( "snd_closed", SND_CHANNEL_BODY2 );
break;
case PDOORSND_Opened:
StopSound( SND_CHANNEL_BODY2 );
StartSound( "snd_opened", SND_CHANNEL_BODY2 );
break;
case PDOORSND_Stopped:
StopSound( SND_CHANNEL_BODY );
break;
case PDOORSND_FullyOpened:
StopSound( SND_CHANNEL_BODY );
StopSound( SND_CHANNEL_BODY2 );
StartSound( "snd_fullyopened", SND_CHANNEL_BODY2 );
break;
}
doorSndState = newState;
}
//--------------------------------
// hhProxDoor::OpenPortal
//--------------------------------
void hhProxDoor::OpenPortal( void ) {
if( areaPortal && !gameLocal.isClient ) {
gameLocal.SetPortalState( areaPortal, PS_BLOCK_NONE );
}
SetAASAreaState( false );
}
//--------------------------------
// hhProxDoor::ClosePortal
//--------------------------------
void hhProxDoor::ClosePortal( void ) {
if( areaPortal && !gameLocal.isClient ) {
gameLocal.SetPortalState( areaPortal, PS_BLOCK_VIEW );
}
SetAASAreaState( IsLocked() );
}
//--------------------------------
// hhProxDoor::SetAASAreaState
//--------------------------------
void hhProxDoor::SetAASAreaState( bool closed ) {
aas_area_closed = closed;
if( !openForMonsters ) {
aas_area_closed = true;
}
gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_CLUSTERPORTAL | AREACONTENTS_OBSTACLE, aas_area_closed );
}
//--------------------------------
// hhProxDoor::Event_PollForExit
//--------------------------------
void hhProxDoor::Event_PollForExit() {
if( PollClosestEntity() == -1.f ) {
SetDoorState( PROXSTATE_GoingInactive );
return;
}
CancelEvents( &EV_PollForExit );
PostEventMS( &EV_PollForExit, proxDoorRefreshMS );
}
//--------------------------------
// hhProxDoor::PollClosestEntity
//--------------------------------
float hhProxDoor::PollClosestEntity() {
int num;
int i;
idEntity* ents[MAX_GENTITIES];
float bestLen;
float distSq;
if (!doorTrigger) {
return 0.0f;
}
num = gameLocal.clip.EntitiesTouchingBounds( doorTrigger->GetAbsBounds().Expand( pm_bboxwidth.GetFloat() ), MASK_SHOT_BOUNDINGBOX, ents, MAX_GENTITIES );
float thinkDistanceSq = (maxDistance + pm_bboxwidth.GetFloat()) * (maxDistance + pm_bboxwidth.GetFloat());
bestLen = thinkDistanceSq;
idEntity* bestEnt = NULL;
for( i = 0; i < num; i++ ) {
if( ents[ i ] && ents[ i ] != this && ents[ i ]->fl.touchTriggers && !ents[ i ]->IsType(hhProxDoorSection::Type) ) {
if( ents[ i ]->IsType(hhPlayer::Type) || ents[ i ]->IsType(hhSpiritProxy::Type) || (openForMonsters && ents[ i ]->IsType(idAI::Type) && ents[ i ]->GetHealth() > 0 ) ) {
if (ents[ i ]->IsType(hhPlayer::Type) && !fl.allowSpiritWalkTouch) { //rww - we don't want spirits to open proxy doors.
hhPlayer *pl = static_cast<hhPlayer *>(ents[i]);
if (pl->IsSpiritWalking()) {
continue;
}
}
distSq = ( ents[ i ]->GetOrigin() - GetOrigin() ).LengthSqr();
if( distSq < bestLen ) {
bestLen = distSq;
bestEnt = ents[ i ];
}
}
}
}
if( bestLen < thinkDistanceSq ) {
entDistanceSq = bestLen;
}
else {
entDistanceSq = -1.f;
}
return entDistanceSq;
}
//--------------------------------
// hhProxDoor::SetDoorState
//--------------------------------
void hhProxDoor::SetDoorState( EProxState doorState ) {
int i;
//HUMANHEAD PCF mdl 04/27/06 - Don't allow locked doors to become active
if ( doorLocked && doorState == PROXSTATE_Active ) {
return;
}
switch( doorState ) {
case PROXSTATE_Active:
BecomeActive( TH_TICKER );
CancelEvents( &EV_PollForExit );
PostEventMS( &EV_PollForExit, 500 );
OpenPortal();
break;
case PROXSTATE_GoingInactive:
break;
case PROXSTATE_Inactive:
// Guarantee the door is closed
for( i = 0; i < doorPieces.Num(); i++ ) {
if (doorPieces[i].IsValid()) {
doorPieces[ i ]->SetProximity( 0.0 );
}
}
ClosePortal();
CancelEvents( &EV_PollForExit );
BecomeInactive( TH_TICKER );
break;
}
proxState = doorState;
}
//--------------------------------
// hhProxDoor::IsLocked
//--------------------------------
bool hhProxDoor::IsLocked() {
return doorLocked;
}
//--------------------------------
// hhProxDoor::Lock
//--------------------------------
void hhProxDoor::Lock( int f ) {
doorLocked = f > 0 ? true : false;
//HUMANHEAD PCF mdl 04/27/06 - Changed PROXSTATE_Inactive to PROXSTATE_GoingInactive
SetDoorState( doorLocked ? PROXSTATE_GoingInactive : PROXSTATE_Active );
SetShaderParm( SHADERPARM_MODE, GetDoorShaderParm( doorLocked, false ) ); // 2=locked, 1=unlocked, 0=never locked
StopSound( SND_CHANNEL_ANY );
}
//--------------------------------
// hhProxDoor::CrushEntities
//--------------------------------
void hhProxDoor::CrushEntities() {
int num;
int i;
idEntity* ents[MAX_GENTITIES];
num = gameLocal.clip.EntitiesTouchingBounds( GetPhysics()->GetAbsBounds(), MASK_SHOT_BOUNDINGBOX|CONTENTS_RENDERMODEL, ents, MAX_GENTITIES );
const char *damageType = spawnArgs.GetString("damageType");
for( i = 0; i < num; i++ ) {
if( ents[ i ] != this && !ents[ i ]->IsType(hhProxDoorSection::Type) && !ents[ i ]->IsType(hhPlayer::Type) && !ents[ i ]->IsType(idAFAttachment::Type) ) { // Check for the player and idAFAttachment (head) in the case of spirit walk
ents[ i ]->Damage( this, this, vec3_origin, damageType, damage, INVALID_JOINT );
ents[ i ]->SquishedByDoor( this );
}
}
}
//--------------------------------
// hhProxDoor::Event_Touch
//--------------------------------
void hhProxDoor::Event_Touch( idEntity *other, trace_t *trace ) {
if ( sndTrigger && trace->c.id == sndTrigger->GetId() ) {
if (other && other->IsType(hhPlayer::Type) && IsLocked() && gameLocal.time > nextSndTriggerTime) {
StartSound("snd_locked", SND_CHANNEL_ANY, 0, false, NULL );
nextSndTriggerTime = gameLocal.time + 10000;
}
return;
}
if( proxState == PROXSTATE_Active ) {
return;
}
if ( !other ) {
gameLocal.Warning("hhProxDoor: Event_Touch given NULL for other\n");
return;
}
float dist = ( other->GetOrigin() - GetOrigin() ).Length();
if (dist > movementDistance) {
return;
}
if( !IsLocked() ) {
SetDoorState( PROXSTATE_Active );
}
}
//--------------------------------
// hhProxDoor::Event_Activate
//--------------------------------
void hhProxDoor::Event_Activate( idEntity* activator ) {
if( spawnArgs.GetBool("locktrigger") ) {
Lock(!doorLocked);
SetAASAreaState( doorLocked );
}
}
//-------------------------------------------------------------------------------------------------
// hhProxDoorTranslator.
//-------------------------------------------------------------------------------------------------
CLASS_DECLARATION( hhProxDoorSection, hhProxDoorTranslator )
END_CLASS
//--------------------------------
// hhProxDoorTranslator::Spawn
//--------------------------------
void hhProxDoorTranslator::Spawn( void ) {
idVec3 sectionOffset;
sectionType = PROXSECTION_Translator;
if( !spawnArgs.GetVector("section_offset", "0 0 0", sectionOffset) ) {
common->Warning( "No section offset found for '%s'", this->GetEntityDefName() );
}
targetOrigin = sectionOffset;
baseOrigin = GetOrigin();
fl.networkSync = true;
}
//--------------------------------
// hhProxDoorTranslator::Save
//--------------------------------
void hhProxDoorTranslator::Save(idSaveGame *savefile) const {
savefile->WriteVec3( baseOrigin );
savefile->WriteVec3( targetOrigin );
}
//--------------------------------
// hhProxDoorTranslator::Restore
//--------------------------------
void hhProxDoorTranslator::Restore( idRestoreGame *savefile ) {
savefile->ReadVec3( baseOrigin );
savefile->ReadVec3( targetOrigin );
}
//--------------------------------
// hhProxDoorTranslator::ClientPredictionThink
//--------------------------------
void hhProxDoorTranslator::ClientPredictionThink( void ) {
hhProxDoorSection::ClientPredictionThink();
}
//--------------------------------
// hhProxDoorTranslator::WriteToSnapshot
//--------------------------------
void hhProxDoorTranslator::WriteToSnapshot( idBitMsgDelta &msg ) const {
//hhProxDoorSection::WriteToSnapshot(msg);
#ifdef _SYNC_PROXDOORS
msg.WriteFloat(baseOrigin.x);
msg.WriteFloat(baseOrigin.y);
msg.WriteFloat(baseOrigin.z);
msg.WriteFloat(targetOrigin.x);
msg.WriteFloat(targetOrigin.y);
msg.WriteFloat(targetOrigin.z);
if (GetPhysics()->IsType(idPhysics_Static::Type)) {
idPhysics_Static *phys = static_cast<idPhysics_Static *>(GetPhysics());
staticPState_t *state = phys->GetPState();
idCQuat q = state->axis.ToCQuat();
msg.WriteFloat(q.x);
msg.WriteFloat(q.y);
msg.WriteFloat(q.z);
}
msg.WriteFloat(proximity);
#else
WriteBindToSnapshot(msg);
msg.WriteBits(proxyParent.GetSpawnId(), 32);
#endif
}
//--------------------------------
// hhProxDoorTranslator::ReadFromSnapshot
//--------------------------------
void hhProxDoorTranslator::ReadFromSnapshot( const idBitMsgDelta &msg ) {
//hhProxDoorSection::ReadFromSnapshot(msg);
#ifdef _SYNC_PROXDOORS
baseOrigin.x = msg.ReadFloat();
baseOrigin.y = msg.ReadFloat();
baseOrigin.z = msg.ReadFloat();
targetOrigin.x = msg.ReadFloat();
targetOrigin.y = msg.ReadFloat();
targetOrigin.z = msg.ReadFloat();
if (GetPhysics()->IsType(idPhysics_Static::Type)) {
idPhysics_Static *phys = static_cast<idPhysics_Static *>(GetPhysics());
staticPState_t *state = phys->GetPState();
idCQuat q;
q.x = msg.ReadFloat();
q.y = msg.ReadFloat();
q.z = msg.ReadFloat();
state->axis = q.ToMat3();
}
float prox = msg.ReadFloat();
SetProximity(prox);
#else
ReadBindFromSnapshot(msg);
proxyParent.SetSpawnId(msg.ReadBits(32));
if (proxyParent.IsValid() && proxyParent->IsType(hhProxDoor::Type)) {
hhProxDoor *parentPtr = static_cast<hhProxDoor *>(proxyParent.GetEntity());
if (parentPtr->hasNetData) {
if (!hasNetData) {
idVec3 parentOrigin;
idMat3 parentAxis;
parentOrigin = proxyParent->GetOrigin();//proxyParent->spawnArgs.GetVector("origin", "0 0 0", parentOrigin);
parentAxis = proxyParent->GetAxis();//proxyParent->spawnArgs.GetMatrix("rotation", "1 0 0 0 1 0 0 0 1", parentAxis);
SetOrigin(parentOrigin);
SetAxis(parentAxis);
baseOrigin = GetOrigin();
spawnArgs.SetVector("origin", parentOrigin);
spawnArgs.SetMatrix("rotation", parentAxis);
hasNetData = true;
}
}
else {
hasNetData = false;
}
}
#endif
}
//--------------------------------
// hhProxDoorTranslator::SetProximity
//--------------------------------
void hhProxDoorTranslator::SetProximity( float prox ) {
SetOrigin( baseOrigin + (targetOrigin * prox) );
proximity = prox;
}
//-------------------------------------------------------------------------------------------------
// hhProxDoorRotator.
//-------------------------------------------------------------------------------------------------
CLASS_DECLARATION( hhProxDoorSection, hhProxDoorRotator )
EVENT( EV_PostSpawn, hhProxDoorRotator::Event_PostSpawn )
END_CLASS
//--------------------------------
// hhProxDoorRotator::Spawn
//--------------------------------
void hhProxDoorRotator::Spawn( void ) {
sectionType = PROXSECTION_Rotator;
if (gameLocal.isMultiplayer) {
if (!gameLocal.isClient) {
PostEventMS( &EV_PostSpawn, 0 );
fl.networkSync = true;
}
}
else { //just call it now. some sp maps might target a door piece in the spawn function of an entity or something crazy like that.
Event_PostSpawn();
}
}
void hhProxDoorRotator::Event_PostSpawn( void ) {
idVec3 sectionOffset;
idVec3 rotVector;
float rotAngle;
if( !spawnArgs.GetVector("section_offset", "0 0 0", sectionOffset) ) {
common->Warning( "No section offset found for '%s'", this->GetEntityDefName() );
}
if( !spawnArgs.GetVector("rot_vector", "0 0 0", rotVector) ) {
common->Warning( "No rotation vector found for '%s'", this->GetEntityDefName() );
}
if( !spawnArgs.GetFloat("rot_angle", "0 0 0", rotAngle) ) {
common->Warning( "No rotation angle found for '%s'", this->GetEntityDefName() );
}
idDict args;
args.SetVector( "origin", GetOrigin() + (sectionOffset * GetAxis()) );
args.SetMatrix( "rotation", GetAxis() );
args.SetVector( "rot_vector", rotVector );
args.SetFloat( "rot_angle", rotAngle );
bindParent = static_cast<hhProxDoorSection*>( gameLocal.SpawnEntityType(hhProxDoorRotMaster::Type, &args) );
if( !bindParent.IsValid() ) {
common->Warning( "Failed to spawn bindParent for '%s'", GetEntityDefName() );
}
else {
bindParent->proxyParent = this;
}
Bind( bindParent.GetEntity(), true );
}
//--------------------------------
// hhProxDoorRotator::Save
//--------------------------------
void hhProxDoorRotator::Save(idSaveGame *savefile) const {
bindParent.Save(savefile);
}
//--------------------------------
// hhProxDoorRotator::Restore
//--------------------------------
void hhProxDoorRotator::Restore( idRestoreGame *savefile ) {
bindParent.Restore(savefile);
}
//--------------------------------
// hhProxDoorRotator::ClientPredictionThink
//--------------------------------
void hhProxDoorRotator::ClientPredictionThink( void ) {
hhProxDoorSection::ClientPredictionThink();
}
//--------------------------------
// hhProxDoorRotator::WriteToSnapshot
//--------------------------------
void hhProxDoorRotator::WriteToSnapshot( idBitMsgDelta &msg ) const {
// hhProxDoorSection::WriteToSnapshot(msg);
#ifdef _SYNC_PROXDOORS
WriteBindToSnapshot(msg);
if (GetPhysics()->IsType(idPhysics_Static::Type)) {
idPhysics_Static *phys = static_cast<idPhysics_Static *>(GetPhysics());
staticPState_t *state = phys->GetPState();
msg.WriteFloat(state->origin.x);
msg.WriteFloat(state->origin.y);
msg.WriteFloat(state->origin.z);
msg.WriteFloat(state->localOrigin.x);
msg.WriteFloat(state->localOrigin.y);
msg.WriteFloat(state->localOrigin.z);
idCQuat q = state->localAxis.ToCQuat();
msg.WriteFloat(q.x);
msg.WriteFloat(q.y);
msg.WriteFloat(q.z);
}
#else
msg.WriteBits(proxyParent.GetSpawnId(), 32);
WriteBindToSnapshot(msg);
msg.WriteBits(bindParent.GetSpawnId(), 32);
#endif
//not needed without prediction
//msg.WriteBits(bindParent.GetSpawnId(), 32);
}
//--------------------------------
// hhProxDoorRotator::ReadFromSnapshot
//--------------------------------
void hhProxDoorRotator::ReadFromSnapshot( const idBitMsgDelta &msg ) {
// hhProxDoorSection::ReadFromSnapshot(msg);
#ifdef _SYNC_PROXDOORS
ReadBindFromSnapshot(msg);
if (GetPhysics()->IsType(idPhysics_Static::Type)) {
idPhysics_Static *phys = static_cast<idPhysics_Static *>(GetPhysics());
staticPState_t *state = phys->GetPState();
state->origin.x = msg.ReadFloat();
state->origin.y = msg.ReadFloat();
state->origin.z = msg.ReadFloat();
state->localOrigin.x = msg.ReadFloat();
state->localOrigin.y = msg.ReadFloat();
state->localOrigin.z = msg.ReadFloat();
idCQuat q;
q.x = msg.ReadFloat();
q.y = msg.ReadFloat();
q.z = msg.ReadFloat();
state->localAxis = q.ToMat3();
}
#else
proxyParent.SetSpawnId(msg.ReadBits(32));
if (proxyParent.IsValid() && proxyParent->IsType(hhProxDoor::Type)) {
hhProxDoor *parentPtr = static_cast<hhProxDoor *>(proxyParent.GetEntity());
if (parentPtr->hasNetData) {
if (!hasNetData) {
idVec3 parentOrigin;
idMat3 parentAxis;
parentOrigin = proxyParent->GetOrigin();//proxyParent->spawnArgs.GetVector("origin", "0 0 0", parentOrigin);
parentAxis = proxyParent->GetAxis();//proxyParent->spawnArgs.GetMatrix("rotation", "1 0 0 0 1 0 0 0 1", parentAxis);
SetOrigin(parentOrigin);
SetAxis(parentAxis);
spawnArgs.SetVector("origin", parentOrigin);
spawnArgs.SetMatrix("rotation", parentAxis);
hasNetData = true;
}
}
else {
hasNetData = false;
}
}
ReadBindFromSnapshot(msg);
bindParent.SetSpawnId(msg.ReadBits(32));
#endif
//not needed without prediction
/*
int spawnId = msg.ReadBits(32);
if (!spawnId) {
bindParent = NULL;
}
else {
bindParent.SetSpawnId(spawnId);
}
*/
}
//--------------------------------
// hhProxDoorRotator::SetProximity
//--------------------------------
void hhProxDoorRotator::SetProximity( float prox ) {
if( bindParent.IsValid() ) {
bindParent->SetProximity( prox );
}
proximity = prox;
}
//-------------------------------------------------------------------------------------------------
// hhProxDoorRotMaster.
//-------------------------------------------------------------------------------------------------
CLASS_DECLARATION( hhProxDoorSection, hhProxDoorRotMaster )
END_CLASS
//--------------------------------
// hhProxDoorRotMaster::Spawn
//--------------------------------
void hhProxDoorRotMaster::Spawn( void ) {
idVec3 rot_vector;
spawnArgs.GetVector("rot_vector", "0 0 1", rot_vector);
baseAxis = GetAxis();
rotVector = GetAxis() * rot_vector;
spawnArgs.GetFloat("rot_angle", "0.0", rotAngle);
fl.networkSync = true;
}
//--------------------------------
// hhProxDoorRotMaster::Save
//--------------------------------
void hhProxDoorRotMaster::Save(idSaveGame *savefile) const {
savefile->WriteVec3( rotVector );
savefile->WriteFloat( rotAngle );
savefile->WriteMat3( baseAxis );
}
//--------------------------------
// hhProxDoorRotMaster::Restore
//--------------------------------
void hhProxDoorRotMaster::Restore( idRestoreGame *savefile ) {
savefile->ReadVec3( rotVector );
savefile->ReadFloat( rotAngle );
savefile->ReadMat3( baseAxis );
}
//--------------------------------
// hhProxDoorRotMaster::ClientPredictionThink
//--------------------------------
void hhProxDoorRotMaster::ClientPredictionThink( void ) {
hhProxDoorSection::ClientPredictionThink();
}
//--------------------------------
// hhProxDoorRotMaster::WriteToSnapshot
//--------------------------------
void hhProxDoorRotMaster::WriteToSnapshot( idBitMsgDelta &msg ) const {
//hhProxDoorSection::WriteToSnapshot(msg);
#ifdef _SYNC_PROXDOORS
msg.WriteFloat(rotVector.x);
msg.WriteFloat(rotVector.y);
msg.WriteFloat(rotVector.z);
msg.WriteFloat(rotAngle);
idCQuat q = baseAxis.ToCQuat();
msg.WriteFloat(q.x);
msg.WriteFloat(q.y);
msg.WriteFloat(q.z);
if (GetPhysics()->IsType(idPhysics_Static::Type)) {
idPhysics_Static *phys = static_cast<idPhysics_Static *>(GetPhysics());
staticPState_t *state = phys->GetPState();
msg.WriteFloat(state->origin.x);
msg.WriteFloat(state->origin.y);
msg.WriteFloat(state->origin.z);
}
msg.WriteFloat(proximity);
#else
WriteBindToSnapshot(msg);
msg.WriteBits(proxyParent.GetSpawnId(), 32);
#endif
}
//--------------------------------
// hhProxDoorRotMaster::ReadFromSnapshot
//--------------------------------
void hhProxDoorRotMaster::ReadFromSnapshot( const idBitMsgDelta &msg ) {
//hhProxDoorSection::ReadFromSnapshot(msg);
#ifdef _SYNC_PROXDOORS
rotVector.x = msg.ReadFloat();
rotVector.y = msg.ReadFloat();
rotVector.z = msg.ReadFloat();
rotAngle = msg.ReadFloat();
idCQuat q;
q.x = msg.ReadFloat();
q.y = msg.ReadFloat();
q.z = msg.ReadFloat();
baseAxis = q.ToMat3();
if (GetPhysics()->IsType(idPhysics_Static::Type)) {
idPhysics_Static *phys = static_cast<idPhysics_Static *>(GetPhysics());
staticPState_t *state = phys->GetPState();
state->origin.x = msg.ReadFloat();
state->origin.y = msg.ReadFloat();
state->origin.z = msg.ReadFloat();
}
float prox = msg.ReadFloat();
SetProximity(prox);
#else
ReadBindFromSnapshot(msg);
proxyParent.SetSpawnId(msg.ReadBits(32));
if (proxyParent.IsValid() && proxyParent->IsType(hhProxDoorRotator::Type)) {
hhProxDoorRotator *parentPtr = static_cast<hhProxDoorRotator *>(proxyParent.GetEntity());
if (parentPtr->hasNetData) {
if (!hasNetData) {
idVec3 sectionOffset, rot_vector;
idVec3 parentOrigin;
idMat3 parentAxis;
proxyParent->spawnArgs.GetVector("origin", "0 0 0", parentOrigin);
proxyParent->spawnArgs.GetMatrix("rotation", "1 0 0 0 1 0 0 0 1", parentAxis);
proxyParent->spawnArgs.GetVector("section_offset", "0 0 0", sectionOffset);
proxyParent->spawnArgs.GetVector("rot_vector", "0 0 0", rot_vector);
proxyParent->spawnArgs.GetFloat("rot_angle", "0.0", rotAngle);
SetOrigin(parentOrigin+(sectionOffset*parentAxis));
SetAxis(parentAxis);
baseAxis = GetAxis();
rotVector = GetAxis() * rot_vector;
hasNetData = true;
}
}
else {
parentPtr->hasNetData = false;
}
}
#endif
}
//--------------------------------
// hhProxDoorRotMaster::SetProximity
//--------------------------------
void hhProxDoorRotMaster::SetProximity( float prox ) {
idRotation desRotation( vec3_origin, rotVector, prox*rotAngle );
SetAxis( baseAxis * desRotation.ToMat3() );
//rww - proxy door pieces keep getting stuck, so make sure this bastard keeps running physics
if (!IsActive(TH_PHYSICS)) {
BecomeActive(TH_PHYSICS);
}
proximity = prox;
}