diff --git a/src/ScreenMapControllers2.cpp b/src/ScreenMapControllers2.cpp new file mode 100644 index 0000000000..9f9dc56fa9 --- /dev/null +++ b/src/ScreenMapControllers2.cpp @@ -0,0 +1,532 @@ +#include "global.h" +#include "ScreenMapControllers2.h" +#include "ScreenManager.h" +#include "RageLog.h" +#include "GameState.h" +#include "RageInput.h" +#include "InputMapper.h" +#include "ThemeManager.h" +#include "ScreenDimensions.h" +#include "InputEventPlus.h" +#include "LocalizedString.h" +#include "Foreach.h" +#include "LuaBinding.h" + +static const float g_fSecondsToWaitForInput = 0.05f; + +static const char *MapControlsStateNames[] = { + "SelectingButton", + "EditingMappings" +}; +XToString( MapControlsState ); +LuaXType( MapControlsState ); + +REGISTER_SCREEN_CLASS( ScreenMapControllers2 ); + +ScreenMapControllers2::ScreenMapControllers2() +{ + this->SubscribeToMessage( Message_AutoJoyMappingApplied ); + m_MapControlsState = MCS_Button; + m_EditingButton = GAME_BUTTON_MENULEFT; + ZERO( m_iMappingChoice ); + ZERO( m_iNumMappingRows ); +} + +static LocalizedString ADD_MAPPING( "ScreenMapControllers2", "Add Mapping" ); +void ScreenMapControllers2::Init() +{ + ScreenWithMenuElements::Init(); + + // load sounds + m_soundChange.Load( THEME->GetPathS(m_sName,"change"), true ); + m_soundDelete.Load( THEME->GetPathS(m_sName,"delete"), true ); + + // set devices text + m_textDevices.LoadFromFont( THEME->GetPathF(m_sName,"devices") ); + m_textDevices.SetName( "Devices" ); + LOAD_ALL_COMMANDS_AND_SET_XY( m_textDevices ); + this->AddChild( &m_textDevices ); + + // button input scroller + WRAP_INPUT_SCROLLER.Load( m_sName, "WrapInputScroller" ); + LOOP_INPUT_SCROLLER.Load( m_sName, "LoopInputScroller" ); + INPUT_SCROLLER_SECONDS_PER_ITEM.Load( m_sName, "InputScrollerSecondsPerItem" ); + INPUT_SCROLLER_NUM_ITEMS_TO_DRAW.Load( m_sName, "InputScrollerNumItemsToDraw" ); + INPUT_SCROLLER_TRANSFORM.Load( m_sName, "InputScrollerTransform" ); + INPUT_SCROLLER_SUBDIVISIONS.Load( m_sName, "InputScrollerSubdivisions" ); + + // map all buttons for this game. (todo: re-add BUTTONS_TO_MAP support?) + FOREACH_GameButtonInScheme( INPUTMAPPER->GetInputScheme(), gb ) + { + KeyToMap k; + k.m_GameButton = gb; + m_KeysToMap.push_back( k ); + } + + // input button names + int iRow = 0; + for( unsigned b=0; bSetName( "ButtonName" ); + pName->LoadFromFont( THEME->GetPathF(m_sName,"ButtonName") ); + RString sText = GameButtonToLocalizedString( INPUTMAPPER->GetInputScheme(), pKey->m_GameButton ); + pName->SetText( sText ); + ActorUtil::LoadAllCommands( *pName, m_sName ); + pName->PlayCommand( b == (unsigned)m_iInputChoice ? "GainFocus" : "LoseFocus" ); + m_InputLine[iRow].AddChild( pName ); + } + + m_InputLine[iRow].DeleteChildrenWhenDone(); + m_InputLine[iRow].SetName( "InputLine" ); + ActorUtil::LoadAllCommands( m_InputLine[iRow], m_sName ); + m_InputScroller.AddChild( &m_InputLine[iRow] ); + + iRow++; + } + + m_InputScroller.SetName( "InputScroller" ); + LOAD_ALL_COMMANDS_AND_SET_XY( m_InputScroller ); + m_InputScroller.SetLoop( LOOP_INPUT_SCROLLER ); + m_InputScroller.SetNumItemsToDraw( INPUT_SCROLLER_NUM_ITEMS_TO_DRAW ); + m_InputScroller.Load2(); + m_InputScroller.SetTransformFromReference( INPUT_SCROLLER_TRANSFORM ); + m_InputScroller.SetSecondsPerItem( INPUT_SCROLLER_SECONDS_PER_ITEM ); + m_InputScroller.SetNumSubdivisions( INPUT_SCROLLER_SUBDIVISIONS ); + this->AddChild( &m_InputScroller ); + + // set player scrollers: + vector vpns; + FOREACH_PlayerNumber( p ) + vpns.push_back( p ); + + // per-player mappings + WRAP_MAPPING_SCROLLER.Load( m_sName, "WrapMappingScroller" ); + LOOP_MAPPING_SCROLLER.Load( m_sName, "LoopMappingScroller" ); + MAPPING_SCROLLER_SECONDS_PER_ITEM.Load( m_sName, "MappingScrollerSecondsPerItem" ); + MAPPING_SCROLLER_NUM_ITEMS_TO_DRAW.Load( m_sName, "MappingScrollerNumItemsToDraw" ); + MAPPING_SCROLLER_TRANSFORM.Load( m_sName, "MappingScrollerTransform" ); + MAPPING_SCROLLER_SUBDIVISIONS.Load( m_sName, "MappingScrollerSubdivisions" ); + + FOREACH( PlayerNumber, vpns, p ) + { + // mapping scroller + m_MappingScroller[*p].SetLoop( LOOP_MAPPING_SCROLLER ); + m_MappingScroller[*p].SetNumItemsToDraw( MAPPING_SCROLLER_NUM_ITEMS_TO_DRAW ); + m_MappingScroller[*p].Load2(); + m_MappingScroller[*p].SetTransformFromReference( MAPPING_SCROLLER_TRANSFORM ); + m_MappingScroller[*p].SetSecondsPerItem( MAPPING_SCROLLER_SECONDS_PER_ITEM ); + m_MappingScroller[*p].SetNumSubdivisions( MAPPING_SCROLLER_SUBDIVISIONS ); + m_MappingScroller[*p].SetName( "MappingScroller"+ssprintf("P%d",(*p)+1) ); + LOAD_ALL_COMMANDS_AND_SET_XY( m_MappingScroller[*p] ); + this->AddChild( &m_MappingScroller[*p] ); + } +} + +void ScreenMapControllers2::BeginScreen() +{ + m_iInputChoice = 0; + m_ActivePlayerMapping = PLAYER_1; + + ScreenWithMenuElements::BeginScreen(); + + m_WaitingForPress.SetZero(); + + Refresh(); +} + +void ScreenMapControllers2::Update( float fDeltaTime ) +{ + ScreenWithMenuElements::Update( fDeltaTime ); + + // Update devices text + m_textDevices.SetText( INPUTMAN->GetDisplayDevicesString() ); + + if( !m_WaitingForPress.IsZero() && m_DeviceIToMap.IsValid() ) + { + // we're going to map an input + if( m_WaitingForPress.PeekDeltaTime() < g_fSecondsToWaitForInput ) + return; // keep waiting + m_WaitingForPress.SetZero(); + + /* do stuff here */ + //ASSERT( m_iCurButton < (int) m_KeysToMap.size() ); + //const KeyToMap *pKey = &m_KeysToMap[m_iCurButton]; + //GameInput curGameI( (GameController)m_iCurController, pKey->m_GameButton ); + //INPUTMAPPER->SetInputMap( m_DeviceIToMap, curGameI, m_iCurSlot ); + //INPUTMAPPER->AddDefaultMappingsForCurrentGameIfUnmapped(); + + // commit to disk after each change + //INPUTMAPPER->SaveMappingsToDisk(); + + Refresh(); + + /* + BitmapText *pText = pKey->m_textMappedTo[m_iCurController][m_iCurSlot]; + pText->PlayCommand( "MappedInput" ); + */ + SCREENMAN->PlayStartSound(); + } +} + + +/* Note that this isn't necessarily correct. For example, JOY_LEFT might + * actually be a D-pad and not an axis. All this is actually doing is giving + * priority to some inputs over others; this function is unsuitable for other use. */ +static bool IsAxis( const DeviceInput& DeviceI ) +{ + if( !DeviceI.IsJoystick() ) + return false; + + static int axes[] = + { + JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN, + JOY_LEFT_2, JOY_RIGHT_2, JOY_UP_2, JOY_DOWN_2, + JOY_Z_UP, JOY_Z_DOWN, + JOY_ROT_UP, JOY_ROT_DOWN, JOY_ROT_LEFT, JOY_ROT_RIGHT, JOY_ROT_Z_UP, JOY_ROT_Z_DOWN, + JOY_HAT_LEFT, JOY_HAT_RIGHT, JOY_HAT_UP, JOY_HAT_DOWN, + JOY_AUX_1, JOY_AUX_2, JOY_AUX_3, JOY_AUX_4, + -1 + }; + + for( int ax = 0; axes[ax] != -1; ++ax ) + if( DeviceI.button == axes[ax] ) + return true; + + return false; +} + +void ScreenMapControllers2::ChangeActivePlayer() +{ + m_ActivePlayerMapping = (m_ActivePlayerMapping == PLAYER_1) ? PLAYER_2 : PLAYER_1; + Message msg("ActivePlayerChanged"); + msg.SetParam("NewActivePlayer",m_ActivePlayerMapping); + MESSAGEMAN->Broadcast(msg); +} + +void ScreenMapControllers2::Input( const InputEventPlus &input ) +{ + if( input.type != IET_FIRST_PRESS && input.type != IET_REPEAT ) + return; // ignore + if( IsTransitioning() ) + return; // ignore + + LOG->Trace( "ScreenMapControllers2::Input(): device: %d, button: %d", + input.DeviceI.device, input.DeviceI.button ); + + int button = input.DeviceI.button; + + /* TRICKY: Some adapters map the PlayStation digital d-pad to both axes and + * buttons. We want buttons to be used for any mappings where possible + * because presses of buttons aren't mutually exclusive and presses of axes + * are (e.g. can't read presses of both Left and Right simultaneously). So, + * when the user presses a button, we'll wait until the next Update before + * adding a mapping so that we get a chance to see all input events the + * user's press of a panel. Prefer non-axis events over axis events. */ + if( !m_WaitingForPress.IsZero() ) + { + if( input.type != IET_FIRST_PRESS ) + return; + + // Don't allow function keys to be mapped. + if( input.DeviceI.device == DEVICE_KEYBOARD && (input.DeviceI.button >= KEY_F1 && input.DeviceI.button <= KEY_F12) ) + { + SCREENMAN->SystemMessage( "INVALID_BUTTON" ); + SCREENMAN->PlayInvalidSound(); + } + else + { + if( m_DeviceIToMap.IsValid() && + !IsAxis(m_DeviceIToMap) && + IsAxis(input.DeviceI) ) + { + LOG->Trace("Ignored input; non-axis event already received"); + return; // ignore this press + } + + m_DeviceIToMap = input.DeviceI; + } + } + else if( input.DeviceI.device == DEVICE_KEYBOARD ) + { + switch( button ) + { + // todo: m_MapControlsState checks + case KEY_UP: // mapping list up + { + if( m_MapControlsState == MCS_EditMappings ) + { + if( m_iMappingChoice[m_ActivePlayerMapping] == 0 ) + break; + m_iMappingChoice[m_ActivePlayerMapping]--; + } + } + break; + case KEY_DOWN: // mapping list down + { + if( m_MapControlsState == MCS_EditMappings ) + { + if( m_iMappingChoice[m_ActivePlayerMapping] == m_iNumMappingRows[m_ActivePlayerMapping] ) + break; + m_iMappingChoice[m_ActivePlayerMapping]++; + } + } + break; + case KEY_LEFT: // on P2, changing to P1 + { + if( m_MapControlsState == MCS_EditMappings ) + { + if(m_ActivePlayerMapping == PLAYER_2) + ChangeActivePlayer(); + } + } + break; + case KEY_RIGHT: // on P1, changing to P2 + { + if( m_MapControlsState == MCS_EditMappings ) + { + if(m_ActivePlayerMapping == PLAYER_1) + ChangeActivePlayer(); + } + } + break; + case KEY_DEL: + case KEY_BACK: + if( m_MapControlsState == MCS_EditMappings ) + { + // clear mapping + /* + if( m_iMappingChoice[m_ActivePlayerMapping] == m_iNumMappingRows[m_ActivePlayerMapping] ) + break; // on "add" + + { + // stuff + + m_soundDelete.Play(); + + // commit to disk after each change + INPUTMAPPER->SaveMappingsToDisk(); + } + */ + } + break; + case KEY_ESC: + { + if(m_MapControlsState == MCS_EditMappings) + { + // xxx: make sure it's not getting a button. + m_MapControlsState = MCS_Button; + SCREENMAN->PlayCancelSound(); + } + else + { + // Quit the screen. + SCREENMAN->PlayStartSound(); + StartTransitioningScreen( SM_GoToNextScreen ); + } + } + break; + case KEY_ENTER: + case KEY_KP_ENTER: + { + if( m_MapControlsState == MCS_EditMappings ) + { + // map button + LOG->Trace("got an enter press..."); + LOG->Trace( ssprintf("current choice: %i",m_iMappingChoice[m_ActivePlayerMapping]) ); + if( m_iMappingChoice[m_ActivePlayerMapping] == m_iNumMappingRows[m_ActivePlayerMapping] ) + { + // add + LOG->Trace("Adding a new mapping"); + } + else + { + // replace + LOG->Trace("Replacing an existing mapping"); + } + /* + m_WaitingForPress.Touch(); + m_DeviceIToMap.MakeInvalid(); + SCREENMAN->PlayStartSound(); + */ + } + } + break; + } + } + + ScreenWithMenuElements::Input( input ); // default handler + + Refresh(); +} + +void ScreenMapControllers2::Refresh() +{ + // update mapping scrollers + UpdateMappingScrollers(); +} + +void ScreenMapControllers2::HandleMessage( const Message &msg ) +{ + if( msg == Message_AutoJoyMappingApplied ) + { + Refresh(); + } + + ScreenWithMenuElements::HandleMessage( msg ); +} + +void ScreenMapControllers2::MenuStart( const InputEventPlus &input ) +{ + // MCS_EditMappings is handled in Input() above. + if( m_MapControlsState == MCS_Button ) + { + m_MapControlsState = MCS_EditMappings; + } +} + +void ScreenMapControllers2::UpdateMappingScrollers() +{ + FOREACH_ENUM( GameController, c ) + { + PlayerNumber pn = (PlayerNumber)c; + m_MappingScroller[pn].RemoveAllChildren(); + + int iLast = 0; + for(unsigned s = 0; s < NUM_SHOWN_GAME_TO_DEVICE_SLOTS; s++) + { + GameInput cur_gi( c, m_EditingButton ); + DeviceInput di; + RString sInput = ""; + if( INPUTMAPPER->GameToDevice( cur_gi, s, di ) ) + sInput = INPUTMAN->GetDeviceSpecificInputString(di); + + if( sInput != "" ) + { + m_MappingLine[iLast].RemoveAllChildren(); + // we have an input, add to the scroller + BitmapText *pText = new BitmapText; + pText->SetName( "MappedTo"+PlayerNumberToString(pn) ); + pText->LoadFromFont( THEME->GetPathF(m_sName,"Mapping") ); + ActorUtil::LoadAllCommands(pText,m_sName); + pText->PlayCommand( ((unsigned)m_iMappingChoice[pn] == s) ? "GainFocus" : "LoseFocus" ); + pText->SetText( sInput ); + + m_MappingLine[iLast].AddChild( pText ); + m_MappingLine[iLast].DeleteChildrenWhenDone(); + m_MappingLine[iLast].SetName("MappingLine"); + ActorUtil::LoadAllCommands(m_MappingLine[iLast],m_sName); + m_MappingScroller[pn].AddChild( &m_MappingLine[iLast] ); + iLast++; + } + } + + BitmapText &text = m_textAddMapping[pn]; + text.LoadFromFont( THEME->GetPathF(m_sName,"AddMapping") ); + text.SetName( "AddMapping"+PlayerNumberToString(pn) ); + ActorUtil::LoadAllCommands( text, m_sName ); + text.PlayCommand( (m_iMappingChoice[pn] == m_iNumMappingRows[pn]) ? "GainFocus" : "LoseFocus" ); + text.SetText( ADD_MAPPING ); + m_MappingScroller[pn].AddChild( &m_textAddMapping[c] ); + iLast++; + + m_iNumMappingRows[pn] = iLast; + + m_MappingScroller[pn].Load2(); + m_MappingScroller[pn].SetTransformFromReference( MAPPING_SCROLLER_TRANSFORM ); + m_MappingScroller[pn].SetCurrentAndDestinationItem( (float)m_iMappingChoice[pn] ); + } +} + +// change game/system button scroller selection +void ScreenMapControllers2::ChangeInputSelection(int iDir) +{ + m_InputLine[m_iInputChoice].PlayCommand("LoseFocus"); + m_iInputChoice += iDir; + m_soundChange.Play(); + m_InputLine[m_iInputChoice].PlayCommand("GainFocus"); + + // set scroller + m_InputScroller.SetCurrentAndDestinationItem( (float)m_iInputChoice ); + + // set current game button + KeyToMap *pKey = &m_KeysToMap[m_iInputChoice]; + m_EditingButton = pKey->m_GameButton; +} + +void ScreenMapControllers2::MenuUp( const InputEventPlus &input ) +{ + if( m_MapControlsState == MCS_Button ) + { + if( m_iInputChoice == 0 ) // limit + return; + ChangeInputSelection(-1); + } +} + +void ScreenMapControllers2::MenuDown( const InputEventPlus &input ) +{ + if( m_MapControlsState == MCS_Button ) + { + if( m_iInputChoice == (int)m_KeysToMap.size()-1 ) // limit + return; + ChangeInputSelection(1); + } +} + +void ScreenMapControllers2::TweenOnScreen() +{ + ScreenWithMenuElements::TweenOnScreen(); + + m_InputScroller.SetCurrentAndDestinationItem( (float)m_iInputChoice ); +} + +// lua start +#include "LuaBinding.h" + +/** @brief Allow Lua to have access to ScreenEdit. */ +class LunaScreenMapControllers2: public Luna +{ +public: + //static int MapControlsState( T* p, lua_State *L ) // + //static int GetEditingGameButton( T* p, lua_State *L ) // GetEditingGameButton() + DEFINE_METHOD( GetInputIndex, GetInputIndex() ); + DEFINE_METHOD( GetNumInputs, GetNumInputs() ); + LunaScreenMapControllers2() + { + //ADD_METHOD( GetEditingGameButton ); + ADD_METHOD( GetInputIndex ); + ADD_METHOD( GetNumInputs ); + //ADD_METHOD( MapControlsState ); + } +}; + +LUA_REGISTER_DERIVED_CLASS( ScreenMapControllers2, ScreenWithMenuElements ) + + +/* + * (c) 2011 AJ Kelly + * All rights reserved. + * + * 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, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * 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 OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/src/ScreenMapControllers2.h b/src/ScreenMapControllers2.h new file mode 100644 index 0000000000..463a8deced --- /dev/null +++ b/src/ScreenMapControllers2.h @@ -0,0 +1,136 @@ +/* ScreenMapControllers2 - Maps device input to game buttons. */ + +#ifndef SCREEN_MAP_CONTROLLERS2_H +#define SCREEN_MAP_CONTROLLERS2_H + +#include "ScreenWithMenuElements.h" +#include "BitmapText.h" +#include "InputMapper.h" +#include "ActorScroller.h" +#include "RageSound.h" +#include "EnumHelper.h" +#include "ThemeMetric.h" + +/* old inputmapper consts: +const int NUM_GAME_TO_DEVICE_SLOTS = 5; // five device inputs may map to one game input +const int NUM_SHOWN_GAME_TO_DEVICE_SLOTS = 3; +const int NUM_USER_GAME_TO_DEVICE_SLOTS = 2; +*/ +const int MAPPING_LINE = NUM_SHOWN_GAME_TO_DEVICE_SLOTS+1; // +1 for "Add Mapping" + +enum MapControlsState +{ + MCS_Button, // which button to edit mappings for + MCS_EditMappings, // player is editing mappings + NUM_MapControlsState, + MapControlsState_Invalid +}; +const RString& MapControlsStateToString( MapControlsState mct ); +LuaDeclareType( MapControlsState ); + +class ScreenMapControllers2 : public ScreenWithMenuElements +{ +public: + ScreenMapControllers2(); + virtual void Init(); + virtual void BeginScreen(); + //virtual void EndScreen(); + + virtual void Update( float fDeltaTime ); + virtual void Input( const InputEventPlus &input ); + + virtual void MenuUp( const InputEventPlus &input ); + virtual void MenuDown( const InputEventPlus &input ); + virtual void MenuStart( const InputEventPlus &input ); + virtual void TweenOnScreen(); + + MapControlsState GetMapControlsState(){ return m_MapControlsState; } + GameButton GetEditingGameButton() { return m_EditingButton; } + int GetInputIndex(){ return m_iInputChoice; } + int GetNumInputs(){ return m_KeysToMap.size(); } + int GetMappingIndex(PlayerNumber pn){ return m_iMappingChoice[pn]; } + + // Lua + virtual void PushSelf( lua_State *L ); + +protected: + virtual void HandleMessage( const Message &msg ); + + void ChangeActivePlayer(); + void ChangeInputSelection(int iDir); + void UpdateMappingScrollers(); + void Refresh(); + + MapControlsState m_MapControlsState; + RageTimer m_WaitingForPress; + DeviceInput m_DeviceIToMap; + + struct KeyToMap + { + GameButton m_GameButton; + BitmapText* m_textLabel; + }; + vector m_KeysToMap; + + BitmapText m_textDevices; + //vector m_textMappingLabels[NUM_PLAYERS]; + BitmapText m_textAddMapping[NUM_PLAYERS]; + + // possible inputs + int m_iInputChoice; + ActorScroller m_InputScroller; + ActorFrame m_InputLine[NUM_GameButton]; + ThemeMetric WRAP_INPUT_SCROLLER; + ThemeMetric LOOP_INPUT_SCROLLER; + ThemeMetric INPUT_SCROLLER_SECONDS_PER_ITEM; + ThemeMetric INPUT_SCROLLER_NUM_ITEMS_TO_DRAW; + ThemeMetric INPUT_SCROLLER_TRANSFORM; + ThemeMetric INPUT_SCROLLER_SUBDIVISIONS; + + // per-player button mappings. + GameButton m_EditingButton; + PlayerNumber m_ActivePlayerMapping; + int m_iMappingChoice[NUM_PLAYERS]; + int m_iNumMappingRows[NUM_PLAYERS]; + ActorScroller m_MappingScroller[NUM_PLAYERS]; + ActorFrame m_MappingLine[MAPPING_LINE]; + ThemeMetric WRAP_MAPPING_SCROLLER; + ThemeMetric LOOP_MAPPING_SCROLLER; + ThemeMetric MAPPING_SCROLLER_SECONDS_PER_ITEM; + ThemeMetric MAPPING_SCROLLER_NUM_ITEMS_TO_DRAW; + ThemeMetric MAPPING_SCROLLER_TRANSFORM; + ThemeMetric MAPPING_SCROLLER_SUBDIVISIONS; + + // should be handled in lua + //BitmapText m_textLabel[NUM_GameController]; + + RageSound m_soundChange; + RageSound m_soundDelete; +}; + +#endif + +/* + * (c) 2011 AJ Kelly + * All rights reserved. + * + * 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, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * 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 OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */