etqw-sdk/source/game/Mover.cpp

1214 lines
28 KiB
C++
Raw Normal View History

2008-05-29 00:00:00 +00:00
// 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 );
}
}