From f4a718a8245b829cba8aed949d02b89cba0d0a0a Mon Sep 17 00:00:00 2001 From: Kyzentun Date: Sat, 17 Jan 2015 21:15:15 -0700 Subject: [PATCH] SetCompatibleStylesForPlayers and ForceSharedSidesMatch added to GameState for SSM to use to fix style mismatch problems. StyleInputToGameInput changed to take a vector to return values in to handle multiple inputs mapped to a single column. Associated adjustments to everything that uses it. Player no longer drops holds in columns that have multiple inputs mapped to them if the wrong one is held. Running out of stage tokens changed from assert to error. --- Themes/_fallback/Languages/en.ini | 8 ++ src/GameState.cpp | 129 +++++++++++++++++++++++++++++- src/GameState.h | 2 + src/GhostArrowRow.cpp | 5 +- src/InputMapper.cpp | 10 +++ src/InputMapper.h | 1 + src/LightsManager.cpp | 10 ++- src/NoteDisplay.cpp | 21 ++--- src/Player.cpp | 69 ++++++++++------ src/ReceptorArrow.cpp | 9 ++- src/ScreenEdit.cpp | 12 ++- src/ScreenGameplay.cpp | 8 +- src/ScreenNameEntry.cpp | 12 ++- src/ScreenSelectMusic.cpp | 37 ++------- src/Style.cpp | 21 +++-- src/Style.h | 2 +- 16 files changed, 270 insertions(+), 86 deletions(-) diff --git a/Themes/_fallback/Languages/en.ini b/Themes/_fallback/Languages/en.ini index a3bdd21eba..42c3069b6c 100644 --- a/Themes/_fallback/Languages/en.ini +++ b/Themes/_fallback/Languages/en.ini @@ -2599,6 +2599,10 @@ Pump_Halfdouble=Half-Double Pump_Couple=Couple Pump_Routine=Routine Kb7_Single=KB7 +Kickbox_Human=Human +Kickbox_Quadarm=Quadarm +Kickbox_Insect=Insect +Kickbox_Arachnid=Arachnid Ez2_Single=Single Ez2_Double=Double Ez2_Real=Real @@ -2634,6 +2638,10 @@ Pump_Halfdouble=Half-Double Pump_Couple=Couple Pump_Routine=Routine Kb7_Single=KB7 +Kickbox_Human=Human +Kickbox_Quadarm=Quadarm +Kickbox_Insect=Insect +Kickbox_Arachnid=Arachnid Ez2_Single=Single Ez2_Double=Double Ez2_Real=Real diff --git a/src/GameState.cpp b/src/GameState.cpp index c673779f02..a6a0c6b530 100644 --- a/src/GameState.cpp +++ b/src/GameState.cpp @@ -739,7 +739,12 @@ void GameState::BeginStage() // only do this check with human players, assume CPU players (Rave) // always have tokens. -aj (this could probably be moved below, even.) if( !IsEventMode() && !IsCpuPlayer(p) ) - ASSERT( m_iPlayerStageTokens[p] >= m_iNumStagesOfThisSong ); + { + if(m_iPlayerStageTokens[p] < m_iNumStagesOfThisSong) + { + LuaHelpers::ReportScriptErrorFmt("Player %d only has %d stage tokens, but needs %d.", p, m_iPlayerStageTokens[p], m_iNumStagesOfThisSong); + } + } m_iPlayerStageTokens[p] -= m_iNumStagesOfThisSong; } FOREACH_HumanPlayer( pn ) @@ -979,6 +984,101 @@ bool GameState::CanSafelyEnterGameplay(RString& reason) return true; } +void GameState::SetCompatibleStylesForPlayers() +{ + bool style_set= false; + if(IsCourseMode()) + { + if(m_pCurCourse != NULL) + { + const Style* style= m_pCurCourse->GetCourseStyle(m_pCurGame, GetNumSidesJoined()); + if(style != NULL) + { + style_set= true; + SetCurrentStyle(style, PLAYER_INVALID); + } + } + else + { + vector vst; + GAMEMAN->GetStepsTypesForGame(m_pCurGame, vst); + const Style *style = GAMEMAN->GetFirstCompatibleStyle( + m_pCurGame, GetNumSidesJoined(), vst[0]); + SetCurrentStyle(style, PLAYER_INVALID); + } + } + if(!style_set) + { + if(GetCurrentGame()->m_PlayersHaveSeparateStyles) + { + FOREACH_EnabledPlayer(pn) + { + StepsType st= StepsType_Invalid; + if(m_pCurSteps[pn] != NULL) + { + st= m_pCurSteps[pn]->m_StepsType; + } + else if(m_pCurTrail[pn] != NULL) + { + st= m_pCurTrail[pn]->m_StepsType; + } + else + { + vector vst; + GAMEMAN->GetStepsTypesForGame(m_pCurGame, vst); + st= vst[0]; + } + const Style *style = GAMEMAN->GetFirstCompatibleStyle( + m_pCurGame, GetNumSidesJoined(), st); + SetCurrentStyle(style, pn); + } + } + else + { + vector vst; + GAMEMAN->GetStepsTypesForGame(m_pCurGame, vst); + const Style *style = GAMEMAN->GetFirstCompatibleStyle( + m_pCurGame, GetNumSidesJoined(), vst[0]); + SetCurrentStyle(style, PLAYER_INVALID); + } + } +} + +void GameState::ForceSharedSidesMatch() +{ + PlayerNumber pn_with_shared= PLAYER_INVALID; + const Style* shared_style= NULL; + FOREACH_EnabledPlayer(pn) + { + const Style* style= GetCurrentStyle(pn); + ASSERT_M(style != NULL, "Style being null should not be possible."); + if(style->m_StyleType == StyleType_TwoPlayersSharedSides) + { + pn_with_shared= pn; + shared_style= style; + } + } + if(pn_with_shared != PLAYER_INVALID) + { + ASSERT_M(GetNumPlayersEnabled() == 2, "2 players must be enabled for shared sides."); + PlayerNumber other_pn= OPPOSITE_PLAYER[pn_with_shared]; + const Style* other_style= GetCurrentStyle(other_pn); + ASSERT_M(other_style != NULL, "Other player's style being null should not be possible."); + if(other_style->m_StyleType != StyleType_TwoPlayersSharedSides) + { + SetCurrentStyle(shared_style, other_pn); + if(IsCourseMode()) + { + m_pCurTrail[other_pn].Set(m_pCurTrail[pn_with_shared]); + } + else + { + m_pCurSteps[other_pn].Set(m_pCurSteps[pn_with_shared]); + } + } + } +} + void GameState::Update( float fDelta ) { m_SongOptions.Update( fDelta ); @@ -1333,7 +1433,6 @@ void GameState::SetCurrentStyle(const Style *style, PlayerNumber pn) } else { - m_SeparatedStyles[pn]= style; if(pn == PLAYER_INVALID) { FOREACH_PlayerNumber(rpn) @@ -1341,6 +1440,10 @@ void GameState::SetCurrentStyle(const Style *style, PlayerNumber pn) m_SeparatedStyles[rpn]= style; } } + else + { + m_SeparatedStyles[pn]= style; + } } if(INPUTMAPPER) { @@ -1415,6 +1518,28 @@ bool GameState::IsHumanPlayer( PlayerNumber pn ) const if( pn == PLAYER_INVALID ) return false; + if(GetCurrentGame()->m_PlayersHaveSeparateStyles) + { + if( GetCurrentStyle(pn) == NULL ) // no style chosen + { + return m_bSideIsJoined[pn]; + } + else + { + StyleType type = GetCurrentStyle(pn)->m_StyleType; + switch( type ) + { + case StyleType_TwoPlayersTwoSides: + case StyleType_TwoPlayersSharedSides: + return true; + case StyleType_OnePlayerOneSide: + case StyleType_OnePlayerTwoSides: + return pn == this->GetMasterPlayerNumber(); + default: + FAIL_M(ssprintf("Invalid style type: %i", type)); + } + } + } if( GetCurrentStyle(pn) == NULL ) // no style chosen { if( PlayersCanJoin() ) diff --git a/src/GameState.h b/src/GameState.h index 09e6f5803d..d449f17e69 100644 --- a/src/GameState.h +++ b/src/GameState.h @@ -74,6 +74,8 @@ public: Song* GetDefaultSong() const; bool CanSafelyEnterGameplay(RString& reason); + void SetCompatibleStylesForPlayers(); + void ForceSharedSidesMatch(); void Update( float fDelta ); diff --git a/src/GhostArrowRow.cpp b/src/GhostArrowRow.cpp index dd023937db..457ff524d3 100644 --- a/src/GhostArrowRow.cpp +++ b/src/GhostArrowRow.cpp @@ -24,8 +24,9 @@ void GhostArrowRow::Load( const PlayerState* pPlayerState, float fYReverseOffset { const RString &sButton = GAMESTATE->GetCurrentStyle(pn)->ColToButtonName( c ); - const GameInput GameI = GAMESTATE->GetCurrentStyle(pn)->StyleInputToGameInput( c, pn ); - NOTESKIN->SetGameController( GameI.controller ); + vector GameI; + GAMESTATE->GetCurrentStyle(pn)->StyleInputToGameInput( c, pn, GameI ); + NOTESKIN->SetGameController( GameI[0].controller ); m_bHoldShowing.push_back( TapNoteSubType_Invalid ); m_bLastHoldShowing.push_back( TapNoteSubType_Invalid ); diff --git a/src/InputMapper.cpp b/src/InputMapper.cpp index 70da57665a..290b8304f2 100644 --- a/src/InputMapper.cpp +++ b/src/InputMapper.cpp @@ -910,6 +910,16 @@ bool InputMapper::IsBeingPressed( GameButton MenuI, PlayerNumber pn ) const return false; } +bool InputMapper::IsBeingPressed(const vector& GameI, MultiPlayer mp, const DeviceInputList *pButtonState ) const +{ + bool pressed= false; + for(size_t i= 0; i < GameI.size(); ++i) + { + pressed |= IsBeingPressed(GameI[i], mp, pButtonState); + } + return pressed; +} + void InputMapper::RepeatStopKey( const GameInput &GameI ) { for( int i=0; i& GameI, MultiPlayer mp = MultiPlayer_Invalid, const DeviceInputList *pButtonState = NULL ) const; void ResetKeyRepeat( const GameInput &GameI ); void ResetKeyRepeat( GameButton MenuI, PlayerNumber pn ); diff --git a/src/LightsManager.cpp b/src/LightsManager.cpp index 84bad22410..9b0d11258b 100644 --- a/src/LightsManager.cpp +++ b/src/LightsManager.cpp @@ -80,10 +80,14 @@ static void GetUsedGameInputs( vector &vGameInputsOut ) { for( int iCol=0; iCol<(*style)->m_iColsPerPlayer; ++iCol ) { - GameInput gi = (*style)->StyleInputToGameInput( iCol, pn ); - if( gi.IsValid() ) + vector gi; + (*style)->StyleInputToGameInput( iCol, pn, gi ); + for(size_t i= 0; i < gi.size(); ++i) { - vGIs.insert( gi ); + if(gi[i].IsValid()) + { + vGIs.insert(gi[i]); + } } } } diff --git a/src/NoteDisplay.cpp b/src/NoteDisplay.cpp index f0bca2c546..5c9189ac78 100644 --- a/src/NoteDisplay.cpp +++ b/src/NoteDisplay.cpp @@ -290,29 +290,30 @@ void NoteDisplay::Load( int iColNum, const PlayerState* pPlayerState, float fYRe m_fYReverseOffsetPixels = fYReverseOffsetPixels; const PlayerNumber pn = m_pPlayerState->m_PlayerNumber; - const GameInput GameI = GAMESTATE->GetCurrentStyle(pPlayerState->m_PlayerNumber)->StyleInputToGameInput( iColNum, pn ); + vector GameI; + GAMESTATE->GetCurrentStyle(pPlayerState->m_PlayerNumber)->StyleInputToGameInput( iColNum, pn, GameI ); const RString &sButton = GAMESTATE->GetCurrentStyle(pPlayerState->m_PlayerNumber)->ColToButtonName( iColNum ); cache->Load( sButton ); // "normal" note types - m_TapNote.Load( sButton, "Tap Note", pn, GameI.controller ); + m_TapNote.Load( sButton, "Tap Note", pn, GameI[0].controller ); //m_TapAdd.Load( sButton, "Tap Addition", pn, GameI.controller ); - m_TapMine.Load( sButton, "Tap Mine", pn, GameI.controller ); - m_TapLift.Load( sButton, "Tap Lift", pn, GameI.controller ); - m_TapFake.Load( sButton, "Tap Fake", pn, GameI.controller ); + m_TapMine.Load( sButton, "Tap Mine", pn, GameI[0].controller ); + m_TapLift.Load( sButton, "Tap Lift", pn, GameI[0].controller ); + m_TapFake.Load( sButton, "Tap Fake", pn, GameI[0].controller ); // hold types FOREACH_HoldType( ht ) { FOREACH_ActiveType( at ) { - m_HoldHead[ht][at].Load( sButton, HoldTypeToString(ht)+" Head "+ActiveTypeToString(at), pn, GameI.controller ); - m_HoldTopCap[ht][at].Load( sButton, HoldTypeToString(ht)+" Topcap "+ActiveTypeToString(at), pn, GameI.controller ); - m_HoldBody[ht][at].Load( sButton, HoldTypeToString(ht)+" Body "+ActiveTypeToString(at), pn, GameI.controller ); - m_HoldBottomCap[ht][at].Load( sButton, HoldTypeToString(ht)+" Bottomcap "+ActiveTypeToString(at), pn, GameI.controller ); - m_HoldTail[ht][at].Load( sButton, HoldTypeToString(ht)+" Tail "+ActiveTypeToString(at), pn, GameI.controller ); + m_HoldHead[ht][at].Load( sButton, HoldTypeToString(ht)+" Head "+ActiveTypeToString(at), pn, GameI[0].controller ); + m_HoldTopCap[ht][at].Load( sButton, HoldTypeToString(ht)+" Topcap "+ActiveTypeToString(at), pn, GameI[0].controller ); + m_HoldBody[ht][at].Load( sButton, HoldTypeToString(ht)+" Body "+ActiveTypeToString(at), pn, GameI[0].controller ); + m_HoldBottomCap[ht][at].Load( sButton, HoldTypeToString(ht)+" Bottomcap "+ActiveTypeToString(at), pn, GameI[0].controller ); + m_HoldTail[ht][at].Load( sButton, HoldTypeToString(ht)+" Tail "+ActiveTypeToString(at), pn, GameI[0].controller ); } } } diff --git a/src/Player.cpp b/src/Player.cpp index 439a005b0b..2ecbad08dd 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -927,9 +927,10 @@ void Player::Update( float fDeltaTime ) ASSERT( m_pPlayerState != NULL ); // TODO: Remove use of PlayerNumber. - GameInput GameI = GAMESTATE->GetCurrentStyle(GetPlayerState()->m_PlayerNumber)->StyleInputToGameInput( col, m_pPlayerState->m_PlayerNumber ); + vector GameI; + GAMESTATE->GetCurrentStyle(GetPlayerState()->m_PlayerNumber)->StyleInputToGameInput( col, m_pPlayerState->m_PlayerNumber, GameI ); - bool bIsHoldingButton = INPUTMAPPER->IsBeingPressed( GameI ); + bool bIsHoldingButton= INPUTMAPPER->IsBeingPressed(GameI); // TODO: Make this work for non-human-controlled players if( bIsHoldingButton && !GAMESTATE->m_bDemonstrationOrJukebox && m_pPlayerState->m_PlayerController==PC_HUMAN ) @@ -1221,10 +1222,13 @@ void Player::UpdateHoldNotes( int iSongRow, float fDeltaTime, vectorGetCurrentStyle(GetPlayerState()->m_PlayerNumber)->StyleInputToGameInput( iTrack, pn ); - // this previously read as bIsHoldingButton &= - // was there a specific reason for this? - Friez - bIsHoldingButton &= INPUTMAPPER->IsBeingPressed( GameI, m_pPlayerState->m_mp ); + vector GameI; + GAMESTATE->GetCurrentStyle(GetPlayerState()->m_PlayerNumber)->StyleInputToGameInput( iTrack, pn, GameI ); + + bool is_holding= false; + // this previously read as bIsHoldingButton &= + // was there a specific reason for this? - Friez + is_holding &= INPUTMAPPER->IsBeingPressed(GameI, m_pPlayerState->m_mp); } } } @@ -2141,9 +2145,14 @@ void Player::StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, b int iNumTracksHeld = 0; for( int t=0; tGetCurrentStyle(GetPlayerState()->m_PlayerNumber)->StyleInputToGameInput( t, pn ); - const float fSecsHeld = INPUTMAPPER->GetSecsHeld( GameI ); - if( fSecsHeld > 0 && fSecsHeld < m_fTimingWindowJump ) + vector GameI; + GAMESTATE->GetCurrentStyle(GetPlayerState()->m_PlayerNumber)->StyleInputToGameInput( t, pn, GameI ); + float secs_held= 0.0f; + for(size_t i= 0; i < GameI.size(); ++i) + { + secs_held= max(secs_held, INPUTMAPPER->GetSecsHeld( GameI[i] )); + } + if( secs_held > 0 && secs_held < m_fTimingWindowJump ) iNumTracksHeld++; } @@ -2950,16 +2959,25 @@ void Player::CrossedRows( int iLastRowCrossed, const RageTimer &now ) if( !REQUIRE_STEP_ON_HOLD_HEADS ) { PlayerNumber pn = m_pPlayerState->m_PlayerNumber; - GameInput GameI = GAMESTATE->GetCurrentStyle(GetPlayerState()->m_PlayerNumber)->StyleInputToGameInput( iTrack, pn ); + vector GameI; + GAMESTATE->GetCurrentStyle(GetPlayerState()->m_PlayerNumber)->StyleInputToGameInput( iTrack, pn, GameI ); if( PREFSMAN->m_fPadStickSeconds > 0.f ) { - float fSecsHeld = INPUTMAPPER->GetSecsHeld( GameI, m_pPlayerState->m_mp ); - if( fSecsHeld >= PREFSMAN->m_fPadStickSeconds ) - Step( iTrack, -1, now - PREFSMAN->m_fPadStickSeconds, true, false ); + for(size_t i= 0; i < GameI.size(); ++i) + { + float fSecsHeld = INPUTMAPPER->GetSecsHeld(GameI[i], m_pPlayerState->m_mp); + if(fSecsHeld >= PREFSMAN->m_fPadStickSeconds) + { + Step(iTrack, -1, now - PREFSMAN->m_fPadStickSeconds, true, false); + } + } } - else if( INPUTMAPPER->IsBeingPressed(GameI, m_pPlayerState->m_mp) ) + else { - Step( iTrack, -1, now, true, false ); + if(INPUTMAPPER->IsBeingPressed(GameI, m_pPlayerState->m_mp)) + { + Step(iTrack, -1, now, true, false); + } } } break; @@ -2969,17 +2987,22 @@ void Player::CrossedRows( int iLastRowCrossed, const RageTimer &now ) // Hold the panel while crossing a mine will cause the mine to explode // TODO: Remove use of PlayerNumber. PlayerNumber pn = m_pPlayerState->m_PlayerNumber; - GameInput GameI = GAMESTATE->GetCurrentStyle(GetPlayerState()->m_PlayerNumber)->StyleInputToGameInput( iTrack, pn ); - if( PREFSMAN->m_fPadStickSeconds > 0 ) + vector GameI; + GAMESTATE->GetCurrentStyle(GetPlayerState()->m_PlayerNumber)->StyleInputToGameInput( iTrack, pn, GameI ); + if( PREFSMAN->m_fPadStickSeconds > 0.0f ) { - float fSecsHeld = INPUTMAPPER->GetSecsHeld( GameI, m_pPlayerState->m_mp ); - if( fSecsHeld >= PREFSMAN->m_fPadStickSeconds ) - Step( iTrack, -1, now - PREFSMAN->m_fPadStickSeconds, true, false ); + for(size_t i= 0; i < GameI.size(); ++i) + { + float fSecsHeld = INPUTMAPPER->GetSecsHeld(GameI[i], m_pPlayerState->m_mp); + if(fSecsHeld >= PREFSMAN->m_fPadStickSeconds) + { + Step( iTrack, -1, now - PREFSMAN->m_fPadStickSeconds, true, false ); + } + } } - else + else if(INPUTMAPPER->IsBeingPressed(GameI, m_pPlayerState->m_mp)) { - if( INPUTMAPPER->IsBeingPressed(GameI, m_pPlayerState->m_mp) ) - Step( iTrack, iRow, now, true, false ); + Step( iTrack, iRow, now, true, false ); } break; } diff --git a/src/ReceptorArrow.cpp b/src/ReceptorArrow.cpp index 4437df69e0..eb744769ba 100644 --- a/src/ReceptorArrow.cpp +++ b/src/ReceptorArrow.cpp @@ -20,9 +20,14 @@ void ReceptorArrow::Load( const PlayerState* pPlayerState, int iColNo ) m_iColNo = iColNo; const PlayerNumber pn = m_pPlayerState->m_PlayerNumber; - const GameInput GameI = GAMESTATE->GetCurrentStyle(pn)->StyleInputToGameInput( iColNo, pn ); + vector GameI; + GAMESTATE->GetCurrentStyle(pn)->StyleInputToGameInput(iColNo, pn, GameI); NOTESKIN->SetPlayerNumber( pn ); - NOTESKIN->SetGameController( GameI.controller ); + // FIXME? Does this cause a problem when game inputs on different + // controllers are mapped to the same column? Such a thing could be set + // up in a style that uses two controllers and has a mapping that fits the + // requirements. -Kyz + NOTESKIN->SetGameController( GameI[0].controller ); RString sButton = GAMESTATE->GetCurrentStyle(pn)->ColToButtonName( iColNo ); m_pReceptor.Load( NOTESKIN->LoadActor(sButton, "Receptor") ); diff --git a/src/ScreenEdit.cpp b/src/ScreenEdit.cpp index fa8b9e4b05..8f5d5221fe 100644 --- a/src/ScreenEdit.cpp +++ b/src/ScreenEdit.cpp @@ -1514,8 +1514,13 @@ void ScreenEdit::Update( float fDeltaTime ) for( int t=0; tGetCurrentStyle(GAMESTATE->GetMasterPlayerNumber())->m_iColsPerPlayer; t++ ) // for each track { - GameInput GameI = GAMESTATE->GetCurrentStyle(GAMESTATE->GetMasterPlayerNumber())->StyleInputToGameInput( t, PLAYER_1 ); - float fSecsHeld = INPUTMAPPER->GetSecsHeld( GameI ); + vector GameI; + GAMESTATE->GetCurrentStyle(GAMESTATE->GetMasterPlayerNumber())->StyleInputToGameInput( t, PLAYER_1, GameI ); + float fSecsHeld= 0.0f; + for(size_t i= 0; i < GameI.size(); ++i) + { + fSecsHeld= max(fSecsHeld, INPUTMAPPER->GetSecsHeld(GameI[i])); + } fSecsHeld = min( fSecsHeld, m_RemoveNoteButtonLastChanged.Ago() ); if( fSecsHeld == 0 ) continue; @@ -1568,7 +1573,8 @@ void ScreenEdit::Update( float fDeltaTime ) bool bButtonIsBeingPressed = false; for( int t=0; tGetCurrentStyle(GAMESTATE->GetMasterPlayerNumber())->m_iColsPerPlayer; t++ ) // for each track { - GameInput GameI = GAMESTATE->GetCurrentStyle(GAMESTATE->GetMasterPlayerNumber())->StyleInputToGameInput( t, PLAYER_1 ); + vector GameI; + GAMESTATE->GetCurrentStyle(GAMESTATE->GetMasterPlayerNumber())->StyleInputToGameInput( t, PLAYER_1, GameI ); if( INPUTMAPPER->IsBeingPressed(GameI) ) bButtonIsBeingPressed = true; } diff --git a/src/ScreenGameplay.cpp b/src/ScreenGameplay.cpp index 42498c0434..8ef4e722c8 100644 --- a/src/ScreenGameplay.cpp +++ b/src/ScreenGameplay.cpp @@ -2179,8 +2179,12 @@ void ScreenGameplay::UpdateLights() if( bBlink ) { - GameInput gi = pStyle->StyleInputToGameInput( t, pi->m_pn ); - bBlinkGameButton[gi.controller][gi.button] = true; + vector gi; + pStyle->StyleInputToGameInput( t, pi->m_pn, gi ); + for(size_t i= 0; i < gi.size(); ++i) + { + bBlinkGameButton[gi[i].controller][gi[i].button] = true; + } } } } diff --git a/src/ScreenNameEntry.cpp b/src/ScreenNameEntry.cpp index 63a97deced..a9ecccddc2 100644 --- a/src/ScreenNameEntry.cpp +++ b/src/ScreenNameEntry.cpp @@ -270,9 +270,15 @@ void ScreenNameEntry::Init() break; // We have enough columns. // Find out if this column is associated with the START menu button. - GameInput gi = GAMESTATE->GetCurrentStyle(p)->StyleInputToGameInput( iCol, p ); - GameButton mb = INPUTMAPPER->GameButtonToMenuButton( gi.button ); - if( mb == GAME_BUTTON_START ) + vector gi; + GAMESTATE->GetCurrentStyle(p)->StyleInputToGameInput( iCol, p, gi ); + bool gi_is_start= false; + for(size_t i= 0; i < gi.size(); ++i) + { + gi_is_start|= (INPUTMAPPER->GameButtonToMenuButton(gi[i].button) + == GAME_BUTTON_START); + } + if(gi_is_start) continue; m_ColToStringIndex[p][iCol] = CurrentStringIndex++; diff --git a/src/ScreenSelectMusic.cpp b/src/ScreenSelectMusic.cpp index a5358c3c49..77d3714dbc 100644 --- a/src/ScreenSelectMusic.cpp +++ b/src/ScreenSelectMusic.cpp @@ -232,10 +232,7 @@ void ScreenSelectMusic::BeginScreen() if( CommonMetrics::AUTO_SET_STYLE ) { - vector vst; - GAMEMAN->GetStepsTypesForGame( GAMESTATE->m_pCurGame, vst ); - const Style *pStyle = GAMEMAN->GetFirstCompatibleStyle( GAMESTATE->m_pCurGame, GAMESTATE->GetNumSidesJoined(), vst[0] ); - GAMESTATE->SetCurrentStyle( pStyle, PLAYER_INVALID ); + GAMESTATE->SetCompatibleStylesForPlayers(); } if( GAMESTATE->GetCurrentStyle(PLAYER_INVALID) == NULL ) @@ -1434,31 +1431,9 @@ bool ScreenSelectMusic::MenuStart( const InputEventPlus &input ) } } - if( CommonMetrics::AUTO_SET_STYLE ) - { - // Now that Steps have been chosen, set a Style that can play them. - const Style *pStyle = NULL; - if( GAMESTATE->IsCourseMode() ) - pStyle = GAMESTATE->m_pCurCourse->GetCourseStyle( GAMESTATE->m_pCurGame, GAMESTATE->GetNumSidesJoined() ); - if( pStyle == NULL ) - { - StepsType stCurrent; - PlayerNumber pn = GAMESTATE->GetMasterPlayerNumber(); - if( GAMESTATE->IsCourseMode() ) - { - ASSERT( GAMESTATE->m_pCurTrail[pn] != NULL ); - stCurrent = GAMESTATE->m_pCurTrail[pn]->m_StepsType; - } - else - { - ASSERT( GAMESTATE->m_pCurSteps[pn] != NULL ); - stCurrent = GAMESTATE->m_pCurSteps[pn]->m_StepsType; - } - vector vst; - pStyle = GAMEMAN->GetFirstCompatibleStyle( GAMESTATE->m_pCurGame, GAMESTATE->GetNumSidesJoined(), stCurrent ); - } - GAMESTATE->SetCurrentStyle( pStyle, PLAYER_INVALID ); - } + // Now that Steps have been chosen, set a Style that can play them. + GAMESTATE->SetCompatibleStylesForPlayers(); + GAMESTATE->ForceSharedSidesMatch(); /* If we're currently waiting on song assets, abort all except the music * and start the music, so if we make a choice quickly before background @@ -1829,6 +1804,10 @@ void ScreenSelectMusic::AfterMusicChange() } SongUtil::GetPlayableSteps( pSong, m_vpSteps ); + if(m_vpSteps.empty()) + { + //LuaHelpers::ReportScriptError("GetPlayableSteps returned nothing."); + } if ( PREFSMAN->m_bShowBanners ) g_sBannerPath = pSong->GetBannerPath(); diff --git a/src/Style.cpp b/src/Style.cpp index 7226095342..a628307574 100644 --- a/src/Style.cpp +++ b/src/Style.cpp @@ -47,7 +47,7 @@ void Style::GetTransformedNoteDataForStyle( PlayerNumber pn, const NoteData& ori noteDataOut.LoadTransformed( original, m_iColsPerPlayer, iNewToOriginalTrack ); } -GameInput Style::StyleInputToGameInput( int iCol, PlayerNumber pn ) const +void Style::StyleInputToGameInput( int iCol, PlayerNumber pn, vector& ret ) const { ASSERT_M( pn < NUM_PLAYERS && iCol < MAX_COLS_PER_PLAYER, ssprintf("P%i C%i", pn, iCol) ); @@ -65,12 +65,20 @@ GameInput Style::StyleInputToGameInput( int iCol, PlayerNumber pn ) const if( iThisInputCol == END_MAPPING ) break; + // A style can have multiple game inputs mapped to a single column, so + // we have to return all the game inputs that are valid. If only the + // first is returned, then holds will drop on other inputs that should + // be valid. -Kyz if( iThisInputCol == iCol ) - return GameInput( gc, gb ); + { + ret.push_back(GameInput( gc, gb )); + } } } - - FAIL_M( ssprintf("Invalid column number %i for player %i in the style %s", iCol, pn, m_szName) ); + if(unlikely(ret.empty())) + { + FAIL_M( ssprintf("Invalid column number %i for player %i in the style %s", iCol, pn, m_szName) ); + } }; int Style::GameInputToColumn( const GameInput &GameI ) const @@ -122,8 +130,9 @@ RString Style::ColToButtonName( int iCol ) const if( pzColumnName != NULL ) return pzColumnName; - GameInput GI = StyleInputToGameInput( iCol, PLAYER_1 ); - return INPUTMAPPER->GetInputScheme()->GetGameButtonName(GI.button); + vector GI; + StyleInputToGameInput( iCol, PLAYER_1, GI ); + return INPUTMAPPER->GetInputScheme()->GetGameButtonName(GI[0].button); } // Lua bindings diff --git a/src/Style.h b/src/Style.h index d7a5ab371f..2562d2bb8d 100644 --- a/src/Style.h +++ b/src/Style.h @@ -80,7 +80,7 @@ public: * This is primarily for Couple and Routine styles. */ bool m_bLockDifficulties; - GameInput StyleInputToGameInput( int iCol, PlayerNumber pn ) const; + void StyleInputToGameInput( int iCol, PlayerNumber pn, vector& ret ) const; /** * @brief Retrieve the column based on the game input. * @param GameI the game input.