mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-19 20:24:49 +00:00
398 lines
13 KiB
C++
398 lines
13 KiB
C++
//-----------------------------------------------------------------------------
|
|
// Copyright (c) 2012 GarageGames, LLC
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to
|
|
// deal in the Software without restriction, including without limitation the
|
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
// sell copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
// IN THE SOFTWARE.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "sfx/sfxState.h"
|
|
#include "sfx/sfxTypes.h"
|
|
#include "core/stream/bitStream.h"
|
|
#include "console/engineAPI.h"
|
|
|
|
|
|
//#define DEBUG_SPEW
|
|
|
|
|
|
IMPLEMENT_CO_DATABLOCK_V1( SFXState );
|
|
|
|
|
|
ConsoleDocClass( SFXState,
|
|
"@brief A boolean switch used to modify playlist behavior.\n\n"
|
|
|
|
"Sound system states are used to allow playlist controllers to make decisions based on global state. This is useful, for "
|
|
"example, to couple audio playback to gameplay state. Certain states may, for example, represent different locations that the "
|
|
"listener can be in, like underwater, in open space, or indoors. Other states could represent moods of the current gameplay "
|
|
"situation, like, for example, an aggressive mood during combat.\n\n"
|
|
|
|
"By activating and deactivating sound states according to gameplay state, a set of concurrently running playlists may "
|
|
"react and adapt to changes in the game.\n\n"
|
|
|
|
"@section SFXState_activation Activation and Deactivation\n"
|
|
|
|
"At any time, a given state can be either active or inactive. Calling activate() on a state increases an internal "
|
|
"counter and calling deactivate() decreases the counter. Only when the count reaches zero will the state be "
|
|
"deactivated.\n\n"
|
|
|
|
"In addition to the activation count, states also maintain a disabling count. Calling disable() increases this count "
|
|
"and calling enable() decreases it. As long as this count is greater than zero, a given state will not be activated "
|
|
"even if its activation count is non-zero. Calling disable() on an active state will not only increase the disabling "
|
|
"count but also deactivate the state. Calling enable() on a state with a positive activation count will re-activate "
|
|
"the state when the disabling count reaches zero.\n\n"
|
|
|
|
"@section SFXState_dependencies State Dependencies\n"
|
|
|
|
"By listing other states in in its #includedStates and #excludedStates fields, a state may automatically trigger the "
|
|
"activation or disabling of other states in the sytem when it is activated. This allows to form dependency chains "
|
|
"between individual states.\n\n"
|
|
|
|
"@tsexample\n"
|
|
"// State indicating that the listener is submerged.\n"
|
|
"singleton SFXState( AudioLocationUnderwater )\n"
|
|
"{\n"
|
|
" parentGroup = AudioLocation;\n"
|
|
" // AudioStateExclusive is a class defined in the core scripts that will automatically\n"
|
|
" // ensure for a state to deactivate all the sibling SFXStates in its parentGroup when it\n"
|
|
" // is activated.\n"
|
|
" className = \"AudioStateExclusive\";\n"
|
|
"};\n"
|
|
"\n"
|
|
"// State suitable e.g. for combat.\n"
|
|
"singleton SFXState( AudioMoodAggressive )\n"
|
|
"{\n"
|
|
" parentGroup = AudioMood;\n"
|
|
" className = \"AudioStateExclusive\";\n"
|
|
"};\n"
|
|
"@endtsexample\n\n"
|
|
|
|
"@see SFXPlayList\n"
|
|
"@see SFXController\n"
|
|
"@see SFXPlayList::state\n"
|
|
"@see SFXPlayList::stateMode\n\n"
|
|
"@ref SFX_interactive\n\n"
|
|
|
|
"@ingroup SFX\n"
|
|
"@ingroup Datablocks"
|
|
);
|
|
|
|
|
|
IMPLEMENT_CALLBACK( SFXState, onActivate, void, (), (),
|
|
"Called when the state goes from inactive to active." );
|
|
IMPLEMENT_CALLBACK( SFXState, onDeactivate, void, (), (),
|
|
"called when the state goes from active to deactive." );
|
|
|
|
|
|
static Vector< SFXState* > sgActiveStates( __FILE__, __LINE__ );
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
SFXState::SFXState()
|
|
: mActiveCount( 0 ),
|
|
mDisableCount( 0 )
|
|
{
|
|
dMemset( mIncludedStates, 0, sizeof( mIncludedStates ) );
|
|
dMemset( mExcludedStates, 0, sizeof( mExcludedStates ) );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void SFXState::initPersistFields()
|
|
{
|
|
addGroup( "State" );
|
|
|
|
addField( "includedStates", TypeSFXStateName, Offset( mIncludedStates, SFXState ),
|
|
MaxIncludedStates,
|
|
"States that will automatically be activated when this state is activated.\n\n"
|
|
"@ref SFXState_activation" );
|
|
addField( "excludedStates", TypeSFXStateName, Offset( mExcludedStates, SFXState ),
|
|
MaxExcludedStates,
|
|
"States that will automatically be disabled when this state is activated.\n\n"
|
|
"@ref SFXState_activation" );
|
|
|
|
endGroup( "State" );
|
|
|
|
Parent::initPersistFields();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void SFXState::activate()
|
|
{
|
|
mActiveCount ++;
|
|
if( mActiveCount == 1 && !isDisabled() )
|
|
_onActivate();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void SFXState::deactivate()
|
|
{
|
|
if( !mActiveCount )
|
|
return;
|
|
|
|
mActiveCount --;
|
|
if( !mActiveCount && !isDisabled() )
|
|
_onDeactivate();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void SFXState::enable()
|
|
{
|
|
if( !mDisableCount )
|
|
return;
|
|
|
|
mDisableCount --;
|
|
|
|
if( !mDisableCount && mActiveCount > 0 )
|
|
_onActivate();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void SFXState::disable()
|
|
{
|
|
mDisableCount ++;
|
|
|
|
if( mDisableCount == 1 && mActiveCount > 0 )
|
|
_onDeactivate();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool SFXState::onAdd()
|
|
{
|
|
if( !Parent::onAdd() )
|
|
return false;
|
|
|
|
Sim::getSFXStateSet()->addObject( this );
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool SFXState::preload( bool server, String& errorStr )
|
|
{
|
|
if( !Parent::preload( server, errorStr ) )
|
|
return false;
|
|
|
|
if( !server )
|
|
{
|
|
for( U32 i = 0; i < MaxIncludedStates; ++ i )
|
|
if( !sfxResolve( &mIncludedStates[ i ], errorStr ) )
|
|
return false;
|
|
|
|
for( U32 i = 0; i < MaxExcludedStates; ++ i )
|
|
if( !sfxResolve( &mExcludedStates[ i ], errorStr ) )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void SFXState::packData( BitStream* stream )
|
|
{
|
|
Parent::packData( stream );
|
|
|
|
for( U32 i = 0; i < MaxIncludedStates; ++ i )
|
|
sfxWrite( stream, mIncludedStates[ i ] );
|
|
for( U32 i = 0; i < MaxExcludedStates; ++ i )
|
|
sfxWrite( stream, mExcludedStates[ i ] );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void SFXState::unpackData( BitStream* stream )
|
|
{
|
|
Parent::unpackData( stream );
|
|
|
|
for( U32 i = 0; i < MaxIncludedStates; ++ i )
|
|
sfxRead( stream, &mIncludedStates[ i ] );
|
|
for( U32 i = 0; i < MaxExcludedStates; ++ i )
|
|
sfxRead( stream, &mExcludedStates[ i ] );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void SFXState::_onActivate()
|
|
{
|
|
#ifdef DEBUG_SPEW
|
|
Platform::outputDebugString( "[SFXState] Activating '%s'", getName() );
|
|
#endif
|
|
|
|
onActivate_callback();
|
|
|
|
// Add the state to the list.
|
|
|
|
sgActiveStates.push_back( this );
|
|
|
|
// Activate included states.
|
|
|
|
for( U32 i = 0; i < MaxIncludedStates; ++ i )
|
|
if( mIncludedStates[ i ] )
|
|
mIncludedStates[ i ]->activate();
|
|
|
|
// Disable excluded states.
|
|
|
|
for( U32 i = 0; i < MaxExcludedStates; ++ i )
|
|
if( mExcludedStates[ i ] )
|
|
mExcludedStates[ i ]->disable();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void SFXState::_onDeactivate()
|
|
{
|
|
#ifdef DEBUG_SPEW
|
|
Platform::outputDebugString( "[SFXState] Deactivating '%s'", getName() );
|
|
#endif
|
|
|
|
onDeactivate_callback();
|
|
|
|
// Remove the state from the list.
|
|
|
|
for( U32 i = 0; i < sgActiveStates.size(); ++ i )
|
|
if( sgActiveStates[ i ] == this )
|
|
{
|
|
sgActiveStates.erase_fast( i );
|
|
break;
|
|
}
|
|
|
|
// Deactivate included states.
|
|
|
|
for( U32 i = 0; i < MaxIncludedStates; ++ i )
|
|
if( mIncludedStates[ i ] )
|
|
mIncludedStates[ i ]->deactivate();
|
|
|
|
// Enable excluded states.
|
|
|
|
for( U32 i = 0; i < MaxExcludedStates; ++ i )
|
|
if( mExcludedStates[ i ] )
|
|
mExcludedStates[ i ]->enable();
|
|
}
|
|
|
|
//=============================================================================
|
|
// Console Methods.
|
|
//=============================================================================
|
|
// MARK: ---- Console Methods ----
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DefineEngineMethod( SFXState, isActive, bool, (),,
|
|
"Test whether the state is currently active.\n"
|
|
"This is true when the activation count is >0 and the disabling count is =0.\n"
|
|
"@return True if the state is currently active.\n"
|
|
"@see activate" )
|
|
{
|
|
return object->isActive();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DefineEngineMethod( SFXState, activate, void, (),,
|
|
"Increase the activation count on the state.\n"
|
|
"If the state isn't already active and it is not disabled, the state will be activated.\n"
|
|
"@see isActive\n"
|
|
"@see deactivate\n" )
|
|
{
|
|
object->activate();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DefineEngineMethod( SFXState, deactivate, void, (),,
|
|
"Decrease the activation count on the state.\n"
|
|
"If the count reaches zero and the state was not disabled, the state will be deactivated.\n"
|
|
"@see isActive\n"
|
|
"@see activate\n" )
|
|
{
|
|
object->deactivate();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DefineEngineMethod( SFXState, isDisabled, bool, (),,
|
|
"Test whether the state is currently disabled.\n"
|
|
"This is true when the disabling count of the state is non-zero.\n"
|
|
"@return True if the state is disabled.\n\n"
|
|
"@see disable\n" )
|
|
{
|
|
return object->isDisabled();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DefineEngineMethod( SFXState, disable, void, (),,
|
|
"Increase the disabling count of the state.\n"
|
|
"If the state is currently active, it will be deactivated.\n"
|
|
"@see isDisabled\n" )
|
|
{
|
|
object->disable();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DefineEngineMethod( SFXState, enable, void, (),,
|
|
"Decrease the disabling count of the state.\n"
|
|
"If the disabling count reaches zero while the activation count is still non-zero, "
|
|
"the state will be reactivated again.\n"
|
|
"@see isDisabled\n" )
|
|
{
|
|
object->enable();
|
|
}
|
|
|
|
//=============================================================================
|
|
// Console Functions.
|
|
//=============================================================================
|
|
// MARK: ---- Console Functions ----
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DefineEngineFunction( sfxGetActiveStates, const char*, (),,
|
|
"Return a newline-separated list of all active states.\n"
|
|
"@return A list of the form\n"
|
|
"@verbatim\n"
|
|
"stateName1 NL stateName2 NL stateName3 ...\n"
|
|
"@endverbatim\n"
|
|
"where each element is the name of an active state object.\n\n"
|
|
"@tsexample\n"
|
|
"// Disable all active states.\n"
|
|
"foreach$( %state in sfxGetActiveStates() )\n"
|
|
" %state.disable();\n"
|
|
"@endtsexample\n\n"
|
|
"@ingroup SFX" )
|
|
{
|
|
StringBuilder str;
|
|
|
|
bool isFirst = true;
|
|
for( U32 i = 0; i < sgActiveStates.size(); ++ i )
|
|
{
|
|
if( !isFirst )
|
|
str.append( ' ' );
|
|
|
|
str.append( sgActiveStates[ i ]->getName() );
|
|
isFirst = false;
|
|
}
|
|
|
|
return Con::getReturnBuffer( str );
|
|
}
|