123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397 |
- //-----------------------------------------------------------------------------
- // 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 );
- }
|