#include "global.h" #include "ScreenNameEntryTraditional.h" #include "SongManager.h" #include "GameConstantsAndTypes.h" #include "RageUtil.h" #include "PrefsManager.h" #include "GameManager.h" #include "RageLog.h" #include "GameState.h" #include "GameSoundManager.h" #include "ThemeManager.h" #include "Course.h" #include "ActorUtil.h" #include "FontCharAliases.h" #include "AnnouncerManager.h" #include "song.h" #include "Steps.h" #include "ProfileManager.h" #include "Profile.h" #include "StatsManager.h" #include "Foreach.h" #include "Style.h" #include "ScreenDimensions.h" #include "InputEventPlus.h" #include "RageInput.h" // // Defines specific to ScreenNameEntryTraditional // #define COMMAND_OPTIONAL( actor, command_name ) \ if( !(actor).GetName().empty() ) \ COMMAND( (actor), command_name ); AutoScreenMessage( SM_ChangeDisplayedFeat ) static const int CHAR_OK = -1; static const int CHAR_BACK = -2; void HighScoreWheelItem::Load( int iRankIndex, const HighScore& hs ) { SetName( "HighScoreWheelItem" ); m_textRank.SetName( "Rank" ); m_textRank.LoadFromFont( THEME->GetPathF(m_sName,"rank") ); m_textRank.SetText( ssprintf("%d", iRankIndex+1) ); m_textRank.SetShadowLength( 2 ); this->AddChild( &m_textRank ); SET_XY_AND_ON_COMMAND( m_textRank ); m_textName.SetName( "Name" ); m_textName.LoadFromFont( THEME->GetPathF(m_sName,"name") ); m_textName.SetText( hs.GetDisplayName() ); m_textName.SetShadowLength( 2 ); this->AddChild( &m_textName ); SET_XY_AND_ON_COMMAND( m_textName ); m_textScore.SetName( "Score" ); m_textScore.LoadFromFont( THEME->GetPathF(m_sName,"score") ); if( PREFSMAN->m_bPercentageScoring ) m_textScore.SetText( PercentageDisplay::FormatPercentScore(hs.GetPercentDP()) ); else m_textScore.SetText( ssprintf("%i", hs.GetScore()) ); m_textScore.SetShadowLength( 2 ); this->AddChild( &m_textScore ); SET_XY_AND_ON_COMMAND( m_textScore ); m_textDate.SetName( "Date" ); m_textDate.LoadFromFont( THEME->GetPathF(m_sName,"date") ); m_textDate.SetText( ssprintf("%02d/%02d", hs.GetDateTime().tm_mon+1, hs.GetDateTime().tm_mday) ); m_textDate.SetShadowLength( 2 ); this->AddChild( &m_textDate ); SET_XY_AND_ON_COMMAND( m_textDate ); } void HighScoreWheelItem::LoadBlank( int iRankIndex ) { HighScore hs; Load( iRankIndex, hs ); } void HighScoreWheelItem::ShowFocus() { apActorCommands c = ActorUtil::ParseActorCommands( "diffuseshift;EffectColor1,1,1,0,1;EffectColor2,0,1,1,1" ); m_textRank.RunCommands( c ); m_textName.RunCommands( c ); m_textScore.RunCommands( c ); m_textDate.RunCommands( c ); } void HighScoreWheel::Load( const HighScoreList& hsl, int iIndexToFocus ) { m_Items.resize( PREFSMAN->m_iMaxHighScoresPerListForMachine ); for( int i=0; im_iMaxHighScoresPerListForMachine; i++ ) { if( unsigned(i) < hsl.vHighScores.size() ) m_Items[i].Load( i, hsl.vHighScores[i] ); else m_Items[i].LoadBlank( i ); this->AddChild( &m_Items[i] ); } m_iIndexToFocus = iIndexToFocus; if( m_iIndexToFocus >= 0 && m_iIndexToFocus < int(hsl.vHighScores.size()) ) m_Items[m_iIndexToFocus].ShowFocus(); RString sTransformFunction = "function(self,offset,itemIndex,numItems) " " local degrees=18*offset; " " local radians=degrees*math.pi/180; " " self:rotationx(degrees); " " self:y(math.sin(radians)*90); " " self:z(math.cos(radians)*90); " "end"; LuaReference ref; ref.SetFromExpression( sTransformFunction ); ActorScroller::SetNumItemsToDraw( 10.5f ); ActorScroller::Load2(); ActorScroller::SetTransformFromReference( ref ); ActorScroller::SetSecondsPerItem( 0.2f ); Scroll(); } float HighScoreWheel::Scroll() { SetCurrentAndDestinationItem( m_SubActors.size()+5.0f ); int iIndexToFocus = max( m_iIndexToFocus, 3 ); SetDestinationItem( (float)iIndexToFocus ); return GetTweenTimeLeft(); } REGISTER_SCREEN_CLASS( ScreenNameEntryTraditional ); ScreenNameEntryTraditional::ScreenNameEntryTraditional() { if( PREFSMAN->m_bScreenTestMode ) { GAMESTATE->m_bSideIsJoined[PLAYER_1] = true; GAMESTATE->m_bSideIsJoined[PLAYER_2] = true; GAMESTATE->m_MasterPlayerNumber = PLAYER_1; GAMESTATE->m_PlayMode.Set( PLAY_MODE_REGULAR ); GAMESTATE->m_pCurStyle.Set( GAMEMAN->GameAndStringToStyle( GAMEMAN->GetDefaultGame(),"versus") ); StageStats ss; for( int z = 0; z < 3; ++z ) { ss.vpPlayedSongs.push_back( SONGMAN->GetRandomSong() ); ss.vpPossibleSongs = ss.vpPlayedSongs; ss.pStyle = GAMESTATE->m_pCurStyle; ss.playMode = GAMESTATE->m_PlayMode; ASSERT( ss.vpPlayedSongs[0]->GetAllSteps().size() ); StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType; FOREACH_PlayerNumber( p ) { Steps *pSteps = ss.vpPlayedSongs[0]->GetAllSteps()[0]; ss.m_player[p].vpPlayedSteps.push_back( pSteps ); GAMESTATE->m_pCurSteps[p].Set( pSteps ); ss.m_player[p].iPossibleDancePoints = 100; ss.m_player[p].iActualDancePoints = 100; ss.m_player[p].iScore = 100; ss.m_player[p].iPossibleDancePoints = 1000; ss.m_player[p].iActualDancePoints = 985; ss.m_player[p].vpPossibleSteps.push_back( pSteps ); HighScore hs; hs.SetGrade( Grade_Tier03 ); hs.SetPercentDP( ss.m_player[p].GetPercentDancePoints() ); hs.SetScore( ss.m_player[p].iScore ); hs.SetDateTime( DateTime::GetNowDateTime() ); int a, b; PROFILEMAN->AddStepsScore( ss.vpPlayedSongs[0], pSteps, p, hs, a, b ); PROFILEMAN->AddStepsScore( ss.vpPlayedSongs[0], pSteps, p, hs, a, b ); PROFILEMAN->AddStepsScore( ss.vpPlayedSongs[0], pSteps, p, hs, a, b ); PROFILEMAN->AddStepsScore( ss.vpPlayedSongs[0], pSteps, p, hs, a, b ); PROFILEMAN->AddStepsScore( ss.vpPlayedSongs[0], pSteps, p, hs, a, b ); PROFILEMAN->AddCategoryScore( st, RANKING_A, p, hs, a, b ); } STATSMAN->m_vPlayedStageStats.push_back( ss ); } } } void ScreenNameEntryTraditional::Init() { ALPHABET_GAP_X.Load( m_sName, "AlphabetGapX" ); NUM_ALPHABET_DISPLAYED.Load( m_sName, "NumAlphabetDisplayed" ); MAX_RANKING_NAME_LENGTH.Load( m_sName, "MaxRankingNameLength" ); FEAT_INTERVAL.Load( m_sName, "FeatInterval" ); KEYBOARD_LETTERS.Load( m_sName, "KeyboardLetters" ); ScreenWithMenuElements::Init(); // Find out if players deserve to enter their name FOREACH_PlayerNumber( p ) { vector aFeats; GAMESTATE->GetRankingFeats( p, aFeats ); m_bStillEnteringName[p] = aFeats.size()>0; m_CurFeat[p] = 0; } // // init keyboards // { FOREACH_HumanPlayer( p ) { // don't show keyboard if didn't make any high scores if( !m_bStillEnteringName[p] ) { m_sprOutOfRanking[p].Load( THEME->GetPathG( m_sName,ssprintf("OutOfRankingP%i",p+1)) ); m_sprOutOfRanking[p]->SetName( ssprintf("OutOfRankingP%i",p+1) ); SET_XY_AND_ON_COMMAND( m_sprOutOfRanking[p] ); this->AddChild( m_sprOutOfRanking[p] ); continue; // skip } m_sprNameFrame[p].Load( THEME->GetPathG(m_sName,ssprintf("name frame p%i",p+1)) ); m_sprNameFrame[p]->SetName( ssprintf("EntryFrameP%i",p+1) ); SET_XY_AND_ON_COMMAND( m_sprNameFrame[p] ); this->AddChild( m_sprNameFrame[p] ); m_Keyboard[p].SetName( ssprintf("KeyboardP%i",p+1) ); SET_XY_AND_ON_COMMAND( m_Keyboard[p] ); this->AddChild( &m_Keyboard[p] ); /* Add letters to m_Keyboard. */ const RString sFontPath = THEME->GetPathF(m_sName,"letters"); const wstring sChars = RStringToWstring(KEYBOARD_LETTERS); BitmapText *pLetterTemplate = new BitmapText; pLetterTemplate->SetName( "Letter" ); pLetterTemplate->LoadFromFont( sFontPath ); ActorUtil::LoadAllCommands( *pLetterTemplate, m_sName ); pLetterTemplate->PlayCommand( "AlphabetInit" ); for( unsigned ch = 0; ch < sChars.size(); ++ch ) { BitmapText *pLetter = new BitmapText( *pLetterTemplate ); pLetter->SetText( ssprintf("%lc", sChars[ch]) ); m_textAlphabet[p].push_back( pLetter ); m_Keyboard[p].AddChild( pLetter ); m_AlphabetLetter[p].push_back( sChars[ch] ); } delete pLetterTemplate; /* Add "<-". */ { BitmapText *pLetter = new BitmapText; pLetter->SetName( ssprintf("LetterP%i",p+1) ); ActorUtil::LoadAllCommands( *pLetter, m_sName ); pLetter->LoadFromFont( sFontPath ); RString sText = "←"; FontCharAliases::ReplaceMarkers( sText ); pLetter->SetText( sText ); pLetter->PlayCommand( "OKInit" ); m_textAlphabet[p].push_back( pLetter ); m_Keyboard[p].AddChild( pLetter ); m_AlphabetLetter[p].push_back( CHAR_BACK ); } /* Add "OK". */ { BitmapText *pLetter = new BitmapText; pLetter->SetName( ssprintf("LetterP%i",p+1) ); ActorUtil::LoadAllCommands( *pLetter, m_sName ); pLetter->LoadFromFont( sFontPath ); RString sText = "&ok;"; FontCharAliases::ReplaceMarkers( sText ); pLetter->SetText( sText ); pLetter->PlayCommand( "OKInit" ); m_textAlphabet[p].push_back( pLetter ); m_Keyboard[p].AddChild( pLetter ); m_AlphabetLetter[p].push_back( CHAR_OK ); } m_sprCursor[p].SetName( ssprintf("CursorP%i",p+1) ); m_sprCursor[p].Load( THEME->GetPathG(m_sName,ssprintf("cursor p%i",p+1)) ); m_Keyboard[p].AddChild( &m_sprCursor[p] ); m_textSelection[p].SetName( ssprintf("SelectionP%i",p+1) ); m_textSelection[p].LoadFromFont( THEME->GetPathF(m_sName,"entry") ); SET_XY_AND_ON_COMMAND( m_textSelection[p] ); this->AddChild( &m_textSelection[p] ); m_SelectedChar[p] = 0; PositionCharsAndCursor( p ); // load last used ranking name if any const Profile* pProfile = PROFILEMAN->GetProfile(p); if( pProfile && !pProfile->m_sLastUsedHighScoreName.empty() ) { m_sSelection[p] = RStringToWstring( pProfile->m_sLastUsedHighScoreName ); if( (int) m_sSelection[p].size() > MAX_RANKING_NAME_LENGTH ) m_sSelection[p].erase( MAX_RANKING_NAME_LENGTH ); ASSERT( (int) m_sSelection[p].size() <= MAX_RANKING_NAME_LENGTH ); if( m_sSelection[p].size() ) SelectChar( p, CHAR_OK, false ); } UpdateSelectionText( p ); /* Don't tween to the initial position. */ for( unsigned i = 0; i < m_textAlphabet[p].size(); ++i ) m_textAlphabet[p][i]->FinishTweening(); } } // // init feat displays // FOREACH_HumanPlayer( p ) { /* Show feat 0, hide others without tweening. Run the ON command for * all actors, even if we're going to hide it anyway, so any style commands * are run. */ #define SET_ON( actor ) \ SET_XY_AND_ON_COMMAND( actor ); \ if( m_FeatDisplay[p].size()>1 ) \ { \ (actor).FinishTweening(); \ COMMAND( actor, "Hide" ); \ (actor).FinishTweening(); \ } m_FeatDisplay[p].reserve( STATSMAN->m_vPlayedStageStats.size() ); for( unsigned i = 0; i < STATSMAN->m_vPlayedStageStats.size(); ++i ) { StageStats &ss = STATSMAN->m_vPlayedStageStats[i]; Song* pSong = ss.vpPlayedSongs[0]; Steps* pSteps = ss.m_player[p].vpPlayedSteps[0]; Course* pCourse = GAMESTATE->m_pCurCourse; Trail* pTrail = GAMESTATE->m_pCurTrail[p]; int iHighScoreIndex = -1; // -1 means "out of ranking" Grade grade = ss.m_player[p].GetGrade(); int iScore = ss.m_player[p].iScore; float fPercentDP = ss.m_player[p].GetPercentDancePoints(); // If this is a SHOW_NEVER song, then it's probably a training. // Don't show a high score if( pSong->m_SelectionDisplay == Song::SHOW_NEVER ) continue; // skip m_FeatDisplay[p].resize( m_FeatDisplay[p].size()+1 ); FeatDisplay &display = m_FeatDisplay[p].back(); const HighScoreList& hsl = GAMESTATE->IsCourseMode() ? PROFILEMAN->GetMachineProfile()->GetCourseHighScoreList(pCourse,pTrail) : PROFILEMAN->GetMachineProfile()->GetStepsHighScoreList(pSong,pSteps); for( int h=0; h<(int)hsl.vHighScores.size() && hm_iMaxHighScoresPerListForMachine; h++ ) { const HighScore &hs = hsl.vHighScores[h]; if( hs.GetName() == RANKING_TO_FILL_IN_MARKER[p] && hs.GetPercentDP() == fPercentDP && hs.GetScore() == iScore ) { iHighScoreIndex = h; break; } } display.m_Wheel.SetName( ssprintf("WheelP%i",p+1) ); display.m_Wheel.Load( hsl, iHighScoreIndex ); SET_ON( display.m_Wheel ); this->AddChild( &display.m_Wheel ); RString sBanner; if( GAMESTATE->IsCourseMode() ) sBanner = pCourse->m_sBannerPath; else sBanner = pSong->GetBannerPath(); if( !sBanner.empty() ) { display.m_sprBanner.SetName( ssprintf("BannerP%i",p+1) ); display.m_sprBanner.Load( sBanner ); SET_ON( display.m_sprBanner ); this->AddChild( &display.m_sprBanner ); } if( grade != Grade_NoData ) { display.m_Grade.SetName( ssprintf("GradeP%i",p+1) ); display.m_Grade.Load( THEME->GetPathG(m_sName,"grades") ); display.m_Grade.SetGrade( p, grade ); SET_ON( display.m_Grade ); this->AddChild( &display.m_Grade ); } display.m_DifficultyIcon.Load( THEME->GetPathG(m_sName,"DifficultyIcon") ); if( GAMESTATE->IsCourseMode() ) display.m_DifficultyIcon.SetFromTrail( p, pTrail ); else display.m_DifficultyIcon.SetFromSteps( p, pSteps ); display.m_DifficultyIcon.SetName( ssprintf("DifficultyIconP%i",p+1) ); SET_ON( display.m_DifficultyIcon ); this->AddChild( &display.m_DifficultyIcon ); display.m_DifficultyMeter.Load( m_sName+ssprintf(" DifficultyMeterP%d",p+1) ); if( GAMESTATE->IsCourseMode() ) display.m_DifficultyMeter.SetFromTrail( pTrail ); else display.m_DifficultyMeter.SetFromSteps( pSteps ); display.m_DifficultyMeter.SetName( ssprintf("DifficultyMeterP%i",p+1) ); SET_ON( display.m_DifficultyMeter ); this->AddChild( &display.m_DifficultyMeter ); display.m_textScore.Load( GAMESTATE->m_pPlayerState[p], &ss.m_player[p], "ScreenNameEntryTraditional Percent", false ); display.m_textScore.SetName( ssprintf("ScoreP%i",p+1) ); SET_ON( display.m_textScore ); this->AddChild( &display.m_textScore ); // if( feat.Feat != "" ) // { // display.m_textCategory.SetName( ssprintf("CategoryP%i", p+1) ); // display.m_textCategory.LoadFromFont( THEME->GetPathF(m_sName, "category") ); // display.m_textCategory.SetText( feat.Feat ); // SET_ON( display.m_textCategory ); // this->AddChild( &display.m_textCategory ); // } /* We always show the banner frame (if any), because fading from a graphic to * itself is ugly. */ display.m_sprBannerFrame.Load( THEME->GetPathG(m_sName,ssprintf("banner frame p%i",p+1)) ); display.m_sprBannerFrame->SetName( ssprintf("BannerFrameP%i",p+1) ); SET_XY_AND_ON_COMMAND( display.m_sprBannerFrame ); this->AddChild( display.m_sprBannerFrame ); } #undef SET_ON } this->PostScreenMessage( SM_ChangeDisplayedFeat, FEAT_INTERVAL ); m_soundKey.Load( THEME->GetPathS(m_sName,"key") ); m_soundChange.Load( THEME->GetPathS(m_sName,"change",true) ); m_soundInvalid.Load( THEME->GetPathS(m_sName,"invalid",true) ); this->SortByDrawOrder(); } static inline int wrapn( int x, int n ) { wrap( x, n ); return x; } void ScreenNameEntryTraditional::PositionCharsAndCursor( int pn ) { const int iSelected = m_SelectedChar[pn]; const int iNumDisplayed = NUM_ALPHABET_DISPLAYED; const int iTotalDisplayed = (int)m_textAlphabet[pn].size(); const int iStart = wrapn( iSelected - iTotalDisplayed/2, iTotalDisplayed ); const int iFirst = -iNumDisplayed/2; const int iLast = iNumDisplayed/2; for( int i = 0; i < (int)m_textAlphabet[pn].size(); ++i ) { const int iNum = wrapn( iStart+i, (int) m_textAlphabet[pn].size() ); BitmapText *bt = m_textAlphabet[pn][iNum]; const int iPos = i - iTotalDisplayed/2; const bool bHidden = ( iPos < iFirst || iPos > iLast ); const int iActualPos = clamp( iPos, iFirst-1, iLast+1 ); bt->PlayCommand( "Change" ); bt->SetX( iActualPos * ALPHABET_GAP_X ); bt->SetDiffuseAlpha( bHidden? 0.0f:1.0f ); } m_sprCursor[pn].SetXY( 0,0 ); } bool ScreenNameEntryTraditional::AnyStillEntering() const { FOREACH_PlayerNumber( p ) if( m_bStillEnteringName[p] ) return true; return false; } ScreenNameEntryTraditional::~ScreenNameEntryTraditional() { LOG->Trace( "ScreenNameEntryTraditional::~ScreenNameEntryTraditional()" ); for( int p=0; pPlayOnceFromDir( ANNOUNCER->GetPathTo("name entry") ); ScreenWithMenuElements::Update(fDelta); } void ScreenNameEntryTraditional::Input( const InputEventPlus &input ) { if( IsTransitioning() ) return; if( input.type == IET_FIRST_PRESS ) { int c; if( input.DeviceI == DeviceInput(DEVICE_KEYBOARD, KEY_BACK) ) { c = CHAR_BACK; } else { wchar_t ch = INPUTMAN->DeviceInputToChar(input.DeviceI,true); MakeUpper( &ch, 1 ); c = ch; } if( c ) { PlayerNumber pn = GAMESTATE->m_MasterPlayerNumber; bool bChanged = SelectChar( pn, c, true ); if( bChanged ) { m_soundChange.Play(); HandleStart( GAMESTATE->m_MasterPlayerNumber ); } return; } } ScreenWithMenuElements::Input( input ); } void ScreenNameEntryTraditional::ChangeDisplayedFeat() { CHECKPOINT; LOG->Trace( "ScreenNameEntryTraditional::ChangeDisplayedFeat" ); FOREACH_HumanPlayer( pn ) { if( m_FeatDisplay[pn].size() < 2 ) continue; int NewFeat = (m_CurFeat[pn]+1) % m_FeatDisplay[pn].size(); int OldFeat = m_CurFeat[pn]; m_CurFeat[pn] = NewFeat; COMMAND_OPTIONAL( m_FeatDisplay[pn][OldFeat].m_Wheel, "Hide" ); COMMAND_OPTIONAL( m_FeatDisplay[pn][NewFeat].m_Wheel, "Unhide" ); COMMAND_OPTIONAL( m_FeatDisplay[pn][OldFeat].m_Grade, "Hide" ); COMMAND_OPTIONAL( m_FeatDisplay[pn][NewFeat].m_Grade, "Unhide" ); COMMAND_OPTIONAL( m_FeatDisplay[pn][OldFeat].m_DifficultyIcon, "Hide" ); COMMAND_OPTIONAL( m_FeatDisplay[pn][NewFeat].m_DifficultyIcon, "Unhide" ); COMMAND_OPTIONAL( m_FeatDisplay[pn][OldFeat].m_DifficultyMeter, "Hide" ); COMMAND_OPTIONAL( m_FeatDisplay[pn][NewFeat].m_DifficultyMeter, "Unhide" ); COMMAND_OPTIONAL( m_FeatDisplay[pn][OldFeat].m_sprBanner, "Hide" ); COMMAND_OPTIONAL( m_FeatDisplay[pn][NewFeat].m_sprBanner, "Unhide" ); COMMAND_OPTIONAL( m_FeatDisplay[pn][OldFeat].m_textScore, "Hide" ); COMMAND_OPTIONAL( m_FeatDisplay[pn][NewFeat].m_textScore, "Unhide" ); COMMAND_OPTIONAL( m_FeatDisplay[pn][OldFeat].m_textCategory, "Hide" ); COMMAND_OPTIONAL( m_FeatDisplay[pn][NewFeat].m_textCategory, "Unhide" ); m_FeatDisplay[pn][NewFeat].m_Wheel.Scroll(); } } void ScreenNameEntryTraditional::HandleScreenMessage( const ScreenMessage SM ) { LOG->Trace( "ScreenNameEntryTraditional::HandleScreenMessage( %d )", SM ); if( SM == SM_MenuTimer ) { if( !m_Out.IsTransitioning() ) { FOREACH_PlayerNumber( p ) Finish( p ); HandleStart( PLAYER_INVALID ); } } else if( SM == SM_ChangeDisplayedFeat ) { ChangeDisplayedFeat(); this->PostScreenMessage( SM_ChangeDisplayedFeat, FEAT_INTERVAL ); } ScreenWithMenuElements::HandleScreenMessage( SM ); } void ScreenNameEntryTraditional::Finish( PlayerNumber pn ) { if( !m_bStillEnteringName[pn] ) return; m_bStillEnteringName[pn] = false; UpdateSelectionText( pn ); /* hide NAME_ cursor */ RString sSelection = WStringToRString( m_sSelection[pn] ); // save last used ranking name Profile* pProfile = PROFILEMAN->GetProfile(pn); pProfile->m_sLastUsedHighScoreName = sSelection; TrimRight( sSelection, " " ); TrimLeft( sSelection, " " ); GAMESTATE->StoreRankingName( pn, sSelection ); OFF_COMMAND( m_Keyboard[pn] ); for( int i = 0; i < (int)m_textAlphabet[pn].size(); ++i ) OFF_COMMAND( m_textAlphabet[pn][i] ); OFF_COMMAND( m_sprCursor[pn] ); if( !AnyStillEntering() ) AllFinished(); } void ScreenNameEntryTraditional::UpdateSelectionText( int pn ) { wstring text = m_sSelection[pn]; if( m_bStillEnteringName[pn] && (int) text.size() < MAX_RANKING_NAME_LENGTH ) text += L"_"; m_textSelection[pn].SetText( WStringToRString(text) ); } void ScreenNameEntryTraditional::MenuStart( const InputEventPlus &input ) { HandleStart( input.pn ); } void ScreenNameEntryTraditional::HandleStart( PlayerNumber pn ) { /* The screen may have started out with nobody entering, in which case we're * just showing scores and the first Start press moves on. */ if( !AnyStillEntering() ) { AllFinished(); return; } if( !m_bStillEnteringName[pn] ) return; // ignore const int iCurrentSelection = m_SelectedChar[pn]; const int iSelectedLetter = m_AlphabetLetter[pn][iCurrentSelection]; switch( iSelectedLetter ) { case CHAR_OK: m_soundKey.Play(); Finish( pn ); break; case CHAR_BACK: Backspace( pn ); break; default: /* If we have room, add a new character. */ if( (int) m_sSelection[pn].size() == MAX_RANKING_NAME_LENGTH ) { m_soundInvalid.Play(); SelectChar( pn, CHAR_BACK, false ); break; } m_sSelection[pn] += wchar_t(iSelectedLetter); UpdateSelectionText( pn ); m_soundKey.Play(); /* If that filled the string, set the cursor on OK. */ if( (int) m_sSelection[pn].size() == MAX_RANKING_NAME_LENGTH ) SelectChar( pn, CHAR_OK, false ); } } void ScreenNameEntryTraditional::MenuSelect( const InputEventPlus &input ) { if( !m_bStillEnteringName[input.pn] ) return; // ignore Backspace( input.pn ); } bool ScreenNameEntryTraditional::SelectChar( PlayerNumber pn, int c, bool bOptional ) { FOREACH( int, m_AlphabetLetter[pn], letter ) { if( *letter == c ) // character found { m_SelectedChar[pn] = letter - m_AlphabetLetter[pn].begin(); PositionCharsAndCursor( pn ); return true; } } if( !bOptional ) ASSERT( false ); // character not found return false; } void ScreenNameEntryTraditional::Backspace( PlayerNumber pn ) { if( !m_sSelection[pn].size() ) { m_soundInvalid.Play(); return; } m_sSelection[pn].erase( m_sSelection[pn].size()-1, 1 ); UpdateSelectionText( pn ); m_soundKey.Play(); } void ScreenNameEntryTraditional::MenuLeft( const InputEventPlus &input ) { PlayerNumber pn = input.pn; if( !m_bStillEnteringName[pn] || IsTransitioning() ) return; --m_SelectedChar[pn]; wrap( m_SelectedChar[pn], m_textAlphabet[pn].size() ); PositionCharsAndCursor( pn ); m_soundChange.Play(); } void ScreenNameEntryTraditional::MenuRight( const InputEventPlus &input ) { PlayerNumber pn = input.pn; if( !m_bStillEnteringName[pn] || IsTransitioning() ) return; ++m_SelectedChar[pn]; wrap( m_SelectedChar[pn], m_textAlphabet[pn].size() ); PositionCharsAndCursor( pn ); m_soundChange.Play(); } void ScreenNameEntryTraditional::AllFinished() { StartTransitioningScreen( SM_GoToNextScreen ); FOREACH_HumanPlayer( pn ) { OFF_COMMAND( m_sprOutOfRanking[pn] ); OFF_COMMAND( m_sprNameFrame[pn] ); OFF_COMMAND( m_textSelection[pn] ); } } /* * (c) 2001-2004 Glenn Maynard, Chris Danford * 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. */