1214 lines
28 KiB
C++
1214 lines
28 KiB
C++
|
// Copyright (C) 2007 Id Software, Inc.
|
||
|
//
|
||
|
|
||
|
#include "precompiled.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#if defined( _DEBUG ) && !defined( ID_REDIRECT_NEWDELETE )
|
||
|
#define new DEBUG_NEW
|
||
|
#undef THIS_FILE
|
||
|
static char THIS_FILE[] = __FILE__;
|
||
|
#endif
|
||
|
|
||
|
#include "Mover.h"
|
||
|
#include "script/Script_Helper.h"
|
||
|
#include "ContentMask.h"
|
||
|
#include "structures/TeamManager.h"
|
||
|
#include "Player.h"
|
||
|
#include "WorldSpawn.h"
|
||
|
|
||
|
/*
|
||
|
===============================================================================
|
||
|
|
||
|
sdPortalState
|
||
|
|
||
|
===============================================================================
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdPortalState::sdPortalState
|
||
|
============
|
||
|
*/
|
||
|
sdPortalState::sdPortalState( void ) {
|
||
|
areaPortal = 0;
|
||
|
open = true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdPortalState::~sdPortalState
|
||
|
============
|
||
|
*/
|
||
|
sdPortalState::~sdPortalState( void ) {
|
||
|
Open();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdPortalState::Init
|
||
|
============
|
||
|
*/
|
||
|
void sdPortalState::Init( const idBounds& bounds ) {
|
||
|
areaPortal = gameRenderWorld->FindPortal( bounds );
|
||
|
Open();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdPortalState::Open
|
||
|
============
|
||
|
*/
|
||
|
void sdPortalState::Open( void ) {
|
||
|
if ( areaPortal == 0 ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
open = true;
|
||
|
gameRenderWorld->SetPortalState( areaPortal, PS_BLOCK_NONE );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdPortalState::Close
|
||
|
============
|
||
|
*/
|
||
|
void sdPortalState::Close( void ) {
|
||
|
if ( areaPortal == 0 ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
open = false;
|
||
|
gameRenderWorld->SetPortalState( areaPortal, PS_BLOCK_ALL );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===============================================================================
|
||
|
|
||
|
idSplinePath, holds a spline path to be used by an idMover
|
||
|
|
||
|
===============================================================================
|
||
|
*/
|
||
|
|
||
|
CLASS_DECLARATION( idEntity, idSplinePath )
|
||
|
END_CLASS
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idSplinePath::idSplinePath
|
||
|
================
|
||
|
*/
|
||
|
idSplinePath::idSplinePath() {
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idSplinePath::Spawn
|
||
|
================
|
||
|
*/
|
||
|
void idSplinePath::Spawn( void ) {
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===============================================================================
|
||
|
|
||
|
idMover_Binary
|
||
|
|
||
|
Doors, plats, and buttons are all binary (two position) movers
|
||
|
Pos1 is "at rest", pos2 is "activated"
|
||
|
|
||
|
===============================================================================
|
||
|
*/
|
||
|
|
||
|
extern const idEventDef EV_SetToggle;
|
||
|
extern const idEventDef EV_Disable;
|
||
|
extern const idEventDef EV_Enable;
|
||
|
|
||
|
const idEventDefInternal EV_MatchTeam( "internal_matchteam", "dd" );
|
||
|
const idEventDef EV_Enable( "enable", '\0', DOC_TEXT( "Enables an entity, allowing it to be used by the player." ), 0, "See also $event:disable$." );
|
||
|
const idEventDef EV_Disable( "disable", '\0', DOC_TEXT( "Disables an entity, making it unusable by the player." ), 0, "See also $event:enable$." );
|
||
|
const idEventDef EV_GetMoveMaster( "getMoveMaster", 'e', DOC_TEXT( "Returns the master of the mover team." ), 0, NULL );
|
||
|
const idEventDef EV_GetNextSlave( "getNextSlave", 'e', DOC_TEXT( "Returns the next entity in the mover team." ), 0, NULL );
|
||
|
const idEventDef EV_SetToggle( "setToggle", '\0', DOC_TEXT( "Sets the toggle state for the entity. If toggle mode is enabled, the entity will toggle between the two states, rather than returning to the initial state after a period of time." ), 1, NULL, "b", "toggle", "Set toggle on or off" );
|
||
|
|
||
|
CLASS_DECLARATION( sdScriptEntity, idMover_Binary )
|
||
|
EVENT( EV_Activate, idMover_Binary::Event_Use_BinaryMover )
|
||
|
EVENT( EV_MatchTeam, idMover_Binary::Event_MatchActivateTeam )
|
||
|
EVENT( EV_Enable, idMover_Binary::Event_Enable )
|
||
|
EVENT( EV_Disable, idMover_Binary::Event_Disable )
|
||
|
EVENT( EV_GetMoveMaster, idMover_Binary::Event_GetMoveMaster )
|
||
|
EVENT( EV_GetNextSlave, idMover_Binary::Event_GetNextSlave )
|
||
|
EVENT( EV_SetToggle, idMover_Binary::Event_SetToggle )
|
||
|
END_CLASS
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdMoverBinaryBroadcastState::MakeDefault
|
||
|
================
|
||
|
*/
|
||
|
void sdMoverBinaryBroadcastState::MakeDefault( void ) {
|
||
|
sdScriptEntityBroadcastData::MakeDefault();
|
||
|
|
||
|
closeTime = 0;
|
||
|
hidden = false;
|
||
|
toggle = false;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdMoverBinaryBroadcastState::Write
|
||
|
================
|
||
|
*/
|
||
|
void sdMoverBinaryBroadcastState::Write( idFile* file ) const {
|
||
|
sdScriptEntityBroadcastData::Write( file );
|
||
|
|
||
|
file->WriteInt( closeTime );
|
||
|
file->WriteBool( hidden );
|
||
|
file->WriteBool( toggle );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdMoverBinaryBroadcastState::Read
|
||
|
================
|
||
|
*/
|
||
|
void sdMoverBinaryBroadcastState::Read( idFile* file ) {
|
||
|
sdScriptEntityBroadcastData::Read( file );
|
||
|
|
||
|
file->ReadInt( closeTime );
|
||
|
file->ReadBool( hidden );
|
||
|
file->ReadBool( toggle );
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::idMover_Binary()
|
||
|
================
|
||
|
*/
|
||
|
idMover_Binary::idMover_Binary( void ) {
|
||
|
pos1.Zero();
|
||
|
pos2.Zero();
|
||
|
moverState = MOVER_POS1;
|
||
|
moveMaster = NULL;
|
||
|
activateChain = NULL;
|
||
|
soundPos1 = 0;
|
||
|
sound1to2 = 0;
|
||
|
sound2to1 = 0;
|
||
|
soundPos2 = 0;
|
||
|
soundLoop = 0;
|
||
|
wait = 0.0f;
|
||
|
damage = 0.0f;
|
||
|
duration = 0;
|
||
|
accelTime = 0;
|
||
|
decelTime = 0;
|
||
|
activatedBy = this;
|
||
|
enabled = false;
|
||
|
toggle = false;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::~idMover_Binary
|
||
|
================
|
||
|
*/
|
||
|
idMover_Binary::~idMover_Binary() {
|
||
|
idMover_Binary* mover;
|
||
|
|
||
|
// if this is the mover master
|
||
|
if ( this == moveMaster ) {
|
||
|
// make the next mover in the chain the move master
|
||
|
for ( mover = moveMaster; mover; mover = mover->activateChain ) {
|
||
|
mover->moveMaster = this->activateChain;
|
||
|
}
|
||
|
} else {
|
||
|
// remove mover from the activate chain
|
||
|
for ( mover = moveMaster; mover; mover = mover->activateChain ) {
|
||
|
if ( mover->activateChain == this ) {
|
||
|
mover->activateChain = this->activateChain;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::Damage
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const sdDeclDamage* damageDecl, const float damageScale, trace_t* collision, bool forceKill ) {
|
||
|
if ( moveMaster != this ) {
|
||
|
moveMaster->Damage( inflictor, attacker, dir, damageDecl, damageScale, collision, forceKill );
|
||
|
} else {
|
||
|
sdScriptEntity::Damage( inflictor, attacker, dir, damageDecl, damageScale, collision, forceKill );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::Think
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::Think( void ) {
|
||
|
sdScriptEntity::Think();
|
||
|
|
||
|
if ( closeTime != -1 ) {
|
||
|
if ( gameLocal.time > closeTime ) {
|
||
|
MatchActivateTeam( MOVER_2TO1, gameLocal.time );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::Spawn
|
||
|
|
||
|
Base class for all movers.
|
||
|
|
||
|
"wait" wait before returning (3 default, -1 = never return)
|
||
|
"speed" movement speed
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::Spawn( void ) {
|
||
|
enabled = true;
|
||
|
|
||
|
closeTime = -1;
|
||
|
|
||
|
activateChain = NULL;
|
||
|
|
||
|
spawnArgs.GetFloat( "wait", "0", wait );
|
||
|
|
||
|
physicsObj.SetSelf( this );
|
||
|
physicsObj.SetClipModel( new idClipModel( GetPhysics()->GetClipModel() ), 1.0f );
|
||
|
physicsObj.SetOrigin( GetPhysics()->GetOrigin() );
|
||
|
physicsObj.SetAxis( GetPhysics()->GetAxis() );
|
||
|
physicsObj.SetClipMask( MASK_SOLID | CONTENTS_BODY | CONTENTS_SLIDEMOVER );
|
||
|
if ( !spawnArgs.GetBool( "solid", "1" ) ) {
|
||
|
physicsObj.SetContents( 0 );
|
||
|
}
|
||
|
if ( !spawnArgs.GetBool( "nopush" ) ) {
|
||
|
physicsObj.SetPusher( 0 );
|
||
|
}
|
||
|
toggle = spawnArgs.GetBool( "toggle" );
|
||
|
physicsObj.SetLinearExtrapolation( EXTRAPOLATION_NONE, 0, 0, GetPhysics()->GetOrigin(), vec3_origin, vec3_origin );
|
||
|
// physicsObj.SetAngularExtrapolation( EXTRAPOLATION_NONE, 0, 0, GetPhysics()->GetAxis().ToAngles(), ang_zero, ang_zero );
|
||
|
SetPhysics( &physicsObj );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::Event_GetMoveMaster
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::Event_GetMoveMaster( void ) {
|
||
|
sdProgram::ReturnEntity( moveMaster );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::Event_GetNextSlave
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::Event_GetNextSlave( void ) {
|
||
|
sdProgram::ReturnEntity( activateChain );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::Event_GotoPosition1
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::Event_GotoPosition1( void ) {
|
||
|
GotoPosition1();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::Event_GotoPosition2
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::Event_GotoPosition2( void ) {
|
||
|
GotoPosition2();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::Event_SetToggle
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::Event_SetToggle( bool toggle ) {
|
||
|
this->toggle = toggle;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::PostMapSpawn
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::PostMapSpawn( void ) {
|
||
|
sdScriptEntity::PostMapSpawn();
|
||
|
|
||
|
bool groupMaster = spawnArgs.GetBool( "groupmaster" );
|
||
|
|
||
|
moveMaster = NULL;
|
||
|
if ( !groupMaster ) {
|
||
|
const char* groupName = spawnArgs.GetString( "group" );
|
||
|
if ( *groupName ) {
|
||
|
sdInstanceCollector< idMover_Binary > instances( true );
|
||
|
|
||
|
for ( int i = 0; i < instances.Num(); i++ ) {
|
||
|
idMover_Binary* mover = instances[ i ];
|
||
|
const char* otherGroupName = mover->spawnArgs.GetString( "group" );
|
||
|
if ( !idStr::Icmp( groupName, otherGroupName ) && mover->spawnArgs.GetBool( "groupmaster" ) ) {
|
||
|
moveMaster = mover;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// create a physics team for the binary mover parts
|
||
|
if ( moveMaster ) {
|
||
|
JoinTeam( moveMaster );
|
||
|
JoinActivateTeam( moveMaster );
|
||
|
|
||
|
idBounds soundOrigin;
|
||
|
|
||
|
soundOrigin.Clear();
|
||
|
|
||
|
idMover_Binary* slave;
|
||
|
for ( slave = moveMaster; slave; slave = slave->activateChain ) {
|
||
|
soundOrigin += slave->GetPhysics()->GetAbsBounds();
|
||
|
}
|
||
|
moveMaster->refSound.origin = soundOrigin.GetCenter();
|
||
|
} else {
|
||
|
moveMaster = this;
|
||
|
OnMasterReady();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===============
|
||
|
idMover_Binary::GetMovedir
|
||
|
|
||
|
The editor only specifies a single value for angles (yaw),
|
||
|
but we have special constants to generate an up or down direction.
|
||
|
Angles will be cleared, because it is being used to represent a direction
|
||
|
instead of an orientation.
|
||
|
===============
|
||
|
*/
|
||
|
void idMover_Binary::GetMovedir( float angle, idVec3 &movedir ) {
|
||
|
if ( angle == -1 ) {
|
||
|
movedir.Set( 0, 0, 1 );
|
||
|
} else if ( angle == -2 ) {
|
||
|
movedir.Set( 0, 0, -1 );
|
||
|
} else {
|
||
|
movedir = idAngles( 0, angle, 0 ).ToForward();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===============
|
||
|
idMover_Binary::UpdateMoverSound
|
||
|
===============
|
||
|
*/
|
||
|
void idMover_Binary::UpdateMoverSound( moverState_t state ) {
|
||
|
if ( moveMaster == this ) {
|
||
|
switch( state ) {
|
||
|
case MOVER_POS1:
|
||
|
break;
|
||
|
case MOVER_POS2:
|
||
|
break;
|
||
|
case MOVER_1TO2:
|
||
|
StartSound( "snd_open", SND_DOOR, 0, NULL );
|
||
|
break;
|
||
|
case MOVER_2TO1:
|
||
|
StartSound( "snd_close", SND_DOOR, 0, NULL );
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===============
|
||
|
idMover_Binary::SetMoverState
|
||
|
===============
|
||
|
*/
|
||
|
void idMover_Binary::SetMoverState( moverState_t newstate, int time ) {
|
||
|
idVec3 delta;
|
||
|
|
||
|
moverState = newstate;
|
||
|
|
||
|
UpdateMoverSound( newstate );
|
||
|
|
||
|
switch( moverState ) {
|
||
|
case MOVER_POS1: {
|
||
|
physicsObj.SetLinearExtrapolation( EXTRAPOLATION_NONE, time, 0, pos1, vec3_origin, vec3_origin );
|
||
|
break;
|
||
|
}
|
||
|
case MOVER_POS2: {
|
||
|
physicsObj.SetLinearExtrapolation( EXTRAPOLATION_NONE, time, 0, pos2, vec3_origin, vec3_origin );
|
||
|
break;
|
||
|
}
|
||
|
case MOVER_1TO2: {
|
||
|
physicsObj.SetLinearExtrapolation( EXTRAPOLATION_LINEAR, time, duration, pos1, ( pos2 - pos1 ) * 1000.0f / duration, vec3_origin );
|
||
|
// if ( accelTime != 0 || decelTime != 0 ) {
|
||
|
// physicsObj.SetLinearInterpolation( time, accelTime, decelTime, duration, pos1, pos2 );
|
||
|
// } else {
|
||
|
// physicsObj.SetLinearInterpolation( 0, 0, 0, 0, pos1, pos2 );
|
||
|
// }
|
||
|
break;
|
||
|
}
|
||
|
case MOVER_2TO1: {
|
||
|
closeTime = -1;
|
||
|
physicsObj.SetLinearExtrapolation( EXTRAPOLATION_LINEAR, time, duration, pos2, ( pos1 - pos2 ) * 1000.0f / duration, vec3_origin );
|
||
|
// if ( accelTime != 0 || decelTime != 0 ) {
|
||
|
// physicsObj.SetLinearInterpolation( time, accelTime, decelTime, duration, pos2, pos1 );
|
||
|
// } else {
|
||
|
// physicsObj.SetLinearInterpolation( 0, 0, 0, 0, pos1, pos2 );
|
||
|
// }
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::OpenPortals
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::OpenPortals( void ) {
|
||
|
for ( idMover_Binary* slave = moveMaster; slave; slave = slave->GetActivateChain() ) {
|
||
|
slave->OpenPortal();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::ClosePortals
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::ClosePortals( bool force ) {
|
||
|
for ( idMover_Binary* slave = moveMaster; slave; slave = slave->GetActivateChain() ) {
|
||
|
if ( !force && slave->IsHidden() ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
slave->ClosePortal();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::MatchActivateTeam
|
||
|
|
||
|
All entities in a mover team will move from pos1 to pos2
|
||
|
in the same amount of time
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::MatchActivateTeam( moverState_t newstate, int time ) {
|
||
|
idMover_Binary *slave;
|
||
|
|
||
|
for ( slave = this; slave != NULL; slave = slave->activateChain ) {
|
||
|
slave->SetMoverState( newstate, time );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::Enable
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::Enable( bool b ) {
|
||
|
enabled = b;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::Event_MatchActivateTeam
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::Event_MatchActivateTeam( moverState_t newstate, int time ) {
|
||
|
MatchActivateTeam( newstate, time );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::BindTeam
|
||
|
|
||
|
All entities in a mover team will be bound
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::BindTeam( idEntity *bindTo ) {
|
||
|
idMover_Binary *slave;
|
||
|
|
||
|
for ( slave = this; slave != NULL; slave = slave->activateChain ) {
|
||
|
slave->Bind( bindTo, true );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::JoinActivateTeam
|
||
|
|
||
|
Set all entities in a mover team to be enabled
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::JoinActivateTeam( idMover_Binary *master ) {
|
||
|
this->activateChain = master->activateChain;
|
||
|
master->activateChain = this;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::Event_Enable
|
||
|
|
||
|
Set all entities in a mover team to be enabled
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::Event_Enable( void ) {
|
||
|
for ( idMover_Binary* slave = moveMaster; slave != NULL; slave = slave->activateChain ) {
|
||
|
slave->Enable( true );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::Event_Disable
|
||
|
|
||
|
Set all entities in a mover team to be disabled
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::Event_Disable( void ) {
|
||
|
for ( idMover_Binary* slave = moveMaster; slave != NULL; slave = slave->activateChain ) {
|
||
|
slave->Enable( false );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::Event_OpenPortal
|
||
|
|
||
|
Sets the portal associtated with this mover to be open
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::Event_OpenPortal( void ) {
|
||
|
for ( idMover_Binary* slave = moveMaster; slave != NULL; slave = slave->activateChain ) {
|
||
|
slave->OpenPortal();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::Event_ClosePortal
|
||
|
|
||
|
Sets the portal associtated with this mover to be closed
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::Event_ClosePortal( void ) {
|
||
|
for ( idMover_Binary* slave = moveMaster; slave != NULL; slave = slave->activateChain ) {
|
||
|
if ( slave->IsHidden() ) {
|
||
|
continue;
|
||
|
}
|
||
|
slave->ClosePortal();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::ReachedPosition
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::ReachedPosition( void ) {
|
||
|
|
||
|
if ( moverState == MOVER_1TO2 ) {
|
||
|
// reached pos2
|
||
|
if ( moveMaster == this ) {
|
||
|
StartSound( "snd_opened", SND_DOOR, 0, NULL );
|
||
|
}
|
||
|
|
||
|
SetMoverState( MOVER_POS2, gameLocal.time );
|
||
|
|
||
|
if ( enabled && wait >= 0 && !toggle ) {
|
||
|
closeTime = gameLocal.time + SEC2MS( wait );
|
||
|
}
|
||
|
} else if ( moverState == MOVER_2TO1 ) {
|
||
|
// reached pos1
|
||
|
if ( moveMaster == this ) {
|
||
|
StartSound( "snd_closed", SND_DOOR, 0, NULL );
|
||
|
}
|
||
|
|
||
|
SetMoverState( MOVER_POS1, gameLocal.time );
|
||
|
|
||
|
// close areaportals
|
||
|
if ( moveMaster == this ) {
|
||
|
ClosePortals( false );
|
||
|
}
|
||
|
|
||
|
if ( enabled && wait >= 0 && spawnArgs.GetBool( "continuous" ) ) {
|
||
|
PostEventSec( &EV_Activate, wait, this );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::GotoPosition1
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::GotoPosition1( void ) {
|
||
|
idMover_Binary *slave;
|
||
|
int partial;
|
||
|
|
||
|
// only the master should control this
|
||
|
if ( moveMaster != this ) {
|
||
|
moveMaster->GotoPosition1();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( ( moverState == MOVER_POS1 ) || ( moverState == MOVER_2TO1 ) ) {
|
||
|
// already there, or on the way
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( moverState == MOVER_POS2 ) {
|
||
|
for ( slave = this; slave != NULL; slave = slave->activateChain ) {
|
||
|
slave->closeTime = -1;
|
||
|
if ( !toggle ) {
|
||
|
slave->closeTime = gameLocal.time;
|
||
|
}
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// 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();
|
||
|
assert( partial >= 0 );
|
||
|
if ( partial < 0 ) {
|
||
|
partial = 0;
|
||
|
}
|
||
|
MatchActivateTeam( MOVER_2TO1, physicsObj.GetTime() - partial );
|
||
|
// if already at at position 1 (partial == duration) execute the reached event
|
||
|
if ( partial >= duration ) {
|
||
|
ReachedPosition();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::GotoPosition2
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::GotoPosition2( void ) {
|
||
|
int partial;
|
||
|
|
||
|
// only the master should control this
|
||
|
if ( moveMaster != this ) {
|
||
|
moveMaster->GotoPosition2();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( ( moverState == MOVER_POS2 ) || ( moverState == MOVER_1TO2 ) ) {
|
||
|
// already there, or on the way
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( moverState == MOVER_POS1 ) {
|
||
|
MatchActivateTeam( MOVER_1TO2, gameLocal.time );
|
||
|
|
||
|
// open areaportal
|
||
|
OpenPortals();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
// only partway up before reversing
|
||
|
if ( moverState == MOVER_2TO1 ) {
|
||
|
// use the physics times because this might be executed during the physics simulation
|
||
|
partial = physicsObj.GetLinearEndTime() - physicsObj.GetTime();
|
||
|
assert( partial >= 0 );
|
||
|
if ( partial < 0 ) {
|
||
|
partial = 0;
|
||
|
}
|
||
|
MatchActivateTeam( MOVER_1TO2, physicsObj.GetTime() - partial );
|
||
|
// if already at at position 2 (partial == duration) execute the reached event
|
||
|
if ( partial >= duration ) {
|
||
|
ReachedPosition();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::Use_BinaryMover
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::Use_BinaryMover( idEntity *activator ) {
|
||
|
// only the master should be used
|
||
|
if ( moveMaster != this ) {
|
||
|
moveMaster->Use_BinaryMover( activator );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( !enabled ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
activatedBy = activator;
|
||
|
|
||
|
if ( moverState == MOVER_POS1 ) {
|
||
|
MatchActivateTeam( MOVER_1TO2, gameLocal.time + gameLocal.msec );
|
||
|
|
||
|
// open areaportal
|
||
|
OpenPortals();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// if all the way up, just delay before coming down
|
||
|
if ( moverState == MOVER_POS2 ) {
|
||
|
idMover_Binary *slave;
|
||
|
|
||
|
if ( wait == -1 ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for ( slave = this; slave != NULL; slave = slave->activateChain ) {
|
||
|
if ( toggle ) {
|
||
|
slave->closeTime = gameLocal.time;
|
||
|
} else {
|
||
|
slave->closeTime = gameLocal.time + SEC2MS( wait );
|
||
|
}
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// only partway down before reversing
|
||
|
if ( moverState == MOVER_2TO1 ) {
|
||
|
GotoPosition2();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// only partway up before reversing
|
||
|
if ( moverState == MOVER_1TO2 ) {
|
||
|
GotoPosition1();
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::Event_Use_BinaryMover
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::Event_Use_BinaryMover( idEntity *activator ) {
|
||
|
Use_BinaryMover( activator );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::PreBind
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::PreBind( void ) {
|
||
|
pos1 = GetWorldCoordinates( pos1 );
|
||
|
pos2 = GetWorldCoordinates( pos2 );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::PostBind
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::PostBind( void ) {
|
||
|
pos1 = GetLocalCoordinates( pos1 );
|
||
|
pos2 = GetLocalCoordinates( pos2 );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::InitSpeed
|
||
|
|
||
|
pos1, pos2, and speed are passed in so the movement delta can be calculated
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::InitSpeed( idVec3 &mpos1, idVec3 &mpos2, float mspeed, float maccelTime, float mdecelTime ) {
|
||
|
idVec3 move;
|
||
|
float distance;
|
||
|
float speed;
|
||
|
|
||
|
pos1 = mpos1;
|
||
|
pos2 = mpos2;
|
||
|
|
||
|
accelTime = idPhysics::SnapTimeToPhysicsFrame( SEC2MS( maccelTime ) );
|
||
|
decelTime = idPhysics::SnapTimeToPhysicsFrame( SEC2MS( mdecelTime ) );
|
||
|
|
||
|
speed = mspeed ? mspeed : 100;
|
||
|
|
||
|
// calculate time to reach second position from speed
|
||
|
move = pos2 - pos1;
|
||
|
distance = move.Length();
|
||
|
duration = idPhysics::SnapTimeToPhysicsFrame( distance * 1000 / speed );
|
||
|
if ( duration <= 0 ) {
|
||
|
duration = 1;
|
||
|
}
|
||
|
|
||
|
moverState = MOVER_POS1;
|
||
|
|
||
|
physicsObj.SetLinearExtrapolation( EXTRAPOLATION_NONE, 0, 0, pos1, vec3_origin, vec3_origin );
|
||
|
// physicsObj.SetLinearInterpolation( 0, 0, 0, 0, vec3_origin, vec3_origin );
|
||
|
SetOrigin( pos1 );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::InitTime
|
||
|
|
||
|
pos1, pos2, and time are passed in so the movement delta can be calculated
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::InitTime( idVec3 &mpos1, idVec3 &mpos2, float mtime, float maccelTime, float mdecelTime ) {
|
||
|
|
||
|
pos1 = mpos1;
|
||
|
pos2 = mpos2;
|
||
|
|
||
|
accelTime = idPhysics::SnapTimeToPhysicsFrame( SEC2MS( maccelTime ) );
|
||
|
decelTime = idPhysics::SnapTimeToPhysicsFrame( SEC2MS( mdecelTime ) );
|
||
|
|
||
|
duration = idPhysics::SnapTimeToPhysicsFrame( SEC2MS( mtime ) );
|
||
|
if ( duration <= 0 ) {
|
||
|
duration = 1;
|
||
|
}
|
||
|
|
||
|
moverState = MOVER_POS1;
|
||
|
|
||
|
physicsObj.SetLinearExtrapolation( EXTRAPOLATION_NONE, 0, 0, pos1, vec3_origin, vec3_origin );
|
||
|
// physicsObj.SetLinearInterpolation( 0, 0, 0, 0, vec3_origin, vec3_origin );
|
||
|
SetOrigin( pos1 );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::GetActivator
|
||
|
================
|
||
|
*/
|
||
|
idEntity *idMover_Binary::GetActivator( void ) const {
|
||
|
return activatedBy.GetEntity();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::CheckNetworkStateChanges
|
||
|
================
|
||
|
*/
|
||
|
bool idMover_Binary::CheckNetworkStateChanges( networkStateMode_t mode, const sdEntityStateNetworkData& baseState ) const {
|
||
|
if ( mode == NSM_BROADCAST ) {
|
||
|
NET_GET_BASE( sdMoverBinaryBroadcastState );
|
||
|
|
||
|
if ( baseData.closeTime != closeTime ) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if ( baseData.hidden != fl.hidden ) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if ( baseData.toggle != toggle ) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return sdScriptEntity::CheckNetworkStateChanges( mode, baseState );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::WriteNetworkState
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::WriteNetworkState( networkStateMode_t mode, const sdEntityStateNetworkData& baseState, sdEntityStateNetworkData& newState, idBitMsg& msg ) const {
|
||
|
if ( mode == NSM_BROADCAST ) {
|
||
|
NET_GET_STATES( sdMoverBinaryBroadcastState );
|
||
|
|
||
|
// update state
|
||
|
newData.closeTime = closeTime;
|
||
|
newData.hidden = fl.hidden;
|
||
|
newData.toggle = toggle;
|
||
|
|
||
|
// write state
|
||
|
msg.WriteDeltaLong( baseData.closeTime, newData.closeTime );
|
||
|
msg.WriteBool( newData.hidden );
|
||
|
msg.WriteBool( newData.toggle );
|
||
|
}
|
||
|
|
||
|
sdScriptEntity::WriteNetworkState( mode, baseState, newState, msg );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::ApplyNetworkState
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::ApplyNetworkState( networkStateMode_t mode, const sdEntityStateNetworkData& newState ) {
|
||
|
if ( mode == NSM_BROADCAST ) {
|
||
|
NET_GET_NEW( sdMoverBinaryBroadcastState );
|
||
|
|
||
|
// update state
|
||
|
closeTime = newData.closeTime;
|
||
|
toggle = newData.toggle;
|
||
|
if ( newData.hidden ) {
|
||
|
Hide();
|
||
|
} else {
|
||
|
Show();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sdScriptEntity::ApplyNetworkState( mode, newState );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::ReadNetworkState
|
||
|
================
|
||
|
*/
|
||
|
void idMover_Binary::ReadNetworkState( networkStateMode_t mode, const sdEntityStateNetworkData& baseState, sdEntityStateNetworkData& newState, const idBitMsg& msg ) const {
|
||
|
if ( mode == NSM_BROADCAST ) {
|
||
|
NET_GET_STATES( sdMoverBinaryBroadcastState );
|
||
|
|
||
|
// read state
|
||
|
newData.closeTime = msg.ReadDeltaLong( baseData.closeTime );
|
||
|
newData.hidden = msg.ReadBool();
|
||
|
newData.toggle = msg.ReadBool();
|
||
|
}
|
||
|
|
||
|
sdScriptEntity::ReadNetworkState( mode, baseState, newState, msg );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idMover_Binary::CreateNetworkStructure
|
||
|
================
|
||
|
*/
|
||
|
sdEntityStateNetworkData* idMover_Binary::CreateNetworkStructure( networkStateMode_t mode ) const {
|
||
|
if ( mode == NSM_BROADCAST ) {
|
||
|
return new sdMoverBinaryBroadcastState();
|
||
|
}
|
||
|
|
||
|
return sdScriptEntity::CreateNetworkStructure( mode );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===============================================================================
|
||
|
|
||
|
idPlat
|
||
|
|
||
|
===============================================================================
|
||
|
*/
|
||
|
|
||
|
CLASS_DECLARATION( idMover_Binary, idPlat )
|
||
|
END_CLASS
|
||
|
|
||
|
/*
|
||
|
===============
|
||
|
idPlat::idPlat
|
||
|
===============
|
||
|
*/
|
||
|
idPlat::idPlat( void ) {
|
||
|
trigger = NULL;
|
||
|
localTriggerOrigin.Zero();
|
||
|
localTriggerAxis.Identity();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===============
|
||
|
idPlat::~idPlat
|
||
|
===============
|
||
|
*/
|
||
|
idPlat::~idPlat( void ) {
|
||
|
gameLocal.clip.DeleteClipModel( trigger );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===============
|
||
|
idPlat::Spawn
|
||
|
===============
|
||
|
*/
|
||
|
void idPlat::Spawn( void ) {
|
||
|
float lip;
|
||
|
float height;
|
||
|
float time;
|
||
|
float speed;
|
||
|
float accel;
|
||
|
float decel;
|
||
|
bool noTouch;
|
||
|
|
||
|
spawnArgs.GetFloat( "speed", "100", speed );
|
||
|
spawnArgs.GetFloat( "damage", "0", damage );
|
||
|
spawnArgs.GetFloat( "wait", "1", wait );
|
||
|
spawnArgs.GetFloat( "lip", "8", lip );
|
||
|
spawnArgs.GetFloat( "accel_time", "0.25", accel );
|
||
|
spawnArgs.GetFloat( "decel_time", "0.25", decel );
|
||
|
|
||
|
// create second position
|
||
|
if ( !spawnArgs.GetFloat( "height", "0", height ) ) {
|
||
|
height = ( GetPhysics()->GetBounds()[1][2] - GetPhysics()->GetBounds()[0][2] ) - lip;
|
||
|
}
|
||
|
|
||
|
spawnArgs.GetBool( "no_touch", "0", noTouch );
|
||
|
|
||
|
pos1 = GetPhysics()->GetOrigin();
|
||
|
pos2 = pos1;
|
||
|
pos2[2] += height;
|
||
|
|
||
|
if ( spawnArgs.GetFloat( "time", "1", time ) ) {
|
||
|
InitTime( pos1, pos2, time, accel, decel );
|
||
|
} else {
|
||
|
InitSpeed( pos1, pos2, speed, accel, decel );
|
||
|
}
|
||
|
|
||
|
SetMoverState( MOVER_POS1, gameLocal.time );
|
||
|
UpdateVisuals();
|
||
|
|
||
|
// spawn the trigger if one hasn't been custom made
|
||
|
if ( !noTouch ) {
|
||
|
// spawn trigger
|
||
|
SpawnPlatTrigger( pos1 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idPlat::Think
|
||
|
================
|
||
|
*/
|
||
|
void idPlat::Think( void ) {
|
||
|
idMover_Binary::Think();
|
||
|
|
||
|
RunPhysics();
|
||
|
|
||
|
const idVec3& org = physicsObj.GetOrigin();
|
||
|
|
||
|
// update trigger position
|
||
|
if ( trigger ) {
|
||
|
trigger->Link( gameLocal.clip, this, 0, org, mat3_identity );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idPlat::PreBind
|
||
|
================
|
||
|
*/
|
||
|
void idPlat::PreBind( void ) {
|
||
|
idMover_Binary::PreBind();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idPlat::PostBind
|
||
|
================
|
||
|
*/
|
||
|
void idPlat::PostBind( void ) {
|
||
|
idMover_Binary::PostBind();
|
||
|
GetLocalTriggerPosition( trigger );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idPlat::GetLocalTriggerPosition
|
||
|
================
|
||
|
*/
|
||
|
void idPlat::GetLocalTriggerPosition( const idClipModel *trigger ) {
|
||
|
idVec3 origin;
|
||
|
idMat3 axis;
|
||
|
|
||
|
if ( !trigger ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
GetMasterPosition( origin, axis );
|
||
|
localTriggerOrigin = ( trigger->GetOrigin() - origin ) * axis.Transpose();
|
||
|
localTriggerAxis = trigger->GetAxis() * axis.Transpose();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
==============
|
||
|
idPlat::SpawnPlatTrigger
|
||
|
===============
|
||
|
*/
|
||
|
void idPlat::SpawnPlatTrigger( idVec3 &pos ) {
|
||
|
idBounds bounds;
|
||
|
idVec3 tmin;
|
||
|
idVec3 tmax;
|
||
|
|
||
|
// the middle trigger will be a thin trigger just
|
||
|
// above the starting position
|
||
|
|
||
|
bounds = GetPhysics()->GetBounds();
|
||
|
|
||
|
tmin[0] = bounds[0][0] + 33;
|
||
|
tmin[1] = bounds[0][1] + 33;
|
||
|
tmin[2] = bounds[0][2];
|
||
|
|
||
|
tmax[0] = bounds[1][0] - 33;
|
||
|
tmax[1] = bounds[1][1] - 33;
|
||
|
tmax[2] = bounds[1][2] + 8;
|
||
|
|
||
|
if ( tmax[0] <= tmin[0] ) {
|
||
|
tmin[0] = ( bounds[0][0] + bounds[1][0] ) * 0.5f;
|
||
|
tmax[0] = tmin[0] + 1;
|
||
|
}
|
||
|
if ( tmax[1] <= tmin[1] ) {
|
||
|
tmin[1] = ( bounds[0][1] + bounds[1][1] ) * 0.5f;
|
||
|
tmax[1] = tmin[1] + 1;
|
||
|
}
|
||
|
|
||
|
trigger = new idClipModel( idTraceModel( idBounds( tmin, tmax ) ), true );
|
||
|
trigger->Link( gameLocal.clip, this, 255, GetPhysics()->GetOrigin(), mat3_identity );
|
||
|
trigger->SetContents( CONTENTS_TRIGGER );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
==============
|
||
|
idPlat::OnTouch
|
||
|
===============
|
||
|
*/
|
||
|
void idPlat::OnTouch( idEntity *other, const trace_t& trace ) {
|
||
|
idPlayer* player = other->Cast< idPlayer >();
|
||
|
if ( !player ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( player->GetHealth() <= 0 ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( ( GetMoverState() == MOVER_POS1 ) && trigger && ( trace.c.id == trigger->GetId() ) ) {
|
||
|
Use_BinaryMover( other );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idPlat::OnTeamBlocked
|
||
|
================
|
||
|
*/
|
||
|
void idPlat::OnTeamBlocked( idEntity *blockedEntity, idEntity *blockingEntity ) {
|
||
|
// reverse direction
|
||
|
Use_BinaryMover( activatedBy.GetEntity() );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===============
|
||
|
idPlat::OnPartBlocked
|
||
|
===============
|
||
|
*/
|
||
|
void idPlat::OnPartBlocked( idEntity *blockingEntity ) {
|
||
|
if ( damage > 0.0f ) {
|
||
|
blockingEntity->Damage( this, this, vec3_origin, DAMAGE_FOR_NAME( "damage_moverCrush" ), damage, NULL );
|
||
|
}
|
||
|
}
|