#include "stdafx.h" /* ----------------------------------------------------------------------------- Class: ScreenGameplay Desc: See header. Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved. Chris Danford ----------------------------------------------------------------------------- */ #include "ScreenGameplay.h" #include "SongManager.h" #include "ScreenManager.h" #include "ScreenSelectMusic.h" #include "ScreenResults.h" #include "GameConstantsAndTypes.h" #include "ThemeManager.h" #include "GameManager.h" #include "SongManager.h" #include "RageLog.h" #include "AnnouncerManager.h" #include "ScreenGameOver.h" // // Defines specific to GameScreenTitleMenu // const float LIFE_X[NUM_PLAYERS] = { CENTER_X-180, CENTER_X+180 }; const float LIFE_Y = SCREEN_TOP+28; const float SCORE_X[NUM_PLAYERS] = { CENTER_X-214, CENTER_X+214 }; const float SCORE_Y = SCREEN_BOTTOM-38; const float DIFFICULTY_X[NUM_PLAYERS] = { SCREEN_LEFT+50, SCREEN_RIGHT-50 }; const float DIFFICULTY_Y = SCREEN_BOTTOM-80; const float MAX_SECONDS_CAN_BE_OFF_BY = 0.20f; const float TIME_BETWEEN_DANCING_COMMENTS = 15; // received while STATE_DANCING const ScreenMessage SM_SongEnded = ScreenMessage(SM_User+102); const ScreenMessage SM_LifeIs0 = ScreenMessage(SM_User+103); // received while STATE_OUTRO const ScreenMessage SM_ShowCleared = ScreenMessage(SM_User+111); const ScreenMessage SM_HideCleared = ScreenMessage(SM_User+112); const ScreenMessage SM_GoToResults = ScreenMessage(SM_User+113); const ScreenMessage SM_BeginFailed = ScreenMessage(SM_User+121); const ScreenMessage SM_ShowFailed = ScreenMessage(SM_User+122); const ScreenMessage SM_PlayFailComment = ScreenMessage(SM_User+123); const ScreenMessage SM_HideFailed = ScreenMessage(SM_User+124); const ScreenMessage SM_GoToScreenAfterFail = ScreenMessage(SM_User+125); ScreenGameplay::ScreenGameplay() { LOG->WriteLine( "ScreenGameplay::ScreenGameplay()" ); m_DancingState = STATE_INTRO; m_fTimeLeftBeforeDancingComment = TIME_BETWEEN_DANCING_COMMENTS; m_bHasFailed = false; m_pSong = SONGMAN->m_pCurSong; m_Background.LoadFromSong( SONGMAN->m_pCurSong ); m_Background.SetDiffuseColor( D3DXCOLOR(0.4f,0.4f,0.4f,1) ); this->AddActor( &m_Background ); // Get the current StyleDef definition (used below) StyleDef* pStyleDef = GAMEMAN->GetCurrentStyleDef(); for( int p=0; pIsPlayerEnabled(PlayerNumber(p)) ) continue; float fDifficultyY = DIFFICULTY_Y; if( PREFSMAN->m_PlayerOptions[p].m_bReverseScroll ) fDifficultyY = SCREEN_HEIGHT - DIFFICULTY_Y; m_DifficultyBanner[p].SetXY( DIFFICULTY_X[p], fDifficultyY ); m_DifficultyBanner[p].SetFromNotes( SONGMAN->m_pCurNotes[p] ); this->AddActor( &m_DifficultyBanner[p] ); NoteData* pOriginalNoteData = SONGMAN->m_pCurNotes[p]->GetNoteData(); NoteData newNoteData; GAMEMAN->GetCurrentStyleDef()->GetTransformedNoteDataForStyle( (PlayerNumber)p, pOriginalNoteData, newNoteData ); m_Player[p].SetX( (float) GAMEMAN->GetCurrentStyleDef()->m_iCenterX[p] ); m_Player[p].Load( (PlayerNumber)p, GAMEMAN->GetCurrentStyleDef(), &newNoteData, PREFSMAN->m_PlayerOptions[p], &m_LifeMeter[p], &m_ScoreDisplay[p] ); this->AddActor( &m_Player[p] ); } for( p=0; pIsPlayerEnabled(PlayerNumber(p)) ) continue; m_LifeMeter[p].SetPlayerOptions( PREFSMAN->m_PlayerOptions[p] ); m_LifeMeter[p].SetXY( LIFE_X[p], LIFE_Y ); m_LifeMeter[p].SetZoomX( 256 ); m_LifeMeter[p].SetZoomY( 20 ); this->AddActor( &m_LifeMeter[p] ); } m_sprTopFrame.Load( THEME->GetPathTo(GRAPHIC_GAMEPLAY_TOP_FRAME) ); m_sprTopFrame.SetXY( CENTER_X, SCREEN_TOP + m_sprTopFrame.GetZoomedHeight()/2 ); this->AddActor( &m_sprTopFrame ); m_sprBottomFrame.Load( THEME->GetPathTo(GRAPHIC_GAMEPLAY_BOTTOM_FRAME) ); m_sprBottomFrame.SetXY( CENTER_X, SCREEN_BOTTOM - m_sprBottomFrame.GetZoomedHeight()/2 ); this->AddActor( &m_sprBottomFrame ); m_textSmallStage.Load( THEME->GetPathTo(FONT_HEADER1) ); m_textSmallStage.TurnShadowOff(); m_textSmallStage.SetXY( CENTER_X, 60 ); m_textSmallStage.SetDiffuseColor( D3DXCOLOR(0.3f,1,1,1) ); m_textSmallStage.SetText( PREFSMAN->GetStageText() ); this->AddActor( &m_textSmallStage ); for( p=0; pIsPlayerEnabled(PlayerNumber(p)) ) continue; m_ScoreDisplay[p].SetXY( SCORE_X[p], SCORE_Y ); m_ScoreDisplay[p].SetZoom( 0.8f ); this->AddActor( &m_ScoreDisplay[p] ); } m_StarWipe.SetClosed(); this->AddActor( &m_StarWipe ); m_sprReady.Load( THEME->GetPathTo(GRAPHIC_GAMEPLAY_READY) ); m_sprReady.SetXY( CENTER_X, CENTER_Y ); m_sprReady.SetDiffuseColor( D3DXCOLOR(1,1,1,0) ); this->AddActor( &m_sprReady ); m_sprHereWeGo.Load( THEME->GetPathTo(GRAPHIC_GAMEPLAY_HERE_WE_GO) ); m_sprHereWeGo.SetXY( CENTER_X, CENTER_Y ); m_sprHereWeGo.SetDiffuseColor( D3DXCOLOR(1,1,1,0) ); this->AddActor( &m_sprHereWeGo ); m_sprCleared.Load( THEME->GetPathTo(GRAPHIC_GAMEPLAY_CLEARED) ); m_sprCleared.SetXY( CENTER_X, CENTER_Y ); m_sprCleared.SetDiffuseColor( D3DXCOLOR(1,1,1,0) ); this->AddActor( &m_sprCleared ); m_sprFailed.Load( THEME->GetPathTo(GRAPHIC_GAMEPLAY_FAILED) ); m_sprFailed.SetXY( CENTER_X, CENTER_Y ); m_sprFailed.SetDiffuseColor( D3DXCOLOR(1,1,1,0) ); this->AddActor( &m_sprFailed ); m_soundMusic.Load( m_pSong->GetMusicPath() ); m_soundFail.Load( THEME->GetPathTo(SOUND_GAMEPLAY_FAILED) ); m_announcerReady.Load( ANNOUNCER->GetPathTo(ANNOUNCER_GAMEPLAY_READY) ); m_announcerHereWeGo.Load( ANNOUNCER->GetPathTo(ANNOUNCER_GAMEPLAY_HERE_WE_GO_NORMAL) ); m_announcerGood.Load( ANNOUNCER->GetPathTo(ANNOUNCER_GAMEPLAY_COMMENT_GOOD) ); m_announcerBad.Load( ANNOUNCER->GetPathTo(ANNOUNCER_GAMEPLAY_COMMENT_BAD) ); m_announcerCleared.Load( ANNOUNCER->GetPathTo(ANNOUNCER_GAMEPLAY_CLEARED) ); m_announcerFailComment.Load(ANNOUNCER->GetPathTo(ANNOUNCER_GAMEPLAY_FAILED) ); m_soundAssistTick.Load( THEME->GetPathTo(SOUND_GAMEPLAY_ASSIST_TICK) ); // Send some messages every have second to we can get the introduction rolling for( int i=0; i<30; i++ ) this->SendScreenMessage( ScreenMessage(SM_User+i), i/2.0f ); m_StarWipe.SetClosed(); } ScreenGameplay::~ScreenGameplay() { LOG->WriteLine( "ScreenGameplay::~ScreenGameplay()" ); m_soundMusic.Stop(); } void ScreenGameplay::Update( float fDeltaTime ) { //LOG->WriteLine( "ScreenGameplay::Update(%f)", fDeltaTime ); Screen::Update( fDeltaTime ); float fSongBeat, fBPS; float fPositionSeconds = m_soundMusic.GetPositionSeconds(); m_pSong->GetBeatAndBPSFromElapsedTime( fPositionSeconds, fSongBeat, fBPS ); //LOG->WriteLine( "m_fOffsetInBeats = %f, m_fBeatsPerSecond = %f, m_Music.GetPositionSeconds = %f", m_fOffsetInBeats, m_fBeatsPerSecond, m_Music.GetPositionSeconds() ); float fMaxBeatDifference = fBPS*MAX_SECONDS_CAN_BE_OFF_BY; for( int p=0; pIsPlayerEnabled(PlayerNumber(p)) ) continue; m_Player[p].Update( fDeltaTime, fSongBeat, fMaxBeatDifference ); } // check for fail switch( PREFSMAN->m_SongOptions.m_FailType ) { case SongOptions::FAIL_ARCADE: case SongOptions::FAIL_END_OF_SONG: if( m_bHasFailed ) break; // if they have already failed, don't bother checking again { // check for both players fail bool bAllAboutToFail = true; bool bAllFailed = true; for( int p=0; pIsPlayerEnabled(PlayerNumber(p)) ) continue; if( !m_LifeMeter[p].IsAboutToFail() ) { bAllAboutToFail = false; bAllFailed = false; } else if( !m_LifeMeter[p].HasFailed() ) { bAllFailed = false; } break; } if( bAllAboutToFail ) m_Background.TurnDangerOn(); else m_Background.TurnDangerOff(); if( bAllFailed ) { m_bHasFailed = true; SCREENMAN->SendMessageToTopScreen( SM_LifeIs0, 0 ); } } break; case SongOptions::FAIL_OFF: break; } switch( m_DancingState ) { case STATE_DANCING: // Check for end of song if( m_DancingState == STATE_DANCING && m_soundMusic.GetLengthSeconds() - m_soundMusic.GetPositionSeconds() < 2 ) this->SendScreenMessage( SM_SongEnded, 1 ); // Check to see if it's time to play a gameplay comment if( PREFSMAN->m_bAnnouncer ) { m_fTimeLeftBeforeDancingComment -= fDeltaTime; if( m_fTimeLeftBeforeDancingComment <= 0 ) { m_fTimeLeftBeforeDancingComment = TIME_BETWEEN_DANCING_COMMENTS; // reset for the next comment if( m_Background.IsDangerOn() ) m_announcerBad.PlayRandom(); else m_announcerGood.PlayRandom(); } } } if( PREFSMAN->m_SongOptions.m_AssistType == SongOptions::ASSIST_TICK ) { // // play assist ticks // // Sound cards have a latency between when a sample is Play()ed and when the sound // will start coming out the speaker. Compensate for this by boosting // fPositionSeconds ahead fPositionSeconds += (SOUND->GetPlayLatency()+0.06f) * m_soundMusic.GetPlaybackRate(); // HACK: Add 0.06 seconds to make them play a tiny bit earlier m_pSong->GetBeatAndBPSFromElapsedTime( fPositionSeconds, fSongBeat, fBPS ); int iIndexNow = BeatToNoteIndexNotRounded( fSongBeat ); static int iIndexLastCrossed = 0; bool bAnyoneHasANote = false; // set this to true if any player has a note at one of the indicies we crossed for( int i=iIndexLastCrossed+1; i<=iIndexNow; i++ ) // for each index we crossed since the last update { for( int p=0; pIsPlayerEnabled( (PlayerNumber)p ) ) continue; // skip bAnyoneHasANote |= m_Player[p].IsThereANoteAtIndex( i ); break; // this will only play the tick for the first player that is joined } } if( bAnyoneHasANote ) m_soundAssistTick.PlayRandom(); iIndexLastCrossed = iIndexNow; } } void ScreenGameplay::DrawPrimitives() { Screen::DrawPrimitives(); } void ScreenGameplay::Input( const DeviceInput& DeviceI, const InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI ) { //LOG->WriteLine( "ScreenGameplay::Input()" ); float fSongBeat, fBPS; m_pSong->GetBeatAndBPSFromElapsedTime( m_soundMusic.GetPositionSeconds(), fSongBeat, fBPS ); if( MenuI.IsValid() ) { switch( MenuI.button ) { case MENU_BUTTON_BACK: if( m_DancingState == STATE_DANCING && !m_bHasFailed ) { m_bHasFailed = true; SCREENMAN->SendMessageToTopScreen( SM_BeginFailed, 0 ); } else ; // do not let user go back! break; } } float fMaxBeatsCanBeOffBy = MAX_SECONDS_CAN_BE_OFF_BY * fBPS; if( type == IET_FIRST_PRESS ) { if( StyleI.IsValid() ) { m_Player[StyleI.player].HandlePlayerStep( fSongBeat, StyleI.col, fMaxBeatsCanBeOffBy ); } } } void ScreenGameplay::HandleScreenMessage( const ScreenMessage SM ) { switch( SM ) { // received while STATE_INTRO case SM_User+0: m_StarWipe.OpenWipingRight(SM_None); break; case SM_User+1: break; case SM_User+2: m_sprReady.StartFocusing(); if( PREFSMAN->m_bAnnouncer ) m_announcerReady.PlayRandom(); break; case SM_User+3: break; case SM_User+4: m_sprReady.StartBlurring(); break; case SM_User+5: m_sprHereWeGo.StartFocusing(); if( PREFSMAN->m_bAnnouncer ) m_announcerHereWeGo.PlayRandom(); m_Background.SetDiffuseColor( D3DXCOLOR(0.8f,0.8f,0.8f,1) ); m_soundMusic.Play(); m_soundMusic.SetPlaybackRate( PREFSMAN->m_SongOptions.m_fMusicRate ); break; case SM_User+6: break; case SM_User+7: break; case SM_User+8: m_sprHereWeGo.StartBlurring(); m_DancingState = STATE_DANCING; // STATE CHANGE! Now the user is allowed to press Back break; case SM_User+9: break; // received while STATE_DANCING case SM_LifeIs0: if( PREFSMAN->m_SongOptions.m_FailType == SongOptions::FAIL_ARCADE ) // fail them now! this->SendScreenMessage( SM_BeginFailed, 0 ); m_DancingState = STATE_OUTRO; break; case SM_SongEnded: if( m_DancingState == STATE_OUTRO ) // gameplay already ended return; // ignore if( m_bHasFailed ) // fail them { this->SendScreenMessage( SM_BeginFailed, 0 ); } else // cleared { m_StarWipe.CloseWipingRight( SM_ShowCleared ); if( PREFSMAN->m_bAnnouncer ) m_announcerCleared.PlayRandom(); // crowd cheer } m_DancingState = STATE_OUTRO; break; // received while STATE_OUTRO case SM_ShowCleared: m_sprCleared.StartFocusing(); SCREENMAN->SendMessageToTopScreen( SM_HideCleared, 2.5 ); break; case SM_HideCleared: m_sprCleared.StartBlurring(); SCREENMAN->SendMessageToTopScreen( SM_GoToResults, 1 ); break; case SM_GoToResults: // send score summaries to the PREFSMAN object so ScreenResults can grab it. PREFSMAN->m_ScoreSummary[PLAYER_1] = m_Player[PLAYER_1].GetScoreSummary(); PREFSMAN->m_ScoreSummary[PLAYER_2] = m_Player[PLAYER_2].GetScoreSummary(); SCREENMAN->SetNewScreen( new ScreenResults ); break; case SM_BeginFailed: m_DancingState = STATE_OUTRO; m_soundMusic.Pause(); m_StarWipe.CloseWipingRight( SM_None ); this->SendScreenMessage( SM_ShowFailed, 0.2f ); break; case SM_ShowFailed: if( PREFSMAN->m_bAnnouncer ) m_soundFail.PlayRandom(); // make the background invisible so we don't waste mem bandwidth drawing it m_Background.BeginTweening( 1 ); m_Background.SetTweenDiffuseColor( D3DXCOLOR(1,1,1,0) ); m_sprFailed.SetZoom( 4 ); m_sprFailed.BeginBlurredTweening( 0.8f, TWEEN_BIAS_END ); m_sprFailed.SetTweenZoom( 0.5f ); // zoom out m_sprFailed.SetTweenDiffuseColor( D3DXCOLOR(1,1,1,0.7f) ); // and fade in m_sprFailed.BeginTweeningQueued( 0.3f ); m_sprFailed.SetTweenZoom( 1.1f ); // bounce m_sprFailed.SetTweenDiffuseColor( D3DXCOLOR(1,1,1,0.7f) ); // and fade in m_sprFailed.BeginTweeningQueued( 0.2f ); m_sprFailed.SetTweenZoom( 1.0f ); // come to rest m_sprFailed.SetTweenDiffuseColor( D3DXCOLOR(1,1,1,0.7f) ); // and fade in SCREENMAN->SendMessageToTopScreen( SM_PlayFailComment, 1.5f ); SCREENMAN->SendMessageToTopScreen( SM_HideFailed, 3.0f ); break; case SM_PlayFailComment: if( PREFSMAN->m_bAnnouncer ) m_announcerFailComment.PlayRandom(); break; case SM_HideFailed: m_sprFailed.StopTweening(); m_sprFailed.BeginTweening(1.0f); m_sprFailed.SetTweenDiffuseColor( D3DXCOLOR(1,1,1,0) ); SCREENMAN->SendMessageToTopScreen( SM_GoToScreenAfterFail, 1.5f ); break; case SM_GoToScreenAfterFail: if( PREFSMAN->m_bEventMode ) SCREENMAN->SetNewScreen( new ScreenSelectMusic ); else SCREENMAN->SetNewScreen( new ScreenGameOver ); break; } }