Files
itgmania212121/stepmania/src/BeginnerHelper.cpp
T
Chris Danford bcbe615c0d Pass ActorCommand structures to Actor instead of unparsed command strings.
This way, we can potentially do the parsing early and not parse inside of Actor as the command is executing.
2004-11-06 23:13:47 +00:00

391 lines
12 KiB
C++

#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-DDR.txt",
"DancePads-DDR.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()
{
}
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].SetEffectNone();
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; i<NUM_ANIMATIONS; ++i)
if(!DoesFileExist(GetAnimPath((Animation)i)))
return false;
return GAMESTATE->m_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; pn<NUM_PLAYERS; pn++)
if(m_bPlayerEnabled[pn])
bAnyLoaded = true;
if(!bAnyLoaded)
return false;
}
// Load the Background and flash.. Flash only shows if the BG does.
if(m_bShowBackground)
{
m_sBackground.Load( THEME->GetPathToG("BeginnerHelper background") );
this->AddChild(&m_sBackground);
m_sBackground.SetXY(SCREEN_CENTER_X, SCREEN_CENTER_Y);
m_sFlash.Load(THEME->GetPathToG("BeginnerHelper flash"));
m_sFlash.SetXY(SCREEN_CENTER_X, SCREEN_CENTER_Y);
m_sFlash.SetDiffuseAlpha(0);
}
// Load StepCircle graphics
for(int lsc=0; lsc<NUM_PLAYERS; lsc++)
for(int lsce=0; lsce<4; lsce++)
{
m_sStepCircle[lsc][lsce].Load(THEME->GetPathToG("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; pl<NUM_PLAYERS; pl++ ) // Load players
{
// Skip if not enabled
if(!m_bPlayerEnabled[pl])
continue;
// Load character data
const Character *Character = GAMESTATE->m_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 DDR PC character models 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; scd<NUM_PLAYERS; scd++)
for(int scde=0; scde<4; scde++)
m_sStepCircle[scd][scde].Draw();
if(DrawCelShaded)
FOREACH_PlayerNumber(pn) // Draw each dancer
if(GAMESTATE->IsHumanPlayer(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.SetEffectNone();
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; iRow<iCurRow; iRow++)
{
// Check if there are any notes at all on this row.. If not, save scanning.
if(!m_NoteData[pn].IsThereATapAtRow(iRow))
continue;
// Find all steps on this row, in order to show the correct animations
int iStep = 0;
const int iNumTracks = m_NoteData[pn].GetNumTracks();
for( int t=0; t<iNumTracks; t++ )
if( m_NoteData[pn].GetTapNote(t,iRow).type == TapNote::tap )
iStep |= 1 << t;
// Assign new data
this->Step(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<NUM_PLAYERS; scu++)
for(int scue=0; scue<4; scue++)
m_sStepCircle[scu][scue].Update(beat);
}
}
/*
* (c) 2003 Kevin Slaughter
* 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.
*/