2016-03-27 11:49:47 +02:00
|
|
|
/*
|
|
|
|
===========================================================================
|
|
|
|
Copyright (C) 2015 the OpenMoHAA team
|
|
|
|
|
|
|
|
This file is part of OpenMoHAA source code.
|
|
|
|
|
|
|
|
OpenMoHAA source code is free software; you can redistribute it
|
|
|
|
and/or modify it under the terms of the GNU General Public License as
|
|
|
|
published by the Free Software Foundation; either version 2 of the License,
|
|
|
|
or (at your option) any later version.
|
|
|
|
|
|
|
|
OpenMoHAA source code is distributed in the hope that it will be
|
|
|
|
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with OpenMoHAA source code; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
===========================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
// specialfx.cpp: Special fx
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "g_local.h"
|
2023-04-29 21:56:38 +02:00
|
|
|
#include "g_phys.h"
|
|
|
|
#include "g_spawn.h"
|
2016-03-27 11:49:47 +02:00
|
|
|
#include "specialfx.h"
|
2023-01-29 20:59:31 +01:00
|
|
|
#include "level.h"
|
2016-03-27 11:49:47 +02:00
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
/*QUAKED func_fulcrum (0 0 1) ? X_AXIS_ONLY Y_AXIS_ONLY
|
|
|
|
|
|
|
|
This creates a fulcrum that when you stand on it, it will rotate due to
|
|
|
|
the weight exerted it will start rotating, when not standing on it, it
|
|
|
|
will return to its rest position.
|
|
|
|
"speed" - set the speed at which the fulcrum will operate (default is 48)
|
|
|
|
"resetspeed" - speed at whcih fulcrum resets, (default speed * 0.002)
|
|
|
|
"dampening" - dampen constant (default 0.95)
|
|
|
|
"limit" - limit the movement of the fulcrum (default 90 degrees)
|
|
|
|
"movesound" - sound to be played while fulcrum is moving
|
|
|
|
|
|
|
|
X_AXIS_ONLY - only adjust the X axis
|
|
|
|
Y_AXIS_ONLY - only adjust the Y axis
|
|
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
#define X_AXIS_ONLY ( 1 << 0 )
|
|
|
|
#define Y_AXIS_ONLY ( 1 << 1 )
|
|
|
|
|
|
|
|
Event EV_Fulcrum_SetSpeed
|
|
|
|
(
|
|
|
|
"speed",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"speed",
|
|
|
|
"Speed at which fulcrum operates itself.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_Fulcrum_Reset
|
|
|
|
(
|
|
|
|
"reset",
|
|
|
|
EV_CONSOLE,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Reset the fulcrum right now.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_Fulcrum_AdjustFulcrum
|
|
|
|
(
|
|
|
|
"_adjust_fulcrum",
|
|
|
|
EV_CODEONLY,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Called periodically to adjust the frustum every frame and update its angular velocity.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_Fulcrum_SetResetSpeed
|
|
|
|
(
|
|
|
|
"resetspeed",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"newResetspeed",
|
|
|
|
"Speed at which fulcrum resets itself, defaults to 0.002 * speed.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_Fulcrum_SetDampening
|
|
|
|
(
|
|
|
|
"dampening",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"newDampening",
|
|
|
|
"dampening of fulcrum.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_Fulcrum_SetLimit
|
|
|
|
(
|
|
|
|
"limit",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"newLimit",
|
|
|
|
"angular limit for the fulcrum.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_Fulcrum_Setup
|
|
|
|
(
|
|
|
|
"_setup",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"setup the fulcrum for the first time.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_Fulcrum_SetMoveSound
|
|
|
|
(
|
|
|
|
"movesound",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"newSinkSound",
|
|
|
|
"Sound played when fulcrum is moving.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
CLASS_DECLARATION( ScriptSlave, Fulcrum, "func_fulcrum" )
|
|
|
|
{
|
|
|
|
{ &EV_Fulcrum_SetSpeed, &Fulcrum::SetSpeed },
|
|
|
|
{ &EV_Fulcrum_Reset, &Fulcrum::Reset },
|
|
|
|
{ &EV_Fulcrum_AdjustFulcrum, &Fulcrum::Adjust },
|
|
|
|
{ &EV_Touch, &Fulcrum::Touched },
|
|
|
|
{ &EV_Fulcrum_SetResetSpeed, &Fulcrum::SetResetSpeed },
|
|
|
|
{ &EV_Fulcrum_SetDampening, &Fulcrum::SetDampening },
|
|
|
|
{ &EV_Fulcrum_SetLimit, &Fulcrum::SetLimit },
|
|
|
|
{ &EV_Fulcrum_Setup, &Fulcrum::Setup },
|
|
|
|
{ &EV_Fulcrum_SetMoveSound, &Fulcrum::SetMoveSound },
|
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
Fulcrum::Fulcrum()
|
|
|
|
{
|
|
|
|
if ( LoadingSavegame )
|
|
|
|
{
|
|
|
|
// Archive function will setup all necessary data
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
touched = qfalse;
|
|
|
|
speed = 48;
|
|
|
|
resetspeed = speed * 0.002;
|
|
|
|
dampening = 0.95f;
|
|
|
|
limit = 90;
|
|
|
|
setMoveType( MOVETYPE_PUSH );
|
|
|
|
PostEvent( EV_Fulcrum_Setup, FRAMETIME );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Fulcrum::Setup
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
startangles = angles;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Fulcrum::SetSpeed
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
speed = ev->GetFloat( 1 );
|
|
|
|
resetspeed = speed * 0.002;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Fulcrum::SetResetSpeed
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
resetspeed = ev->GetFloat( 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Fulcrum::SetDampening
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
dampening = ev->GetFloat( 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Fulcrum::SetLimit
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
limit = ev->GetFloat( 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Fulcrum::SetMoveSound
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
movesound = ev->GetString( 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Fulcrum::Reset
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
StopLoopSound();
|
|
|
|
touched = qfalse;
|
|
|
|
avelocity = vec_zero;
|
|
|
|
setAngles( startangles );
|
|
|
|
CancelEventsOfType( EV_Fulcrum_AdjustFulcrum );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Fulcrum::Touched
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
Vector diff;
|
|
|
|
vec3_t dest;
|
|
|
|
Vector delta;
|
|
|
|
Entity * other;
|
|
|
|
|
|
|
|
other = ev->GetEntity( 1 );
|
|
|
|
|
|
|
|
assert( other );
|
|
|
|
if ( !other )
|
|
|
|
return;
|
|
|
|
|
|
|
|
//
|
|
|
|
// only things resting on me will affect me
|
|
|
|
//
|
|
|
|
if ( other->groundentity != this->edict )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( movesound.length() )
|
|
|
|
{
|
|
|
|
LoopSound( movesound );
|
|
|
|
}
|
|
|
|
|
|
|
|
delta = getLocalVector( other->origin - origin );
|
|
|
|
|
|
|
|
//
|
|
|
|
// clear out angular velocity
|
|
|
|
//
|
|
|
|
avelocity = vec_zero;
|
|
|
|
|
|
|
|
// only look at x and y since z doesn't really concern us.
|
|
|
|
if ( !( spawnflags & X_AXIS_ONLY ) )
|
|
|
|
{
|
|
|
|
avelocity[ PITCH ] += cos( DEG2RAD( startangles[ YAW ] ) ) * speed * delta[ 0 ] / maxs[ 0 ];
|
|
|
|
avelocity[ ROLL ] += sin( DEG2RAD( startangles[ YAW ] ) ) * speed * delta[ 0 ] / maxs[ 0 ];
|
|
|
|
}
|
|
|
|
if ( !( spawnflags & Y_AXIS_ONLY ) )
|
|
|
|
{
|
|
|
|
avelocity[ ROLL ] += cos( DEG2RAD( startangles[ YAW ] ) ) * -speed * delta[ 1 ] / maxs[ 1 ];
|
|
|
|
avelocity[ PITCH ] += sin( DEG2RAD( startangles[ YAW ] ) ) * -speed * delta[ 1 ] / maxs[ 1 ];
|
|
|
|
}
|
|
|
|
|
|
|
|
AnglesSubtract( startangles, angles, dest );
|
|
|
|
diff = Vector( dest );
|
|
|
|
if ( fabs( diff[ PITCH ] ) >= limit )
|
|
|
|
{
|
|
|
|
Vector newAngles;
|
|
|
|
StopLoopSound();
|
|
|
|
if ( diff[ PITCH ] > 0 )
|
|
|
|
{
|
|
|
|
if ( avelocity[ PITCH ] < 0 )
|
|
|
|
{
|
|
|
|
avelocity[ PITCH ] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( diff[ PITCH ] < 0 )
|
|
|
|
{
|
|
|
|
if ( avelocity[ PITCH ] > 0 )
|
|
|
|
{
|
|
|
|
avelocity[ PITCH ] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( fabs( diff[ ROLL ] ) >= limit )
|
|
|
|
{
|
|
|
|
StopLoopSound();
|
|
|
|
if ( diff[ ROLL ] > 0 )
|
|
|
|
{
|
|
|
|
if ( avelocity[ ROLL ] < 0 )
|
|
|
|
{
|
|
|
|
avelocity[ ROLL ] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( diff[ ROLL ] < 0 )
|
|
|
|
{
|
|
|
|
if ( avelocity[ ROLL ] > 0 )
|
|
|
|
{
|
|
|
|
avelocity[ ROLL ] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
touched = qtrue;
|
|
|
|
CancelEventsOfType( EV_Fulcrum_AdjustFulcrum );
|
|
|
|
PostEvent( EV_Fulcrum_AdjustFulcrum, 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Fulcrum::Adjust
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
if ( !touched )
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
float f;
|
|
|
|
Vector diff;
|
|
|
|
vec3_t dest;
|
|
|
|
qboolean post;
|
|
|
|
|
|
|
|
if ( movesound.length() )
|
|
|
|
{
|
|
|
|
LoopSound( movesound );
|
|
|
|
}
|
|
|
|
AnglesSubtract( startangles, angles, dest );
|
|
|
|
diff = Vector( dest );
|
|
|
|
post = qfalse;
|
|
|
|
|
|
|
|
for( i = 0; i < 3; i++ )
|
|
|
|
{
|
|
|
|
if ( diff[ i ] )
|
|
|
|
{
|
|
|
|
avelocity[ i ] += resetspeed * diff[ i ];
|
|
|
|
}
|
|
|
|
avelocity[ i ] *= dampening;
|
|
|
|
f = fabs( avelocity[ i ] );
|
|
|
|
if ( f > 0.01f )
|
|
|
|
{
|
|
|
|
post = qtrue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( !post )
|
|
|
|
{
|
|
|
|
Reset( NULL );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
touched = qfalse;
|
|
|
|
}
|
|
|
|
|
|
|
|
PostEvent( EV_Fulcrum_AdjustFulcrum, FRAMETIME );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
/*QUAKED func_runthrough (0 0 1) ?
|
|
|
|
|
|
|
|
This is a trigger field that the player can run through and spawn tiki models
|
|
|
|
at that position. Used for releasing chaff from grass or butterflys from
|
|
|
|
flower gardens
|
|
|
|
"speed" - speed at which you have to be moving to trigger ( default 100 )
|
|
|
|
"delay" - time between triggering ( default 0.1 )
|
|
|
|
"chance" - chance that the trigger will spawn something( default 0.5 )
|
|
|
|
"lip" - how far below the surface of the trigger we should spawn these things ( default 3 )
|
|
|
|
"offset" - vector offset oriented along velocity vector( default "0 0 0" )
|
|
|
|
"spawnmodel" - thing to spawn when triggered
|
|
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
Event EV_RunThrough_SetSpeed
|
|
|
|
(
|
|
|
|
"speed",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"speed",
|
|
|
|
"threshold speed at which RunThrough is activated.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_RunThrough_SetDelay
|
|
|
|
(
|
|
|
|
"delay",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"delay",
|
|
|
|
"time between RunThrough being activated.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_RunThrough_SetChance
|
|
|
|
(
|
|
|
|
"chance",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"chance",
|
|
|
|
"chance that trigger will spawn something.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_RunThrough_SetLip
|
|
|
|
(
|
|
|
|
"lip",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"lip",
|
|
|
|
"distance below trigger we should spawn things.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_RunThrough_SetSpawnModel
|
|
|
|
(
|
|
|
|
"spawnmodel",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"model_to_spawn",
|
|
|
|
"When triggered, what to spawn.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_RunThrough_SetOffset
|
|
|
|
(
|
|
|
|
"offset",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"v",
|
|
|
|
"spawn_offset",
|
|
|
|
"When triggered, what to offset the spawned object by.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
CLASS_DECLARATION( Entity, RunThrough, "func_runthrough" )
|
|
|
|
{
|
|
|
|
{ &EV_RunThrough_SetSpeed, &RunThrough::SetSpeed },
|
|
|
|
{ &EV_RunThrough_SetDelay, &RunThrough::SetDelay },
|
|
|
|
{ &EV_RunThrough_SetChance, &RunThrough::SetChance },
|
|
|
|
{ &EV_RunThrough_SetLip, &RunThrough::SetLip },
|
|
|
|
{ &EV_RunThrough_SetSpawnModel, &RunThrough::SetSpawnModel },
|
|
|
|
{ &EV_RunThrough_SetOffset, &RunThrough::SetOffset },
|
|
|
|
{ &EV_Touch, &RunThrough::Touched },
|
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
RunThrough::RunThrough()
|
|
|
|
{
|
|
|
|
if ( LoadingSavegame )
|
|
|
|
{
|
|
|
|
// Archive function will setup all necessary data
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
offset = vec_zero;
|
|
|
|
speed = 100.0f;
|
|
|
|
chance = 0.5f;
|
|
|
|
delay = 0.1f;
|
|
|
|
lip = 3.0f;
|
|
|
|
spawnmodel = "";
|
|
|
|
lasttriggertime = 0;
|
|
|
|
setMoveType( MOVETYPE_NONE );
|
|
|
|
setSolidType( SOLID_TRIGGER );
|
|
|
|
}
|
|
|
|
|
|
|
|
void RunThrough::SetSpeed
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
speed = ev->GetFloat( 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void RunThrough::SetChance
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
chance = ev->GetFloat( 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void RunThrough::SetDelay
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
delay = ev->GetFloat( 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void RunThrough::SetLip
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
lip = ev->GetFloat( 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void RunThrough::SetOffset
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
offset = ev->GetVector( 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void RunThrough::SetSpawnModel
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
spawnmodel = ev->GetString( 1 );
|
|
|
|
CacheResource( spawnmodel );
|
|
|
|
}
|
|
|
|
|
|
|
|
void RunThrough::Touched
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
Vector forward, left, up;
|
|
|
|
Vector ang;
|
|
|
|
Vector org;
|
|
|
|
Entity * other;
|
|
|
|
|
|
|
|
other = ev->GetEntity( 1 );
|
|
|
|
|
|
|
|
assert( other );
|
|
|
|
if ( !other )
|
|
|
|
return;
|
|
|
|
|
|
|
|
// don't trigger on the world
|
|
|
|
if ( other == world )
|
|
|
|
return;
|
|
|
|
|
|
|
|
// don't re-trigger too soon
|
|
|
|
if ( level.time < lasttriggertime )
|
|
|
|
return;
|
|
|
|
|
|
|
|
// don't trigger if not moving fast enough
|
|
|
|
if ( other->velocity.length() < speed )
|
|
|
|
return;
|
|
|
|
|
|
|
|
// don't trigger if chance says not to.
|
|
|
|
if ( G_Random( 1 ) > chance )
|
|
|
|
return;
|
|
|
|
|
|
|
|
ang = other->velocity.toAngles();
|
|
|
|
ang.AngleVectors( &forward, &left, &up );
|
|
|
|
|
|
|
|
// get the origin from the thing that triggered me
|
|
|
|
org = other->origin;
|
|
|
|
|
|
|
|
// set the height of the origin based on the bounds of this trigger minus the lip
|
|
|
|
org.z = absmax.z - lip;
|
|
|
|
|
|
|
|
org += offset.x * forward;
|
|
|
|
org += offset.y * left;
|
|
|
|
org += offset.z * up;
|
|
|
|
|
|
|
|
if ( spawnmodel.length() )
|
|
|
|
{
|
|
|
|
Entity * ent;
|
|
|
|
// purposely declared here so that we don't do it every frame
|
|
|
|
SpawnArgs args;
|
|
|
|
|
|
|
|
args.setArg( "origin", va( "%f %f %f", org[ 0 ], org[ 1 ], org[ 2 ] ) );
|
|
|
|
args.setArg( "angles", va( "%f %f %f", ang[ 0 ], ang[ 1 ], ang[ 2 ] ) );
|
|
|
|
args.setArg( "model", spawnmodel.c_str() );
|
|
|
|
|
|
|
|
ent = ( Entity * )args.Spawn();
|
|
|
|
if ( ent )
|
|
|
|
{
|
|
|
|
ent->ProcessPendingEvents();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// set trigger time for next time
|
|
|
|
lasttriggertime = level.time + delay;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
/*QUAKED func_sinkobject (0 0 1) ? x FALLAWAY NO_RESET
|
|
|
|
|
|
|
|
This creates an object which gradually sinks downward when stepped on.
|
|
|
|
"delay" - delay between when object starts reacting towards weight (default 0 seconds)
|
|
|
|
"speed" - set the speed at which sinkobject sinks (default is 50)
|
|
|
|
"resetspeed" - speed at which sinkobject resets its position, (default speed * 0.1)
|
|
|
|
"dampening" - dampening constant to mitigate acceleration (default 0.95)
|
|
|
|
"limit" - limit the movement of the sinkobject how far down it should go (default 1000 units)
|
|
|
|
"resetdelay" - time between player gets off platform, and platform starts resetting itself.
|
|
|
|
"sinksound" - sound to be played while platform is sinking.
|
|
|
|
"resetsound" - sound to be played while platform is resetting.
|
|
|
|
"active" - make the sink object active
|
|
|
|
"notactive" - make the sink object not active
|
|
|
|
|
|
|
|
FALLAWAY - the sink object will progressively fall down faster and faster
|
|
|
|
NO_RESET - the sink object will not reset, only move downward
|
|
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
#define FALLAWAY ( 1 << 1 )
|
|
|
|
#define NO_RESET ( 1 << 2 )
|
|
|
|
|
|
|
|
Event EV_SinkObject_SetSpeed
|
|
|
|
(
|
|
|
|
"speed",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"speed",
|
|
|
|
"Speed at which SinkObject starts falling.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_SinkObject_SetDelay
|
|
|
|
(
|
|
|
|
"delay",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"delay",
|
|
|
|
"Delay until SinkObject starts falling.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_SinkObject_Reset
|
|
|
|
(
|
|
|
|
"reset",
|
|
|
|
EV_CONSOLE,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Reset the SinkObject right now.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_SinkObject_AdjustSinkObject
|
|
|
|
(
|
|
|
|
"_adjust_SinkObject",
|
|
|
|
EV_CODEONLY,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Called periodically to adjust the sinkobject every frame and adjust its velocity.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_SinkObject_Fall
|
|
|
|
(
|
|
|
|
"_fall_SinkObject",
|
|
|
|
EV_CODEONLY,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Called periodically to make a sink object fall away.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_SinkObject_SetResetSpeed
|
|
|
|
(
|
|
|
|
"resetspeed",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"newResetspeed",
|
|
|
|
"Speed at which SinkObject resets itself, defaults to 0.002 * speed.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_SinkObject_SetResetDelay
|
|
|
|
(
|
|
|
|
"resetdelay",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"newResetDelay",
|
|
|
|
"Delay between when sinkobject starts resetting.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_SinkObject_SetSinkSound
|
|
|
|
(
|
|
|
|
"sinksound",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"newSinkSound",
|
|
|
|
"Sound played when sinkobject is sinking.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_SinkObject_SetResetSound
|
|
|
|
(
|
|
|
|
"resetsound",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"newResetSound",
|
|
|
|
"Sound played when sinkobject is resetting.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_SinkObject_SetDampening
|
|
|
|
(
|
|
|
|
"dampening",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"newDampening",
|
|
|
|
"dampening of SinkObject.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_SinkObject_SetLimit
|
|
|
|
(
|
|
|
|
"limit",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"newLimit",
|
|
|
|
"maximum displacement of the SinkObject.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_SinkObject_Setup
|
|
|
|
(
|
|
|
|
"_setup",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"setup the SinkObject for the first time.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_SinkObject_MakeActive
|
|
|
|
(
|
|
|
|
"active",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"make the SinkObject active, so that it will respond to players touching it.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
Event EV_SinkObject_MakeNonActive
|
|
|
|
(
|
|
|
|
"notactive",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"make the SinkObject not active, so that it won't respond to players touching it.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
CLASS_DECLARATION( ScriptSlave, SinkObject, "func_sinkobject" )
|
|
|
|
{
|
|
|
|
{ &EV_SinkObject_SetSpeed, &SinkObject::SetSpeed },
|
|
|
|
{ &EV_SinkObject_SetDelay, &SinkObject::SetDelay },
|
|
|
|
{ &EV_SinkObject_Reset, &SinkObject::Reset },
|
|
|
|
{ &EV_SinkObject_AdjustSinkObject, &SinkObject::Adjust },
|
|
|
|
{ &EV_SinkObject_Fall, &SinkObject::Fall },
|
|
|
|
{ &EV_Touch, &SinkObject::Touched },
|
|
|
|
{ &EV_SinkObject_SetResetSpeed, &SinkObject::SetResetSpeed },
|
|
|
|
{ &EV_SinkObject_SetDampening, &SinkObject::SetDampening },
|
|
|
|
{ &EV_SinkObject_SetLimit, &SinkObject::SetLimit },
|
|
|
|
{ &EV_SinkObject_Setup, &SinkObject::Setup },
|
|
|
|
{ &EV_SinkObject_SetResetDelay, &SinkObject::SetResetDelay },
|
|
|
|
{ &EV_SinkObject_SetResetSound, &SinkObject::SetResetSound },
|
|
|
|
{ &EV_SinkObject_SetSinkSound, &SinkObject::SetSinkSound },
|
|
|
|
{ &EV_SinkObject_MakeActive, &SinkObject::MakeActive },
|
|
|
|
{ &EV_SinkObject_MakeNonActive, &SinkObject::MakeNonActive },
|
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
#define RESET_SCALE 0.1f
|
|
|
|
#define SPEED_DIVISOR ( 1.0f / 250.0f )
|
|
|
|
|
|
|
|
SinkObject::SinkObject()
|
|
|
|
{
|
|
|
|
if ( LoadingSavegame )
|
|
|
|
{
|
|
|
|
// Archive function will setup all necessary data
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
active = qtrue;
|
|
|
|
sinksound = "";
|
|
|
|
resetsound = "";
|
|
|
|
resetdelay = 0;
|
|
|
|
delay = 0;
|
|
|
|
touched = qfalse;
|
|
|
|
speed = 50 * SPEED_DIVISOR;
|
|
|
|
resetspeed = speed * RESET_SCALE;
|
|
|
|
dampening = 0.95f;
|
|
|
|
limit = 1000;
|
|
|
|
time_touched = -1;
|
|
|
|
time_reset = -1;
|
|
|
|
setMoveType( MOVETYPE_PUSH );
|
|
|
|
PostEvent( EV_SinkObject_Setup, FRAMETIME );
|
|
|
|
}
|
|
|
|
|
|
|
|
void SinkObject::Setup
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
startpos = origin;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SinkObject::SetSpeed
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
speed = ev->GetFloat( 1 ) * SPEED_DIVISOR;
|
|
|
|
resetspeed = speed * RESET_SCALE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SinkObject::SetDelay
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
delay = ev->GetFloat( 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void SinkObject::SetResetSpeed
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
resetspeed = ev->GetFloat( 1 ) * SPEED_DIVISOR;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SinkObject::SetResetDelay
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
resetdelay = ev->GetFloat( 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void SinkObject::SetSinkSound
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
sinksound = ev->GetString( 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void SinkObject::SetResetSound
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
resetsound = ev->GetString( 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void SinkObject::SetDampening
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
dampening = ev->GetFloat( 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void SinkObject::SetLimit
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
limit = ev->GetFloat( 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void SinkObject::Reset
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
time_reset = -1;
|
|
|
|
time_touched = -1;
|
|
|
|
touched = qfalse;
|
|
|
|
velocity = vec_zero;
|
|
|
|
setOrigin( startpos );
|
|
|
|
CancelEventsOfType( EV_SinkObject_AdjustSinkObject );
|
|
|
|
StopLoopSound();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SinkObject::Touched
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
Entity * other;
|
|
|
|
|
|
|
|
// if we aren't active, don't let anyone touch us
|
|
|
|
if ( !active )
|
|
|
|
return;
|
|
|
|
|
|
|
|
other = ev->GetEntity( 1 );
|
|
|
|
|
|
|
|
assert( other );
|
|
|
|
if ( !other )
|
|
|
|
return;
|
|
|
|
|
|
|
|
//
|
|
|
|
// only things resting on me will affect me
|
|
|
|
//
|
|
|
|
if ( other->groundentity != this->edict )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( delay )
|
|
|
|
{
|
|
|
|
if ( time_touched == -1 )
|
|
|
|
time_touched = level.time + delay;
|
|
|
|
//
|
|
|
|
// not time yet
|
|
|
|
//
|
|
|
|
if ( level.time < time_touched )
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ( sinksound.length() )
|
|
|
|
{
|
|
|
|
LoopSound( sinksound );
|
|
|
|
}
|
|
|
|
|
|
|
|
velocity.z -= speed;
|
|
|
|
|
|
|
|
if ( origin.z < ( startpos.z - limit ) )
|
|
|
|
{
|
|
|
|
origin.z = startpos.z - limit;
|
|
|
|
setOrigin( origin );
|
|
|
|
velocity = vec_zero;
|
|
|
|
}
|
|
|
|
|
|
|
|
touched = qtrue;
|
|
|
|
|
|
|
|
if ( spawnflags & FALLAWAY )
|
|
|
|
{
|
|
|
|
CancelEventsOfType( EV_SinkObject_Fall );
|
|
|
|
PostEvent( EV_SinkObject_Fall, FRAMETIME );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
CancelEventsOfType( EV_SinkObject_AdjustSinkObject );
|
|
|
|
PostEvent( EV_SinkObject_AdjustSinkObject, FRAMETIME );
|
|
|
|
}
|
|
|
|
|
|
|
|
void SinkObject::Fall
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
velocity.z -= speed;
|
|
|
|
|
|
|
|
if ( origin.z < ( startpos.z - limit ) )
|
|
|
|
{
|
|
|
|
origin.z = startpos.z - limit;
|
|
|
|
setOrigin( origin );
|
|
|
|
velocity = vec_zero;
|
|
|
|
StopLoopSound();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CancelEventsOfType( EV_SinkObject_Fall );
|
|
|
|
PostEvent( EV_SinkObject_Fall, FRAMETIME );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SinkObject::Adjust
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
if ( !touched )
|
|
|
|
{
|
|
|
|
float diff;
|
|
|
|
|
|
|
|
if ( spawnflags & NO_RESET )
|
|
|
|
{
|
|
|
|
StopLoopSound();
|
|
|
|
time_touched = -1;
|
|
|
|
velocity.z = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( resetdelay )
|
|
|
|
{
|
|
|
|
// stop the object
|
|
|
|
velocity.z = 0;
|
|
|
|
// kill its sound
|
|
|
|
StopLoopSound();
|
|
|
|
if ( time_reset == -1 )
|
|
|
|
time_reset = level.time + resetdelay;
|
|
|
|
//
|
|
|
|
// not time yet
|
|
|
|
//
|
|
|
|
if ( level.time < time_reset )
|
|
|
|
{
|
|
|
|
PostEvent( EV_SinkObject_AdjustSinkObject, FRAMETIME );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( resetsound.length() )
|
|
|
|
{
|
|
|
|
LoopSound( resetsound );
|
|
|
|
}
|
|
|
|
diff = startpos.z - origin.z;
|
|
|
|
|
|
|
|
velocity.z += resetspeed * diff;
|
|
|
|
velocity.z *= dampening;
|
|
|
|
if ( ( fabs( diff ) < 0.5f ) && ( fabs( velocity.z ) < 1 ) )
|
|
|
|
{
|
|
|
|
Reset( NULL );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
touched = qfalse;
|
|
|
|
}
|
|
|
|
|
|
|
|
PostEvent( EV_SinkObject_AdjustSinkObject, FRAMETIME );
|
|
|
|
}
|
|
|
|
|
|
|
|
void SinkObject::MakeActive
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
active = qtrue;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SinkObject::MakeNonActive
|
|
|
|
(
|
|
|
|
Event *ev
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
active = qfalse;
|
|
|
|
}
|