From efb3b0b3ed2636f3a6959ee0b2452762165b2690 Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Mon, 2 Jul 2012 16:57:22 -0500 Subject: [PATCH] [ScreenHowToPlay] Run InitCommand on Characters if enabled. --- Docs/Changelog_sm5.txt | 4 + src/ScreenHowToPlay.cpp | 707 ++++++++++++++++++++-------------------- 2 files changed, 358 insertions(+), 353 deletions(-) diff --git a/Docs/Changelog_sm5.txt b/Docs/Changelog_sm5.txt index 116347a6df..82013431f7 100644 --- a/Docs/Changelog_sm5.txt +++ b/Docs/Changelog_sm5.txt @@ -8,6 +8,10 @@ ________________________________________________________________________________ StepMania 5.0 ???? ?? | 20120??? -------------------------------------------------------------------------------- +2012/07/02 +---------- +* [ScreenHowToPlay] Run InitCommand on Characters if enabled. [AJ] + 2012/06/27 ---------- * [SongManager] Ending a group's name in PreferredSongs with "/*" will now load diff --git a/src/ScreenHowToPlay.cpp b/src/ScreenHowToPlay.cpp index 8f97cac451..be997bae2e 100644 --- a/src/ScreenHowToPlay.cpp +++ b/src/ScreenHowToPlay.cpp @@ -1,353 +1,354 @@ -#include "global.h" -#include "ScreenHowToPlay.h" -#include "ThemeManager.h" -#include "GameState.h" -#include "Steps.h" -#include "GameManager.h" -#include "NotesLoaderSM.h" -#include "NotesLoaderSSC.h" -#include "GameSoundManager.h" -#include "Model.h" -#include "ThemeMetric.h" -#include "PlayerState.h" -#include "Style.h" -#include "PrefsManager.h" -#include "CharacterManager.h" -#include "StatsManager.h" -#include "RageDisplay.h" -#include "SongUtil.h" -#include "Character.h" -#include "LifeMeterBar.h" - -static const ThemeMetric NUM_W2S ("ScreenHowToPlay","NumW2s"); -static const ThemeMetric NUM_MISSES ("ScreenHowToPlay","NumMisses"); -static const ThemeMetric USE_CHARACTER ("ScreenHowToPlay","UseCharacter"); -static const ThemeMetric USE_PAD ("ScreenHowToPlay","UsePad"); -static const ThemeMetric USE_PLAYER ("ScreenHowToPlay","UsePlayer"); -static const ThemeMetric CHARACTER_NAME("ScreenHowToPlay","CharacterName"); - -enum Animation -{ - ANIM_DANCE_PAD, - ANIM_DANCE_PADS, - ANIM_UP, - ANIM_DOWN, - ANIM_LEFT, - ANIM_RIGHT, - ANIM_JUMPLR, - NUM_ANIMATIONS -}; - -static const RString anims[NUM_ANIMATIONS] = -{ - "DancePad.txt", - "DancePads.txt", - "BeginnerHelper_step-up.bones.txt", - "BeginnerHelper_step-down.bones.txt", - "BeginnerHelper_step-left.bones.txt", - "BeginnerHelper_step-right.bones.txt", - "BeginnerHelper_step-jumplr.bones.txt" -}; - -static RString GetAnimPath( Animation a ) -{ - return RString("Characters/") + anims[a]; -} - -static bool HaveAllCharAnimations() -{ - for( int i = ANIM_UP; i < NUM_ANIMATIONS; ++i ) - if( !DoesFileExist( GetAnimPath( (Animation) i ) ) ) - return false; - return true; -} - -REGISTER_SCREEN_CLASS( ScreenHowToPlay ); -ScreenHowToPlay::ScreenHowToPlay() -{ - m_iW2s = 0; - m_iNumW2s = NUM_W2S; - - // initialize these because they might not be used. - m_pLifeMeterBar = NULL; - m_pmCharacter = NULL; - m_pmDancePad = NULL; -} - -void ScreenHowToPlay::Init() -{ - ScreenAttract::Init(); - - if( (bool)USE_PAD && DoesFileExist( GetAnimPath(ANIM_DANCE_PAD) ) ) - { - m_pmDancePad = new Model; - m_pmDancePad->SetName( "Pad" ); - m_pmDancePad->LoadMilkshapeAscii( GetAnimPath(ANIM_DANCE_PAD) ); - // xxx: hardcoded rotation. can be undone, but still. -freem - m_pmDancePad->SetRotationX( 35 ); - ActorUtil::LoadAllCommandsAndSetXY( m_pmDancePad, m_sName ); - } - - // Display a character - vector vpCharacters; - CHARMAN->GetCharacters( vpCharacters ); - if( (bool)USE_CHARACTER && vpCharacters.size() && HaveAllCharAnimations() ) - { - Character* displayChar; - if( !CHARACTER_NAME.GetValue().empty() && CHARMAN->GetCharacterFromID(CHARACTER_NAME) ) - displayChar = CHARMAN->GetCharacterFromID(CHARACTER_NAME); - else - displayChar = CHARMAN->GetRandomCharacter(); - - RString sModelPath = displayChar->GetModelPath(); - if( sModelPath != "" ) - { - m_pmCharacter = new Model; - m_pmCharacter->SetName( "Character" ); - m_pmCharacter->LoadMilkshapeAscii( displayChar->GetModelPath() ); - m_pmCharacter->LoadMilkshapeAsciiBones( "Step-LEFT", GetAnimPath( ANIM_LEFT ) ); - m_pmCharacter->LoadMilkshapeAsciiBones( "Step-DOWN", GetAnimPath( ANIM_DOWN ) ); - m_pmCharacter->LoadMilkshapeAsciiBones( "Step-UP", GetAnimPath( ANIM_UP ) ); - m_pmCharacter->LoadMilkshapeAsciiBones( "Step-RIGHT", GetAnimPath( ANIM_RIGHT ) ); - m_pmCharacter->LoadMilkshapeAsciiBones( "Step-JUMPLR", GetAnimPath( ANIM_JUMPLR ) ); - RString sRestFile = displayChar->GetRestAnimationPath(); - ASSERT( !sRestFile.empty() ); - m_pmCharacter->LoadMilkshapeAsciiBones( "rest",displayChar->GetRestAnimationPath() ); - m_pmCharacter->SetDefaultAnimation( "rest" ); - m_pmCharacter->PlayAnimation( "rest" ); // Stay bouncing after a step has finished animating. - - // xxx: hardcoded rotation. can be undone, but still. -freem - m_pmCharacter->SetRotationX( 40 ); - m_pmCharacter->SetCullMode( CULL_NONE ); // many of the models floating around have the vertex order flipped - ActorUtil::LoadAllCommandsAndSetXY( m_pmCharacter, m_sName ); - } - } - - GAMESTATE->SetCurrentStyle( GAMEMAN->GetHowToPlayStyleForGame(GAMESTATE->m_pCurGame) ); - - if( USE_PLAYER ) - { - m_pLifeMeterBar = new LifeMeterBar; - m_pLifeMeterBar->SetName("LifeMeterBar"); - m_pLifeMeterBar->Load( GAMESTATE->m_pPlayerState[PLAYER_1], &STATSMAN->m_CurStageStats.m_player[PLAYER_1] ); - ActorUtil::LoadAllCommandsAndSetXY( m_pLifeMeterBar, m_sName ); - m_pLifeMeterBar->FillForHowToPlay( NUM_W2S, NUM_MISSES ); - - // Allow themers to use either a .ssc or .sm file for this. -aj - RString sStepsPath = THEME->GetPathO(m_sName, "steps"); - SSCLoader loaderSSC; - SMLoader loaderSM; - if( sStepsPath.Right(4) == ".ssc" ) - loaderSSC.LoadFromSimfile( sStepsPath, m_Song, false ); - else - loaderSM.LoadFromSimfile( sStepsPath, m_Song, false ); - m_Song.AddAutoGenNotes(); - - const Style* pStyle = GAMESTATE->GetCurrentStyle(); - - Steps *pSteps = SongUtil::GetClosestNotes( &m_Song, pStyle->m_StepsType, Difficulty_Beginner ); - ASSERT_M( pSteps != NULL, ssprintf("No playable steps of StepsType '%s' for ScreenHowToPlay", StringConversion::ToString(pStyle->m_StepsType).c_str()) ); - - pSteps->m_Timing.TidyUpData(); - NoteData tempNoteData; - pSteps->GetNoteData( tempNoteData ); - pStyle->GetTransformedNoteDataForStyle( PLAYER_1, tempNoteData, m_NoteData ); - - GAMESTATE->m_pCurSong.Set( &m_Song ); - GAMESTATE->m_pCurSteps[PLAYER_1].Set(pSteps); - GAMESTATE->m_bGameplayLeadIn.Set( false ); - GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerController = PC_AUTOPLAY; - - m_Player->Init( - "Player", - GAMESTATE->m_pPlayerState[PLAYER_1], - NULL, - m_pLifeMeterBar, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL ); - m_Player.Load( m_NoteData ); - m_Player->SetName( "Player" ); - this->AddChild( m_Player ); - ActorUtil::LoadAllCommandsAndSetXY( m_Player, m_sName ); - - // Don't show judgment - PO_GROUP_ASSIGN( GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerOptions, ModsLevel_Stage, m_fBlind, 1.0f ); - GAMESTATE->SetMasterPlayerNumber(PLAYER_1); - GAMESTATE->m_bDemonstrationOrJukebox = true; - } - - // deferred until after the player, so the notes go under it - if( m_pLifeMeterBar ) - this->AddChild( m_pLifeMeterBar ); - if( m_pmDancePad ) - this->AddChild( m_pmDancePad ); - if( m_pmCharacter ) - this->AddChild( m_pmCharacter ); - - m_fFakeSecondsIntoSong = 0; - - this->MoveToTail( &m_In ); - this->MoveToTail( &m_Out ); -} - -ScreenHowToPlay::~ScreenHowToPlay() -{ - delete m_pLifeMeterBar; - delete m_pmCharacter; - delete m_pmDancePad; -} - -void ScreenHowToPlay::Step() -{ -// xxx: assumes dance. -freem -#define ST_LEFT 0x01 -#define ST_DOWN 0x02 -#define ST_UP 0x04 -#define ST_RIGHT 0x08 -#define ST_JUMPLR (ST_LEFT | ST_RIGHT) -#define ST_JUMPUD (ST_UP | ST_DOWN) - - int iStep = 0; - const int iNoteRow = BeatToNoteRowNotRounded( GAMESTATE->m_Position.m_fSongBeat + 0.6f ); - // if we want to miss from here on out, don't process steps. - if( m_iW2s < m_iNumW2s && m_NoteData.IsThereATapAtRow( iNoteRow ) ) - { - const int iNumTracks = m_NoteData.GetNumTracks(); - for( int k=0; kPlayAnimation( "Step-LEFT", 1.8f ); break; - case ST_RIGHT: m_pmCharacter->PlayAnimation( "Step-RIGHT", 1.8f ); break; - case ST_UP: m_pmCharacter->PlayAnimation( "Step-UP", 1.8f ); break; - case ST_DOWN: m_pmCharacter->PlayAnimation( "Step-DOWN", 1.8f ); break; - case ST_JUMPLR: m_pmCharacter->PlayAnimation( "Step-JUMPLR", 1.8f ); break; - case ST_JUMPUD: - // Until I can get an UP+DOWN jump animation, this will have to do. - m_pmCharacter->PlayAnimation( "Step-JUMPLR", 1.8f ); - - m_pmCharacter->StopTweening(); - m_pmCharacter->BeginTweening( GAMESTATE->m_Position.m_fCurBPS /8, TWEEN_LINEAR ); - m_pmCharacter->SetRotationY( 90 ); - m_pmCharacter->BeginTweening( (1/(GAMESTATE->m_Position.m_fCurBPS * 2) ) ); //sleep between jump-frames - m_pmCharacter->BeginTweening( GAMESTATE->m_Position.m_fCurBPS /6, TWEEN_LINEAR ); - m_pmCharacter->SetRotationY( 0 ); - break; - } - } -} - -void ScreenHowToPlay::Update( float fDelta ) -{ - if( GAMESTATE->m_pCurSong != NULL ) - { - GAMESTATE->UpdateSongPosition( m_fFakeSecondsIntoSong, GAMESTATE->m_pCurSong->m_SongTiming ); - m_fFakeSecondsIntoSong += fDelta; - - static int iLastNoteRowCounted = 0; - int iCurNoteRow = BeatToNoteRowNotRounded( GAMESTATE->m_Position.m_fSongBeat ); - - if( iCurNoteRow != iLastNoteRowCounted &&m_NoteData.IsThereATapAtRow(iCurNoteRow) ) - { - if( m_pLifeMeterBar && !m_Player ) - { - if ( m_iW2s < m_iNumW2s ) - m_pLifeMeterBar->ChangeLife( TNS_W2 ); - else - m_pLifeMeterBar->ChangeLife( TNS_Miss ); - } - m_iW2s++; - iLastNoteRowCounted = iCurNoteRow; - } - - // Once we hit the number of perfects we want, we want to fail. Switch - // the controller to HUMAN. Since we aren't taking input, the steps will - // always be misses. - if( m_iW2s > m_iNumW2s ) - GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerController = PC_HUMAN; - - // Per the above code, we don't always want the character stepping. - // If they try to make all of the steps in the miss part, they look - // silly. Have then stand still instead. - freem - if ( m_pmCharacter ) - { - if( m_iW2s <= m_iNumW2s ) - Step(); - } - } - - ScreenAttract::Update( fDelta ); -} - -void ScreenHowToPlay::HandleScreenMessage( const ScreenMessage SM ) -{ - if( SM == SM_GainFocus ) - { - // We do this ourself. - SOUND->HandleSongTimer( false ); - } - else if( SM == SM_LoseFocus ) - { - SOUND->HandleSongTimer( true ); - } - else if( SM == SM_GoToNextScreen ) - { - GAMESTATE->Reset(); - } - ScreenAttract::HandleScreenMessage( SM ); -} - -// lua start -#include "LuaBinding.h" - -/** @brief Allow Lua to have access to the ScreenHowToPlay. */ -class LunaScreenHowToPlay: public Luna -{ -public: - static int GetLifeMeter( T* p, lua_State *L ) - { - //PlayerNumber pn = Enum::Check( L, 1 ); - - p->m_pLifeMeterBar->PushSelf( L ); - return 1; - } - - LunaScreenHowToPlay() - { - ADD_METHOD( GetLifeMeter ); - } -}; - -LUA_REGISTER_DERIVED_CLASS( ScreenHowToPlay, ScreenAttract ) -// lua end - -/* - * (c) 2001-2004 Chris Danford, Thad Ward - * 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. - */ +#include "global.h" +#include "ScreenHowToPlay.h" +#include "ThemeManager.h" +#include "GameState.h" +#include "Steps.h" +#include "GameManager.h" +#include "NotesLoaderSM.h" +#include "NotesLoaderSSC.h" +#include "GameSoundManager.h" +#include "Model.h" +#include "ThemeMetric.h" +#include "PlayerState.h" +#include "Style.h" +#include "PrefsManager.h" +#include "CharacterManager.h" +#include "StatsManager.h" +#include "RageDisplay.h" +#include "SongUtil.h" +#include "Character.h" +#include "LifeMeterBar.h" + +static const ThemeMetric NUM_W2S ("ScreenHowToPlay","NumW2s"); +static const ThemeMetric NUM_MISSES ("ScreenHowToPlay","NumMisses"); +static const ThemeMetric USE_CHARACTER ("ScreenHowToPlay","UseCharacter"); +static const ThemeMetric USE_PAD ("ScreenHowToPlay","UsePad"); +static const ThemeMetric USE_PLAYER ("ScreenHowToPlay","UsePlayer"); +static const ThemeMetric CHARACTER_NAME("ScreenHowToPlay","CharacterName"); + +enum Animation +{ + ANIM_DANCE_PAD, + ANIM_DANCE_PADS, + ANIM_UP, + ANIM_DOWN, + ANIM_LEFT, + ANIM_RIGHT, + ANIM_JUMPLR, + NUM_ANIMATIONS +}; + +static const RString anims[NUM_ANIMATIONS] = +{ + "DancePad.txt", + "DancePads.txt", + "BeginnerHelper_step-up.bones.txt", + "BeginnerHelper_step-down.bones.txt", + "BeginnerHelper_step-left.bones.txt", + "BeginnerHelper_step-right.bones.txt", + "BeginnerHelper_step-jumplr.bones.txt" +}; + +static RString GetAnimPath( Animation a ) +{ + return RString("Characters/") + anims[a]; +} + +static bool HaveAllCharAnimations() +{ + for( int i = ANIM_UP; i < NUM_ANIMATIONS; ++i ) + if( !DoesFileExist( GetAnimPath( (Animation) i ) ) ) + return false; + return true; +} + +REGISTER_SCREEN_CLASS( ScreenHowToPlay ); +ScreenHowToPlay::ScreenHowToPlay() +{ + m_iW2s = 0; + m_iNumW2s = NUM_W2S; + + // initialize these because they might not be used. + m_pLifeMeterBar = NULL; + m_pmCharacter = NULL; + m_pmDancePad = NULL; +} + +void ScreenHowToPlay::Init() +{ + ScreenAttract::Init(); + + if( (bool)USE_PAD && DoesFileExist( GetAnimPath(ANIM_DANCE_PAD) ) ) + { + m_pmDancePad = new Model; + m_pmDancePad->SetName( "Pad" ); + m_pmDancePad->LoadMilkshapeAscii( GetAnimPath(ANIM_DANCE_PAD) ); + // xxx: hardcoded rotation. can be undone, but still. -freem + m_pmDancePad->SetRotationX( 35 ); + ActorUtil::LoadAllCommandsAndSetXY( m_pmDancePad, m_sName ); + } + + // Display a character + vector vpCharacters; + CHARMAN->GetCharacters( vpCharacters ); + if( (bool)USE_CHARACTER && vpCharacters.size() && HaveAllCharAnimations() ) + { + Character* displayChar; + if( !CHARACTER_NAME.GetValue().empty() && CHARMAN->GetCharacterFromID(CHARACTER_NAME) ) + displayChar = CHARMAN->GetCharacterFromID(CHARACTER_NAME); + else + displayChar = CHARMAN->GetRandomCharacter(); + + RString sModelPath = displayChar->GetModelPath(); + if( sModelPath != "" ) + { + m_pmCharacter = new Model; + m_pmCharacter->SetName( "Character" ); + m_pmCharacter->LoadMilkshapeAscii( displayChar->GetModelPath() ); + m_pmCharacter->LoadMilkshapeAsciiBones( "Step-LEFT", GetAnimPath( ANIM_LEFT ) ); + m_pmCharacter->LoadMilkshapeAsciiBones( "Step-DOWN", GetAnimPath( ANIM_DOWN ) ); + m_pmCharacter->LoadMilkshapeAsciiBones( "Step-UP", GetAnimPath( ANIM_UP ) ); + m_pmCharacter->LoadMilkshapeAsciiBones( "Step-RIGHT", GetAnimPath( ANIM_RIGHT ) ); + m_pmCharacter->LoadMilkshapeAsciiBones( "Step-JUMPLR", GetAnimPath( ANIM_JUMPLR ) ); + RString sRestFile = displayChar->GetRestAnimationPath(); + ASSERT( !sRestFile.empty() ); + m_pmCharacter->LoadMilkshapeAsciiBones( "rest",displayChar->GetRestAnimationPath() ); + m_pmCharacter->SetDefaultAnimation( "rest" ); + m_pmCharacter->PlayAnimation( "rest" ); // Stay bouncing after a step has finished animating. + + // xxx: hardcoded rotation. can be undone, but still. -freem + m_pmCharacter->SetRotationX( 40 ); + m_pmCharacter->SetCullMode( CULL_NONE ); // many of the models floating around have the vertex order flipped + m_pmCharacter->RunCommands( displayChar->m_cmdInit ); // run InitCommand from file + ActorUtil::LoadAllCommandsAndSetXY( m_pmCharacter, m_sName ); + } + } + + GAMESTATE->SetCurrentStyle( GAMEMAN->GetHowToPlayStyleForGame(GAMESTATE->m_pCurGame) ); + + if( USE_PLAYER ) + { + m_pLifeMeterBar = new LifeMeterBar; + m_pLifeMeterBar->SetName("LifeMeterBar"); + m_pLifeMeterBar->Load( GAMESTATE->m_pPlayerState[PLAYER_1], &STATSMAN->m_CurStageStats.m_player[PLAYER_1] ); + ActorUtil::LoadAllCommandsAndSetXY( m_pLifeMeterBar, m_sName ); + m_pLifeMeterBar->FillForHowToPlay( NUM_W2S, NUM_MISSES ); + + // Allow themers to use either a .ssc or .sm file for this. -aj + RString sStepsPath = THEME->GetPathO(m_sName, "steps"); + SSCLoader loaderSSC; + SMLoader loaderSM; + if( sStepsPath.Right(4) == ".ssc" ) + loaderSSC.LoadFromSimfile( sStepsPath, m_Song, false ); + else + loaderSM.LoadFromSimfile( sStepsPath, m_Song, false ); + m_Song.AddAutoGenNotes(); + + const Style* pStyle = GAMESTATE->GetCurrentStyle(); + + Steps *pSteps = SongUtil::GetClosestNotes( &m_Song, pStyle->m_StepsType, Difficulty_Beginner ); + ASSERT_M( pSteps != NULL, ssprintf("No playable steps of StepsType '%s' for ScreenHowToPlay", StringConversion::ToString(pStyle->m_StepsType).c_str()) ); + + pSteps->m_Timing.TidyUpData(); + NoteData tempNoteData; + pSteps->GetNoteData( tempNoteData ); + pStyle->GetTransformedNoteDataForStyle( PLAYER_1, tempNoteData, m_NoteData ); + + GAMESTATE->m_pCurSong.Set( &m_Song ); + GAMESTATE->m_pCurSteps[PLAYER_1].Set(pSteps); + GAMESTATE->m_bGameplayLeadIn.Set( false ); + GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerController = PC_AUTOPLAY; + + m_Player->Init( + "Player", + GAMESTATE->m_pPlayerState[PLAYER_1], + NULL, + m_pLifeMeterBar, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL ); + m_Player.Load( m_NoteData ); + m_Player->SetName( "Player" ); + this->AddChild( m_Player ); + ActorUtil::LoadAllCommandsAndSetXY( m_Player, m_sName ); + + // Don't show judgment + PO_GROUP_ASSIGN( GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerOptions, ModsLevel_Stage, m_fBlind, 1.0f ); + GAMESTATE->SetMasterPlayerNumber(PLAYER_1); + GAMESTATE->m_bDemonstrationOrJukebox = true; + } + + // deferred until after the player, so the notes go under it + if( m_pLifeMeterBar ) + this->AddChild( m_pLifeMeterBar ); + if( m_pmDancePad ) + this->AddChild( m_pmDancePad ); + if( m_pmCharacter ) + this->AddChild( m_pmCharacter ); + + m_fFakeSecondsIntoSong = 0; + + this->MoveToTail( &m_In ); + this->MoveToTail( &m_Out ); +} + +ScreenHowToPlay::~ScreenHowToPlay() +{ + delete m_pLifeMeterBar; + delete m_pmCharacter; + delete m_pmDancePad; +} + +void ScreenHowToPlay::Step() +{ +// xxx: assumes dance. -freem +#define ST_LEFT 0x01 +#define ST_DOWN 0x02 +#define ST_UP 0x04 +#define ST_RIGHT 0x08 +#define ST_JUMPLR (ST_LEFT | ST_RIGHT) +#define ST_JUMPUD (ST_UP | ST_DOWN) + + int iStep = 0; + const int iNoteRow = BeatToNoteRowNotRounded( GAMESTATE->m_Position.m_fSongBeat + 0.6f ); + // if we want to miss from here on out, don't process steps. + if( m_iW2s < m_iNumW2s && m_NoteData.IsThereATapAtRow( iNoteRow ) ) + { + const int iNumTracks = m_NoteData.GetNumTracks(); + for( int k=0; kPlayAnimation( "Step-LEFT", 1.8f ); break; + case ST_RIGHT: m_pmCharacter->PlayAnimation( "Step-RIGHT", 1.8f ); break; + case ST_UP: m_pmCharacter->PlayAnimation( "Step-UP", 1.8f ); break; + case ST_DOWN: m_pmCharacter->PlayAnimation( "Step-DOWN", 1.8f ); break; + case ST_JUMPLR: m_pmCharacter->PlayAnimation( "Step-JUMPLR", 1.8f ); break; + case ST_JUMPUD: + // Until I can get an UP+DOWN jump animation, this will have to do. + m_pmCharacter->PlayAnimation( "Step-JUMPLR", 1.8f ); + + m_pmCharacter->StopTweening(); + m_pmCharacter->BeginTweening( GAMESTATE->m_Position.m_fCurBPS /8, TWEEN_LINEAR ); + m_pmCharacter->SetRotationY( 90 ); + m_pmCharacter->BeginTweening( (1/(GAMESTATE->m_Position.m_fCurBPS * 2) ) ); //sleep between jump-frames + m_pmCharacter->BeginTweening( GAMESTATE->m_Position.m_fCurBPS /6, TWEEN_LINEAR ); + m_pmCharacter->SetRotationY( 0 ); + break; + } + } +} + +void ScreenHowToPlay::Update( float fDelta ) +{ + if( GAMESTATE->m_pCurSong != NULL ) + { + GAMESTATE->UpdateSongPosition( m_fFakeSecondsIntoSong, GAMESTATE->m_pCurSong->m_SongTiming ); + m_fFakeSecondsIntoSong += fDelta; + + static int iLastNoteRowCounted = 0; + int iCurNoteRow = BeatToNoteRowNotRounded( GAMESTATE->m_Position.m_fSongBeat ); + + if( iCurNoteRow != iLastNoteRowCounted &&m_NoteData.IsThereATapAtRow(iCurNoteRow) ) + { + if( m_pLifeMeterBar && !m_Player ) + { + if ( m_iW2s < m_iNumW2s ) + m_pLifeMeterBar->ChangeLife( TNS_W2 ); + else + m_pLifeMeterBar->ChangeLife( TNS_Miss ); + } + m_iW2s++; + iLastNoteRowCounted = iCurNoteRow; + } + + // Once we hit the number of perfects we want, we want to fail. Switch + // the controller to HUMAN. Since we aren't taking input, the steps will + // always be misses. + if( m_iW2s > m_iNumW2s ) + GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerController = PC_HUMAN; + + // Per the above code, we don't always want the character stepping. + // If they try to make all of the steps in the miss part, they look + // silly. Have then stand still instead. - freem + if ( m_pmCharacter ) + { + if( m_iW2s <= m_iNumW2s ) + Step(); + } + } + + ScreenAttract::Update( fDelta ); +} + +void ScreenHowToPlay::HandleScreenMessage( const ScreenMessage SM ) +{ + if( SM == SM_GainFocus ) + { + // We do this ourself. + SOUND->HandleSongTimer( false ); + } + else if( SM == SM_LoseFocus ) + { + SOUND->HandleSongTimer( true ); + } + else if( SM == SM_GoToNextScreen ) + { + GAMESTATE->Reset(); + } + ScreenAttract::HandleScreenMessage( SM ); +} + +// lua start +#include "LuaBinding.h" + +/** @brief Allow Lua to have access to the ScreenHowToPlay. */ +class LunaScreenHowToPlay: public Luna +{ +public: + static int GetLifeMeter( T* p, lua_State *L ) + { + //PlayerNumber pn = Enum::Check( L, 1 ); + + p->m_pLifeMeterBar->PushSelf( L ); + return 1; + } + + LunaScreenHowToPlay() + { + ADD_METHOD( GetLifeMeter ); + } +}; + +LUA_REGISTER_DERIVED_CLASS( ScreenHowToPlay, ScreenAttract ) +// lua end + +/* + * (c) 2001-2004 Chris Danford, Thad Ward + * 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. + */