#include "global.h" /* ----------------------------------------------------------------------------- Class: ScreenNameEntry Desc: See header. Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved. Chris Danford ----------------------------------------------------------------------------- */ #include "ScreenNameEntry.h" #include "SongManager.h" #include "ScreenManager.h" #include "GameConstantsAndTypes.h" #include "RageUtil.h" #include "PrefsManager.h" #include "GameManager.h" #include "RageLog.h" #include "GameState.h" #include "RageSounds.h" #include "ThemeManager.h" #include "ScreenRanking.h" #include "Course.h" #include // // Defines specific to ScreenNameEntry // #define TIMER_X THEME->GetMetricF("ScreenNameEntry","TimerX") #define TIMER_Y THEME->GetMetricF("ScreenNameEntry","TimerY") #define CATEGORY_Y THEME->GetMetricF("ScreenNameEntry","CategoryY") #define CHARS_ZOOM_SMALL THEME->GetMetricF("ScreenNameEntry","CharsZoomSmall") #define CHARS_ZOOM_LARGE THEME->GetMetricF("ScreenNameEntry","CharsZoomLarge") #define CHARS_SPACING_Y THEME->GetMetricF("ScreenNameEntry","CharsSpacingY") #define SCROLLING_CHARS_COLOR THEME->GetMetricC("ScreenNameEntry","ScrollingCharsColor") #define SELECTED_CHARS_COLOR THEME->GetMetricC("ScreenNameEntry","SelectedCharsColor") #define GRAY_ARROWS_Y THEME->GetMetricF("ScreenNameEntry","GrayArrowsY") #define NUM_CHARS_TO_DRAW_BEHIND THEME->GetMetricI("ScreenNameEntry","NumCharsToDrawBehind") #define NUM_CHARS_TO_DRAW_TOTAL THEME->GetMetricI("ScreenNameEntry","NumCharsToDrawTotal") #define FAKE_BEATS_PER_SEC THEME->GetMetricF("ScreenNameEntry","FakeBeatsPerSec") #define TIMER_SECONDS THEME->GetMetricI("ScreenNameEntry","TimerSeconds") // cache for frequently used metrics float g_fCharsZoomSmall; float g_fCharsZoomLarge; float g_fCharsSpacingY; RageColor g_ScrollingCharsColor; RageColor g_SelectedCharsColor; float g_fGrayArrowsY; int g_iNumCharsToDrawBehind; int g_iNumCharsToDrawTotal; float g_fFakeBeatsPerSec; const char NAME_CHARS[] = { ' ',' ',' ',' ','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z' }; #define NUM_NAME_CHARS (ARRAYSIZE(NAME_CHARS)) #define HEIGHT_OF_ALL_CHARS (NUM_NAME_CHARS * g_fCharsSpacingY) int GetClosestCharIndex( float fFakeBeat ) { int iCharIndex = (int)roundf(fFakeBeat) % NUM_NAME_CHARS; ASSERT( iCharIndex >= 0 ); return iCharIndex; } // return value is relative to gray arrows float GetClosestCharYOffset( float fFakeBeat ) { float f = fmodf(fFakeBeat, 1.0f); if( f > 0.5f ) f -= 1; ASSERT( f>-0.5f && f<=0.5f ); return -f; } // return value is relative to gray arrows float GetClosestCharYPos( float fFakeBeat ) { return GetClosestCharYOffset(fFakeBeat)*g_fCharsSpacingY; } ScreenNameEntry::ScreenNameEntry( CString sClassName ) : Screen( sClassName ) { LOG->Trace( "ScreenNameEntry::ScreenNameEntry()" ); // update cache g_fCharsZoomSmall = CHARS_ZOOM_SMALL; g_fCharsZoomLarge = CHARS_ZOOM_LARGE; g_fCharsSpacingY = CHARS_SPACING_Y; g_ScrollingCharsColor = SCROLLING_CHARS_COLOR; g_SelectedCharsColor = SELECTED_CHARS_COLOR; g_fGrayArrowsY = GRAY_ARROWS_Y; g_iNumCharsToDrawBehind = NUM_CHARS_TO_DRAW_BEHIND; g_iNumCharsToDrawTotal = NUM_CHARS_TO_DRAW_TOTAL; g_fFakeBeatsPerSec = FAKE_BEATS_PER_SEC; // DEBUGGING STUFF // GAMESTATE->m_CurGame = GAME_DANCE; // GAMESTATE->m_CurStyle = STYLE_DANCE_SINGLE; // GAMESTATE->m_PlayMode = PLAY_MODE_ARCADE; // GAMESTATE->m_bSideIsJoined[PLAYER_1] = true; // GAMESTATE->m_MasterPlayerNumber = PLAYER_1; // GAMESTATE->m_RankingCategory[PLAYER_1] = RANKING_A; // GAMESTATE->m_iRankingIndex[PLAYER_1] = 0; /* Save options. We'll reset them to display letters, and we must put them * back when we're done. */ GAMESTATE->StoreSelectedOptions(); // reset Player and Song Options { for( int p=0; pm_PlayerOptions[p] = PlayerOptions(); GAMESTATE->m_SongOptions = SongOptions(); } GAMESTATE->m_bPastHereWeGo = true; // enable the gray arrows m_Background.LoadFromAniDir( THEME->GetPathToB("ScreenNameEntry background") ); this->AddChild( &m_Background ); for( int p=0; pm_iRankingIndex[p] != -1; m_bStillEnteringName[p] = bNewHighScore; // false if they made a new high score for( int i=0; im_PlayerOptions[p] = PlayerOptions(); ASSERT( GAMESTATE->IsHumanPlayer(p) ); // they better be enabled if they made a high score! m_GrayArrowRow[p].Load( (PlayerNumber)p ); m_GrayArrowRow[p].SetX( (float)GAMESTATE->GetCurrentStyleDef()->m_iCenterX[p] ); m_GrayArrowRow[p].SetY( SCREEN_TOP + 100 ); this->AddChild( &m_GrayArrowRow[p] ); const StyleDef* pStyleDef = GAMESTATE->GetCurrentStyleDef(); m_ColToStringIndex[p].insert(m_ColToStringIndex[p].begin(), pStyleDef->m_iColsPerPlayer, -1); int CurrentStringIndex = 0; for( int t=0; tm_iColsPerPlayer; t++ ) { if(CurrentStringIndex == MAX_RANKING_NAME_LENGTH) continue; /* We have enough columns. */ /* Find out if this column is associated with the START menu button. */ StyleInput si((PlayerNumber)p, t); GameInput gi=GAMESTATE->GetCurrentStyleDef()->StyleInputToGameInput(si); MenuInput m=GAMESTATE->GetCurrentGameDef()->GameInputToMenuInput(gi); if(m.button == MENU_BUTTON_START) continue; m_ColToStringIndex[p][t] = CurrentStringIndex++; float ColX = pStyleDef->m_iCenterX[p] + pStyleDef->m_ColumnInfo[p][t].fXOffset; m_textSelectedChars[p][t].LoadFromFont( THEME->GetPathToF("ScreenNameEntry letters") ); m_textSelectedChars[p][t].SetX( ColX ); m_textSelectedChars[p][t].SetY( GRAY_ARROWS_Y ); m_textSelectedChars[p][t].SetDiffuse( g_SelectedCharsColor ); m_textSelectedChars[p][t].SetZoom( CHARS_ZOOM_LARGE ); this->AddChild( &m_textSelectedChars[p][t] ); // draw these manually m_textScrollingChars[p][t].LoadFromFont( THEME->GetPathToF("ScreenNameEntry letters") ); m_textScrollingChars[p][t].SetX( ColX ); m_textScrollingChars[p][t].SetY( GRAY_ARROWS_Y ); m_textScrollingChars[p][t].SetDiffuse( g_ScrollingCharsColor ); //this->AddChild( &m_textScrollingChars[p][t] ); // draw these manually } m_textCategory[p].LoadFromFont( THEME->GetPathToF("ScreenNameEntry category") ); m_textCategory[p].SetX( (float)GAMESTATE->GetCurrentStyleDef()->m_iCenterX[p] ); m_textCategory[p].SetY( CATEGORY_Y ); CString sCategoryText = ssprintf("No. %d in\n", GAMESTATE->m_iRankingIndex[p]+1); switch( GAMESTATE->m_PlayMode ) { case PLAY_MODE_ARCADE: case PLAY_MODE_BATTLE: case PLAY_MODE_RAVE: { StageStats SS; vector vSongs; GAMESTATE->GetFinalEvalStatsAndSongs( SS, vSongs ); sCategoryText += ssprintf("Type %c (%d)", 'A'+GAMESTATE->m_RankingCategory[p], SS.iMeter[p] ); } break; case PLAY_MODE_NONSTOP: case PLAY_MODE_ONI: case PLAY_MODE_ENDLESS: sCategoryText += ssprintf("%s", GAMESTATE->m_pCurCourse->m_sName.c_str()); break; default: ASSERT(0); } m_textCategory[p].SetText( sCategoryText ); this->AddChild( &m_textCategory[p] ); } bool bAnyStillEntering = false; { for( int p=0; pm_bMenuTimer ) m_Timer.Disable(); else m_Timer.SetSeconds(TIMER_SECONDS); m_Timer.SetXY( TIMER_X, TIMER_Y ); this->AddChild( &m_Timer ); m_In.Load( THEME->GetPathToB("ScreenNameEntry in") ); m_In.StartTransitioning(); // this->AddChild( &m_In ); // draw and update this manually too m_Out.Load( THEME->GetPathToB("ScreenNameEntry out") ); // this->AddChild( &m_Out ); // draw and update this manually too m_soundStep.Load( THEME->GetPathToS("ScreenNameEntry step") ); SOUND->PlayMusic( THEME->GetPathToS("ScreenNameEntry music") ); m_fFakeBeat = 0; } ScreenNameEntry::~ScreenNameEntry() { LOG->Trace( "ScreenNameEntry::~ScreenNameEntry()" ); } void ScreenNameEntry::Update( float fDelta ) { m_fFakeBeat += fDelta * FAKE_BEATS_PER_SEC; GAMESTATE->m_fSongBeat = m_fFakeBeat; Screen::Update(fDelta); m_In.Update( fDelta ); m_Out.Update( fDelta ); } void ScreenNameEntry::DrawPrimitives() { Screen::DrawPrimitives(); int iClosestIndex = GetClosestCharIndex( m_fFakeBeat ); int iStartDrawingIndex = iClosestIndex - NUM_CHARS_TO_DRAW_BEHIND; iStartDrawingIndex += NUM_NAME_CHARS; // make positive const StyleDef* pStyleDef = GAMESTATE->GetCurrentStyleDef(); for( int p=0; pm_iColsPerPlayer; t++ ) { if(m_ColToStringIndex[p][t] == -1) continue; m_textScrollingChars[p][t].SetText( ssprintf("%c",c) ); // why doens't CStdStr have a contructor that takes a char? m_textScrollingChars[p][t].SetY( fY ); float fZoom = g_fCharsZoomSmall; if( iCharIndex==iClosestIndex ) fZoom = SCALE(fabsf(GetClosestCharYOffset(m_fFakeBeat)),0,0.5f,g_fCharsZoomLarge,g_fCharsZoomSmall); m_textScrollingChars[p][t].SetZoom(fZoom); RageColor color = g_ScrollingCharsColor; if( i==0 ) color.a *= SCALE(GetClosestCharYOffset(m_fFakeBeat),-0.5f,0.f,0.f,1.f); if( i==g_iNumCharsToDrawTotal-1 ) color.a *= SCALE(GetClosestCharYOffset(m_fFakeBeat),0.f,0.5f,1.f,0.f); m_textScrollingChars[p][t].SetDiffuse( color ); m_textScrollingChars[p][t].Draw(); } fY += g_fCharsSpacingY; iCharIndex = (iCharIndex+1) % NUM_NAME_CHARS; } for( int t=0; tm_iColsPerPlayer; t++ ) { m_textSelectedChars[p][t].Draw(); } } m_In.Draw(); m_Out.Draw(); } void ScreenNameEntry::Input( const DeviceInput& DeviceI, const InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI ) { LOG->Trace( "ScreenNameEntry::Input()" ); if( m_In.IsTransitioning() || m_Out.IsTransitioning() ) return; if( type != IET_FIRST_PRESS ) return; // ignore if( StyleI.IsValid() && m_bStillEnteringName[StyleI.player]) { int StringIndex = m_ColToStringIndex[StyleI.player][StyleI.col]; if(StringIndex != -1) { m_GrayArrowRow[StyleI.player].Step( StyleI.col ); m_soundStep.Play(); char c = NAME_CHARS[GetClosestCharIndex(m_fFakeBeat)]; m_textSelectedChars[StyleI.player][StyleI.col].SetText( ssprintf("%c",c) ); m_sSelectedName[StyleI.player][StringIndex] = c; } } Screen::Input( DeviceI, type, GameI, MenuI, StyleI ); } void ScreenNameEntry::HandleScreenMessage( const ScreenMessage SM ) { switch( SM ) { case SM_MenuTimer: if( !m_Out.IsTransitioning() ) { for( int p=0; pMenuStart( (PlayerNumber)p ); } break; case SM_GoToNextScreen: { GAMESTATE->RestoreSelectedOptions(); Grade max_grade = GRADE_E; vector vSongs; StageStats stats; GAMESTATE->GetFinalEvalStatsAndSongs( stats, vSongs ); /* Hack: go back to the select course screen in event mode. */ if( PREFSMAN->m_bEventMode && GAMESTATE->IsCourseMode() ) { SCREENMAN->SetNewScreen( "ScreenSelectCourse" ); break; } for( int p=0; pIsHumanPlayer(p) ) max_grade = max( max_grade, stats.GetGrade((PlayerNumber)p) ); if( max_grade >= GRADE_AA ) SCREENMAN->SetNewScreen( "ScreenCredits" ); else SCREENMAN->SetNewScreen( "ScreenMusicScroll" ); } break; } } void ScreenNameEntry::MenuStart( PlayerNumber pn ) { if( !m_bStillEnteringName[pn] ) return; m_bStillEnteringName[pn] = false; m_soundStep.Play(); TrimRight( m_sSelectedName[pn], " " ); TrimLeft( m_sSelectedName[pn], " " ); if( m_sSelectedName[pn] == "" ) m_sSelectedName[pn] = DEFAULT_RANKING_NAME; if( GAMESTATE->IsCourseMode() ) { GAMESTATE->m_pRankingCourse->m_RankingScores[GAMESTATE->m_RankingNotesType][GAMESTATE->m_iRankingIndex[pn]].sName = m_sSelectedName[pn]; } else { SONGMAN->m_MachineScores[GAMESTATE->m_RankingNotesType][GAMESTATE->m_RankingCategory[pn]][GAMESTATE->m_iRankingIndex[pn]].sName = m_sSelectedName[pn]; } bool bAnyStillEntering = false; for( int p=0; p