#include "global.h" #include "ActorUtil.h" #include "BeginnerHelper.h" #include "GameState.h" #include "PrefsManager.h" #include "RageLog.h" #include "RageDisplay.h" #include "Steps.h" #include "Style.h" #include "Model.h" #include "ScreenDimensions.h" // "PLAYER_X" offsets are relative to the pad.. ex: Setting this to 10, and the HELPER to 300, will put the dancer at 310 #define PLAYER_X( px ) THEME->GetMetricF("BeginnerHelper",ssprintf("Player%d_X",px+1)) #define PLAYER_ANGLE THEME->GetMetricF("BeginnerHelper","PlayerAngle") #define DANCEPAD_ANGLE THEME->GetMetricF("BeginnerHelper","DancePadAngle") // "HELPER" offsets effect the pad/dancer as a whole.. Their relative Y cooridinates are hard-coded for eachother. #define HELPER_X THEME->GetMetricF("BeginnerHelper","HelperX") #define HELPER_Y THEME->GetMetricF("BeginnerHelper","HelperY") #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) enum Animation { ANIM_DANCE_PAD, ANIM_DANCE_PADS, ANIM_UP, ANIM_DOWN, ANIM_LEFT, ANIM_RIGHT, ANIM_JUMPLR, NUM_ANIMATIONS }; static const char *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 CString GetAnimPath(Animation a) { return CString("Characters/") + anims[a]; } BeginnerHelper::BeginnerHelper() { m_bShowBackground = true; m_bInitialized = false; m_iLastRowChecked = m_iLastRowFlashed = 0; FOREACH_PlayerNumber( pn ) m_bPlayerEnabled[pn] = false; FOREACH_PlayerNumber( pn ) m_pDancer[pn] = new Model; m_pDancePad = new Model; } BeginnerHelper::~BeginnerHelper() { FOREACH_PlayerNumber( pn ) delete m_pDancer[pn]; delete m_pDancePad; } void BeginnerHelper::ShowStepCircle( PlayerNumber pn, int CSTEP ) { int isc=0; // Save OR issues within array boundries.. it's worth the extra few bytes of memory. switch(CSTEP) { case ST_LEFT: isc=0; break; case ST_RIGHT: isc=1; break; case ST_UP: isc=2; break; case ST_DOWN: isc=3; break; } m_sStepCircle[pn][isc].StopEffect(); m_sStepCircle[pn][isc].SetZoom(2); m_sStepCircle[pn][isc].StopTweening(); m_sStepCircle[pn][isc].BeginTweening((GAMESTATE->m_fCurBPS/3), TWEEN_LINEAR); m_sStepCircle[pn][isc].SetZoom(0); } void BeginnerHelper::AddPlayer( PlayerNumber pn, NoteData *pSteps ) { ASSERT(!m_bInitialized); ASSERT(pSteps != NULL); ASSERT((pn >= 0) && (pn < NUM_PLAYERS)); ASSERT(GAMESTATE->IsHumanPlayer(pn)); if(!CanUse()) return; const Character *Character = GAMESTATE->m_pCurCharacters[pn]; ASSERT( Character != NULL ); if(!DoesFileExist(Character->GetModelPath())) return; m_NoteData[pn].CopyAll(*pSteps); m_bPlayerEnabled[pn] = true; } bool BeginnerHelper::CanUse() { for(int i=0; im_pCurStyle->m_bCanUseBeginnerHelper; } bool BeginnerHelper::Initialize( int iDancePadType ) { ASSERT( !m_bInitialized ); if(!CanUse()) return false; // If no players were successfully added, bail. { bool bAnyLoaded = false; for(int pn=0; pnGetPathG("BeginnerHelper","background") ); this->AddChild(&m_sBackground); m_sBackground.SetXY(1,1); m_sFlash.Load(THEME->GetPathG("BeginnerHelper","flash")); m_sFlash.SetXY(0,0); m_sFlash.SetDiffuseAlpha(0); } // Load StepCircle graphics for(int lsc=0; lscGetPathG("BeginnerHelper","stepcircle")); m_sStepCircle[lsc][lsce].SetZoom(0); // Hide until needed. this->AddChild(&m_sStepCircle[lsc][lsce]); // Set coordinates of StepCircle switch(lsce) { case 0: m_sStepCircle[lsc][lsce].SetXY((HELPER_X+PLAYER_X(lsc)-80),HELPER_Y); break; // Left case 1: m_sStepCircle[lsc][lsce].SetXY((HELPER_X+PLAYER_X(lsc)+80),HELPER_Y); break; // Right case 2: m_sStepCircle[lsc][lsce].SetXY((HELPER_X+PLAYER_X(lsc)),(HELPER_Y-60)); break; // Up case 3: m_sStepCircle[lsc][lsce].SetXY((HELPER_X+PLAYER_X(lsc)),(HELPER_Y+60)); break; // Down } } // Load the DancePad switch(iDancePadType) { case 0: break; // No pad case 1: m_pDancePad->LoadMilkshapeAscii(GetAnimPath(ANIM_DANCE_PAD)); break; case 2: m_pDancePad->LoadMilkshapeAscii(GetAnimPath(ANIM_DANCE_PADS)); break; } m_pDancePad->SetHorizAlign( align_left ); m_pDancePad->SetRotationX( DANCEPAD_ANGLE ); m_pDancePad->SetX(HELPER_X); m_pDancePad->SetY(HELPER_Y); m_pDancePad->SetZoom(23); // Pad should always be 3 units bigger in zoom than the dancer. for( int pl=0; plm_pCurCharacters[pl]; ASSERT( Character != NULL ); // Load textures m_pDancer[pl]->SetHorizAlign( align_left ); m_pDancer[pl]->LoadMilkshapeAscii( Character->GetModelPath() ); // Load needed animations m_pDancer[pl]->LoadMilkshapeAsciiBones("Step-LEFT", GetAnimPath(ANIM_LEFT)); m_pDancer[pl]->LoadMilkshapeAsciiBones("Step-DOWN", GetAnimPath(ANIM_DOWN)); m_pDancer[pl]->LoadMilkshapeAsciiBones("Step-UP", GetAnimPath(ANIM_UP)); m_pDancer[pl]->LoadMilkshapeAsciiBones("Step-RIGHT", GetAnimPath(ANIM_RIGHT)); m_pDancer[pl]->LoadMilkshapeAsciiBones("Step-JUMPLR", GetAnimPath(ANIM_JUMPLR)); m_pDancer[pl]->LoadMilkshapeAsciiBones("rest", Character->GetRestAnimationPath()); m_pDancer[pl]->SetDefaultAnimation("rest"); m_pDancer[pl]->PlayAnimation("rest"); m_pDancer[pl]->SetRotationX(PLAYER_ANGLE); m_pDancer[pl]->SetX(HELPER_X+PLAYER_X(pl)); m_pDancer[pl]->SetY(HELPER_Y+10); m_pDancer[pl]->SetZoom(20); m_pDancer[pl]->SetCullMode(CULL_NONE); // many of the models floating around have the vertex order flipped m_pDancer[pl]->m_bRevertToDefaultAnimation = true; // Stay bouncing after a step has finished animating } m_bInitialized = true; return true; } void BeginnerHelper::DrawPrimitives() { // If not initialized, don't bother with this if(!m_bInitialized) return; ActorFrame::DrawPrimitives(); m_sFlash.Draw(); bool DrawCelShaded = PREFSMAN->m_bCelShadeModels; if(DrawCelShaded) m_pDancePad->DrawCelShaded(); else { DISPLAY->SetLighting( true ); DISPLAY->SetLightDirectional( 0, RageColor(0.5,0.5,0.5,1), RageColor(1,1,1,1), RageColor(0,0,0,1), RageVector3(0, 0, 1) ); m_pDancePad->Draw(); DISPLAY->ClearZBuffer(); // So character doesn't step "into" the dance pad. DISPLAY->SetLightOff(0); DISPLAY->SetLighting(false); } // Draw StepCircles for(int scd=0; scdIsHumanPlayer(pn)) m_pDancer[pn]->DrawCelShaded(); else { DISPLAY->SetLighting( true ); DISPLAY->SetLightDirectional( 0, RageColor(0.5,0.5,0.5,1), RageColor(1,1,1,1), RageColor(0,0,0,1), RageVector3(0, 0, 1) ); FOREACH_PlayerNumber(pn) // Draw each dancer if(GAMESTATE->IsHumanPlayer(pn)) m_pDancer[pn]->Draw(); DISPLAY->SetLightOff(0); DISPLAY->SetLighting(false); } } void BeginnerHelper::Step( PlayerNumber pn, int CSTEP ) { m_pDancer[pn]->StopTweening(); m_pDancer[pn]->SetRotationY(0); // Make sure we're not still inside of a JUMPUD tween. switch(CSTEP) { case ST_LEFT: ShowStepCircle(pn, ST_LEFT); m_pDancer[pn]->PlayAnimation("Step-LEFT", 1.5f); break; case ST_RIGHT: ShowStepCircle(pn, ST_RIGHT); m_pDancer[pn]->PlayAnimation("Step-RIGHT", 1.5f); break; case ST_UP: ShowStepCircle(pn, ST_UP); m_pDancer[pn]->PlayAnimation("Step-UP", 1.5f); break; case ST_DOWN: ShowStepCircle(pn, ST_DOWN); m_pDancer[pn]->PlayAnimation("Step-DOWN", 1.5f); break; case ST_JUMPLR: ShowStepCircle(pn, ST_LEFT); ShowStepCircle(pn, ST_RIGHT); m_pDancer[pn]->PlayAnimation("Step-JUMPLR", 1.5f); break; case ST_JUMPUD: ShowStepCircle(pn, ST_UP); ShowStepCircle(pn, ST_DOWN); m_pDancer[pn]->StopTweening(); m_pDancer[pn]->PlayAnimation("Step-JUMPLR", 1.5f); m_pDancer[pn]->BeginTweening((GAMESTATE->m_fCurBPS /8), TWEEN_LINEAR); m_pDancer[pn]->SetRotationY(90); m_pDancer[pn]->BeginTweening((1/(GAMESTATE->m_fCurBPS * 2))); //sleep between jump-frames m_pDancer[pn]->BeginTweening(GAMESTATE->m_fCurBPS /6, TWEEN_LINEAR); m_pDancer[pn]->SetRotationY(0); break; } m_sFlash.StopEffect(); m_sFlash.StopTweening(); m_sFlash.Sleep(GAMESTATE->m_fCurBPS /16); m_sFlash.SetDiffuseAlpha(1); m_sFlash.BeginTweening(1/GAMESTATE->m_fCurBPS * 0.5f); m_sFlash.SetDiffuseAlpha(0); } void BeginnerHelper::Update( float fDeltaTime ) { if(!m_bInitialized) return; // the row we want to check on this update int iCurRow = BeatToNoteRowNotRounded(GAMESTATE->m_fSongBeat + 0.4f); FOREACH_EnabledPlayer( pn ) { for(int iRow=m_iLastRowChecked; iRowStep(pn, iStep); } } // Make sure we don't accidentally scan a row 2x m_iLastRowChecked = iCurRow; // Update animations ActorFrame::Update(fDeltaTime); m_pDancePad->Update(fDeltaTime); m_sFlash.Update(fDeltaTime); float beat = (fDeltaTime*GAMESTATE->m_fCurBPS); // If this is not a human player, the dancer is not shown FOREACH_HumanPlayer( pu ) { // Update dancer's animation and StepCircles m_pDancer[pu]->Update( beat ); for(int scu=0; scu