Files
itgmania212121/stepmania/src/ScreenGameplay.cpp
T

2482 lines
76 KiB
C++
Raw Normal View History

2003-02-16 04:01:45 +00:00
#include "global.h"
2002-05-20 08:59:37 +00:00
#include "ScreenGameplay.h"
#include "SongManager.h"
#include "ScreenManager.h"
#include "GameConstantsAndTypes.h"
2002-07-23 01:41:40 +00:00
#include "PrefsManager.h"
2002-05-20 08:59:37 +00:00
#include "GameManager.h"
#include "SongManager.h"
#include "RageLog.h"
2002-07-23 01:41:40 +00:00
#include "LifeMeterBar.h"
#include "LifeMeterBattery.h"
#include "GameState.h"
#include "ScoreDisplayNormal.h"
2003-10-05 05:24:50 +00:00
#include "ScoreDisplayPercentage.h"
2002-07-23 01:41:40 +00:00
#include "ScoreDisplayOni.h"
2003-02-25 00:33:42 +00:00
#include "ScoreDisplayBattle.h"
2003-04-07 05:14:27 +00:00
#include "ScoreDisplayRave.h"
2002-07-27 19:29:51 +00:00
#include "ScreenPrompt.h"
#include "GrooveRadar.h"
2002-09-06 23:36:04 +00:00
#include "NotesLoaderSM.h"
#include "ThemeManager.h"
#include "RageTimer.h"
#include "ScoreKeeperMAX2.h"
2003-06-30 18:08:27 +00:00
#include "ScoreKeeperRave.h"
2003-04-02 21:57:25 +00:00
#include "NoteFieldPositioning.h"
#include "LyricsLoader.h"
2003-04-13 21:17:14 +00:00
#include "ActorUtil.h"
2003-04-22 04:54:04 +00:00
#include "NoteSkinManager.h"
#include "RageTextureManager.h"
2004-07-08 00:10:34 +00:00
#include "GameSoundManager.h"
2003-06-30 18:08:27 +00:00
#include "CombinedLifeMeterTug.h"
#include "Inventory.h"
2003-07-17 20:10:07 +00:00
#include "Course.h"
2003-08-07 06:36:34 +00:00
#include "NoteDataUtil.h"
2005-02-21 06:22:46 +00:00
#include "UnlockManager.h"
2003-11-16 04:45:12 +00:00
#include "LightsManager.h"
2003-12-17 10:21:31 +00:00
#include "ProfileManager.h"
2005-02-16 03:25:45 +00:00
#include "StatsManager.h"
2004-01-11 23:33:56 +00:00
#include "PlayerAI.h" // for NUM_SKILL_LEVELS
#include "NetworkSyncManager.h"
#include "Foreach.h"
2004-08-19 01:18:11 +00:00
#include "DancingCharacters.h"
#include "ScreenDimensions.h"
#include "ThemeMetric.h"
#include "PlayerState.h"
2005-01-15 02:01:26 +00:00
#include "Style.h"
2005-01-30 02:43:32 +00:00
#include "LuaManager.h"
#include "MemoryCardManager.h"
2005-03-20 09:52:48 +00:00
#include "CommonMetrics.h"
2002-05-20 08:59:37 +00:00
//
2002-07-23 01:41:40 +00:00
// Defines
2002-05-20 08:59:37 +00:00
//
#define PREV_SCREEN THEME->GetMetric (m_sName,"PrevScreen")
#define NEXT_SCREEN THEME->GetMetric (m_sName,"NextScreen")
#define SHOW_LIFE_METER_FOR_DISABLED_PLAYERS THEME->GetMetricB(m_sName,"ShowLifeMeterForDisabledPlayers")
#define EVAL_ON_FAIL THEME->GetMetricB(m_sName,"ShowEvaluationOnFail")
#define SHOW_SCORE_IN_RAVE THEME->GetMetricB(m_sName,"ShowScoreInRave")
#define SONG_POSITION_METER_WIDTH THEME->GetMetricF(m_sName,"SongPositionMeterWidth")
#define PLAYER_X( p, styleType ) THEME->GetMetricF(m_sName,ssprintf("PlayerP%d%sX",p+1,StyleTypeToString(styleType).c_str()))
2003-04-22 14:32:48 +00:00
2005-02-26 06:22:40 +00:00
static ThemeMetric<float> INITIAL_BACKGROUND_BRIGHTNESS ("ScreenGameplay","InitialBackgroundBrightness");
static ThemeMetric<float> SECONDS_BETWEEN_COMMENTS ("ScreenGameplay","SecondsBetweenComments");
2003-04-13 21:17:14 +00:00
2003-08-12 00:05:01 +00:00
/* Global, so it's accessible from ShowSavePrompt: */
static float g_fOldOffset; // used on offset screen to calculate difference
2003-04-13 21:17:14 +00:00
AutoScreenMessage( SM_PlayGo )
2002-05-20 08:59:37 +00:00
// received while STATE_DANCING
AutoScreenMessage( SM_LoadNextSong )
AutoScreenMessage( SM_StartLoadingNextSong )
2002-05-20 08:59:37 +00:00
// received while STATE_OUTRO
AutoScreenMessage( SM_SaveChangedBeforeGoingBack )
AutoScreenMessage( SM_GoToScreenAfterBack )
2002-05-20 08:59:37 +00:00
AutoScreenMessage( SM_BeginFailed )
2002-05-20 08:59:37 +00:00
// received while STATE_INTRO
AutoScreenMessage( SM_StartHereWeGo )
AutoScreenMessage( SM_StopHereWeGo )
2002-05-20 08:59:37 +00:00
static Preference<float> g_fNetStartOffset( Options, "NetworkStartOffset", -3.0 );
2003-10-25 07:58:10 +00:00
2004-11-26 17:28:47 +00:00
REGISTER_SCREEN_CLASS( ScreenGameplay );
ScreenGameplay::ScreenGameplay( CString sName ) : ScreenWithMenuElements(sName)
2002-05-20 08:59:37 +00:00
{
2005-02-26 06:22:40 +00:00
PLAYER_TYPE.Load( sName, "PlayerType" );
2005-03-12 00:04:27 +00:00
GIVE_UP_TEXT.Load( sName, "GiveUpText" );
GIVE_UP_ABORTED_TEXT.Load( sName, "GiveUpAbortedText" );
2005-03-23 02:11:33 +00:00
MUSIC_FADE_OUT_SECONDS.Load( sName, "MusicFadeOutSeconds" );
START_GIVES_UP.Load( sName, "StartGivesUp" );
BACK_GIVES_UP.Load( sName, "BackGivesUp" );
GIVING_UP_FAILS.Load( sName, "GivingUpFails" );
2004-02-18 02:31:43 +00:00
}
2002-05-20 08:59:37 +00:00
2004-02-18 02:31:43 +00:00
void ScreenGameplay::Init()
{
ScreenWithMenuElements::Init();
2005-01-03 22:44:19 +00:00
/* Pause MEMCARDMAN. If a memory card is remove, we don't want to interrupt the
* player by making a noise until the game finishes. */
2005-02-06 10:10:38 +00:00
if( !GAMESTATE->m_bDemonstrationOrJukebox )
MEMCARDMAN->PauseMountingThread();
2005-01-03 23:20:11 +00:00
if( GAMESTATE->m_bDemonstrationOrJukebox )
2004-03-23 06:11:10 +00:00
LIGHTSMAN->SetLightsMode( LIGHTSMODE_DEMONSTRATION );
2003-11-16 04:45:12 +00:00
else
LIGHTSMAN->SetLightsMode( LIGHTSMODE_GAMEPLAY );
2003-11-16 04:45:12 +00:00
2004-10-25 03:47:22 +00:00
m_pSoundMusic = NULL;
m_bPaused = false;
2004-10-25 03:47:22 +00:00
/* We do this ourself. */
SOUND->HandleSongTimer( false );
2003-12-18 08:53:38 +00:00
2003-11-13 00:39:36 +00:00
//need to initialize these before checking for demonstration mode
//otherwise destructor will try to delete possibly invalid pointers
2004-05-16 12:34:02 +00:00
FOREACH_PlayerNumber(p)
2003-11-13 00:39:36 +00:00
{
m_pLifeMeter[p] = NULL;
2003-11-26 06:40:03 +00:00
m_pPrimaryScoreDisplay[p] = NULL;
m_pSecondaryScoreDisplay[p] = NULL;
2003-11-13 00:39:36 +00:00
m_pPrimaryScoreKeeper[p] = NULL;
m_pSecondaryScoreKeeper[p] = NULL;
m_pInventory[p] = NULL ;
}
m_pCombinedLifeMeter = NULL;
2003-03-09 00:55:49 +00:00
2003-02-04 21:36:30 +00:00
if( GAMESTATE->m_pCurSong == NULL && GAMESTATE->m_pCurCourse == NULL )
2005-01-03 21:05:40 +00:00
return; // ScreenDemonstration will move us to the next screen. We just need to survive for one update without crashing.
2003-01-19 21:05:03 +00:00
/* Save selected options before we change them. */
GAMESTATE->StoreSelectedOptions();
/* Save settings to the profile now. Don't do this on extra stages, since the
* user doesn't have full control; saving would force profiles to DIFFICULTY_HARD
* and save over their default modifiers every time someone got an extra stage.
* Do this before course modifiers are set up. */
if( !GAMESTATE->IsExtraStage() && !GAMESTATE->IsExtraStage2() )
{
FOREACH_HumanPlayer( pn )
GAMESTATE->SaveCurrentSettingsToProfile(pn);
}
2005-02-23 04:46:05 +00:00
/* Called once per stage (single song or single course). */
GAMESTATE->BeginStage();
2003-04-14 22:12:54 +00:00
2003-04-07 21:24:14 +00:00
2002-08-28 22:42:40 +00:00
2002-08-02 09:31:06 +00:00
2003-04-07 21:24:14 +00:00
// fill in difficulty of CPU players with that of the first human player
2004-05-16 23:15:17 +00:00
FOREACH_PotentialCpuPlayer(p)
GAMESTATE->m_pCurSteps[p].Set( GAMESTATE->m_pCurSteps[ GAMESTATE->GetFirstHumanPlayer() ] );
2003-04-07 21:24:14 +00:00
2005-01-03 23:29:40 +00:00
/* Increment the course play count. */
if( GAMESTATE->IsCourseMode() && !GAMESTATE->m_bDemonstrationOrJukebox )
FOREACH_EnabledPlayer(p)
PROFILEMAN->IncrementCoursePlayCount( GAMESTATE->m_pCurCourse, GAMESTATE->m_pCurTrail[p], p );
2002-07-23 01:41:40 +00:00
2005-02-16 03:25:45 +00:00
STATSMAN->m_CurStageStats.playMode = GAMESTATE->m_PlayMode;
STATSMAN->m_CurStageStats.pStyle = GAMESTATE->m_pCurStyle;
2003-09-06 01:20:56 +00:00
/* Record combo rollover. */
FOREACH_EnabledPlayer(pn)
STATSMAN->m_CurStageStats.m_player[pn].UpdateComboList( 0, true );
2003-09-06 01:20:56 +00:00
if( GAMESTATE->IsExtraStage() )
2005-02-16 03:25:45 +00:00
STATSMAN->m_CurStageStats.StageType = StageStats::STAGE_EXTRA;
else if( GAMESTATE->IsExtraStage2() )
2005-02-16 03:25:45 +00:00
STATSMAN->m_CurStageStats.StageType = StageStats::STAGE_EXTRA2;
else
2005-02-16 03:25:45 +00:00
STATSMAN->m_CurStageStats.StageType = StageStats::STAGE_NORMAL;
2003-03-26 23:08:05 +00:00
//
// Init ScoreKeepers
//
2004-05-16 12:34:02 +00:00
2004-05-16 12:42:16 +00:00
FOREACH_EnabledPlayer(p)
2003-03-26 23:08:05 +00:00
{
2004-05-16 12:34:02 +00:00
switch( PREFSMAN->m_iScoringType )
{
2003-08-11 23:12:01 +00:00
case PrefsManager::SCORING_MAX2:
case PrefsManager::SCORING_5TH:
m_pPrimaryScoreKeeper[p] = new ScoreKeeperMAX2(
GAMESTATE->m_pPlayerState[p],
2005-02-16 03:25:45 +00:00
&STATSMAN->m_CurStageStats.m_player[p] );
break;
2003-08-11 23:12:01 +00:00
default: ASSERT(0);
}
2003-06-30 18:08:27 +00:00
switch( GAMESTATE->m_PlayMode )
{
case PLAY_MODE_RAVE:
m_pSecondaryScoreKeeper[p] = new ScoreKeeperRave(
GAMESTATE->m_pPlayerState[p],
2005-02-16 03:25:45 +00:00
&STATSMAN->m_CurStageStats.m_player[p] );
2003-06-30 18:08:27 +00:00
break;
}
2002-06-14 22:25:22 +00:00
}
m_bChangedOffsetOrBPM = GAMESTATE->m_SongOptions.m_bAutoSync;
2002-07-28 20:28:37 +00:00
2002-05-20 08:59:37 +00:00
m_DancingState = STATE_INTRO;
// Set this in LoadNextSong()
//m_fTimeLeftBeforeDancingComment = SECONDS_BETWEEN_COMMENTS;
2003-04-13 00:44:50 +00:00
m_bZeroDeltaOnNextUpdate = false;
// init old offset in case offset changes in song
2003-08-12 00:05:01 +00:00
if( GAMESTATE->IsCourseMode() )
g_fOldOffset = -1000;
else
2003-12-18 04:48:26 +00:00
g_fOldOffset = GAMESTATE->m_pCurSong->m_Timing.m_fBeat0OffsetInSeconds;
m_SongBackground.SetName( "SongBackground" );
m_SongBackground.SetDrawOrder( DRAW_ORDER_BEFORE_EVERYTHING );
ON_COMMAND( m_SongBackground );
this->AddChild( &m_SongBackground );
2004-01-07 00:13:32 +00:00
m_SongForeground.SetName( "SongForeground" );
m_SongForeground.SetDrawOrder( DRAW_ORDER_OVERLAY+1 ); // on top of the overlay, but under transitions
ON_COMMAND( m_SongBackground );
this->AddChild( &m_SongForeground );
2004-01-07 00:13:32 +00:00
2005-03-11 02:06:39 +00:00
if( PREFSMAN->m_bShowBeginnerHelper )
{
m_BeginnerHelper.SetDrawOrder( DRAW_ORDER_BEFORE_EVERYTHING );
m_BeginnerHelper.SetXY( SCREEN_CENTER_X, SCREEN_CENTER_Y );
this->AddChild( &m_BeginnerHelper );
}
2003-10-08 23:32:08 +00:00
2003-10-09 06:43:51 +00:00
m_sprStaticBackground.SetName( "StaticBG" );
m_sprStaticBackground.Load( THEME->GetPathG(m_sName,"Static Background") );
2003-10-09 06:43:51 +00:00
SET_XY( m_sprStaticBackground );
2004-05-02 03:01:27 +00:00
m_sprStaticBackground.SetDrawOrder( DRAW_ORDER_BEFORE_EVERYTHING ); // behind everything else
2003-10-08 23:32:08 +00:00
this->AddChild(&m_sprStaticBackground);
2002-05-27 08:23:27 +00:00
2005-01-03 23:20:11 +00:00
if( !GAMESTATE->m_bDemonstrationOrJukebox ) // only load if we're going to use it
2003-04-13 23:22:27 +00:00
{
m_Toasty.Load( THEME->GetPathB(m_sName,"toasty") );
2003-04-13 23:22:27 +00:00
this->AddChild( &m_Toasty );
}
2004-05-16 12:34:02 +00:00
FOREACH_EnabledPlayer(p)
2002-05-20 08:59:37 +00:00
{
float fPlayerX = PLAYER_X( p, GAMESTATE->GetCurrentStyle()->m_StyleType );
/* Perhaps this should be handled better by defining a new
* StyleType for ONE_PLAYER_ONE_CREDIT_AND_ONE_COMPUTER,
* but for now just ignore SoloSingles when it's Battle or Rave
* Mode. This doesn't begin to address two-player solo (6 arrows) */
if( PREFSMAN->m_bSoloSingle &&
GAMESTATE->m_PlayMode != PLAY_MODE_BATTLE &&
GAMESTATE->m_PlayMode != PLAY_MODE_RAVE &&
GAMESTATE->GetCurrentStyle()->m_StyleType == ONE_PLAYER_ONE_SIDE )
fPlayerX = SCREEN_CENTER_X;
2004-07-10 18:37:39 +00:00
m_Player[p].SetName( ssprintf("Player%i", p+1) );
2002-08-01 21:55:40 +00:00
m_Player[p].SetX( fPlayerX );
m_Player[p].SetY( SCREEN_CENTER_Y );
this->AddChild( &m_Player[p] );
2002-08-01 21:55:40 +00:00
2004-07-10 18:37:39 +00:00
m_sprOniGameOver[p].SetName( ssprintf("OniGameOver%i", p+1) );
m_sprOniGameOver[p].Load( THEME->GetPathG(m_sName,"oni gameover") );
2002-08-01 21:55:40 +00:00
m_sprOniGameOver[p].SetX( fPlayerX );
m_sprOniGameOver[p].SetY( SCREEN_TOP - m_sprOniGameOver[p].GetZoomedHeight()/2 );
m_sprOniGameOver[p].SetDiffuse( RageColor(1,1,1,0) ); // 0 alpha so we don't waste time drawing while not visible
this->AddChild( &m_sprOniGameOver[p] );
2002-05-20 08:59:37 +00:00
}
m_NextSong.Load( THEME->GetPathB(m_sName,"next course song") );
m_NextSong.SetDrawOrder( DRAW_ORDER_TRANSITIONS-1 );
this->AddChild( &m_NextSong );
2002-08-01 21:55:40 +00:00
2004-05-02 03:01:27 +00:00
m_SongFinished.SetDrawOrder( DRAW_ORDER_TRANSITIONS-1 );
this->AddChild( &m_SongFinished );
2002-06-14 22:25:22 +00:00
2005-02-06 03:32:53 +00:00
bool bBattery = GAMESTATE->m_SongOptions.m_LifeType==SongOptions::LIFE_BATTERY;
2003-11-19 12:33:52 +00:00
//
// Add LifeFrame
//
2005-02-06 03:32:53 +00:00
m_sprLifeFrame.Load( THEME->GetPathG(m_sName,bBattery?"oni life frame":"life frame") );
m_sprLifeFrame.SetName( "LifeFrame" );
2003-04-13 21:17:14 +00:00
SET_XY( m_sprLifeFrame );
2002-10-18 19:01:32 +00:00
this->AddChild( &m_sprLifeFrame );
//
2003-11-19 12:33:52 +00:00
// Add score frame
//
2005-02-06 03:32:53 +00:00
m_sprScoreFrame.Load( THEME->GetPathG(m_sName,bBattery?"oni score frame":"score frame") );
m_sprScoreFrame.SetName( "ScoreFrame" );
2003-11-19 12:33:52 +00:00
SET_XY( m_sprScoreFrame );
this->AddChild( &m_sprScoreFrame );
//
// Add combined life meter
//
switch( GAMESTATE->m_PlayMode )
{
2003-08-19 04:27:50 +00:00
case PLAY_MODE_BATTLE:
case PLAY_MODE_RAVE:
2003-08-19 04:27:50 +00:00
m_pCombinedLifeMeter = new CombinedLifeMeterTug;
m_pCombinedLifeMeter->SetName( "CombinedLife" );
SET_XY( *m_pCombinedLifeMeter );
this->AddChild( m_pCombinedLifeMeter );
break;
}
//
// Before the lifemeter loads, if Networking is required
// we need to wait, so that there is no Dead On Start issues.
// if you wait too long at the second checkpoint, you will
// appear dead when you begin your game.
//
NSMAN->StartRequest(0);
//
2003-11-19 12:33:52 +00:00
// Add individual life meter
//
2003-06-30 18:08:27 +00:00
switch( GAMESTATE->m_PlayMode )
2002-05-20 08:59:37 +00:00
{
case PLAY_MODE_REGULAR:
2003-06-30 18:08:27 +00:00
case PLAY_MODE_ONI:
case PLAY_MODE_NONSTOP:
case PLAY_MODE_ENDLESS:
2004-05-16 19:22:37 +00:00
FOREACH_PlayerNumber(p)
2003-06-30 18:08:27 +00:00
{
2004-05-16 19:22:37 +00:00
if( !GAMESTATE->IsPlayerEnabled(p) && !SHOW_LIFE_METER_FOR_DISABLED_PLAYERS )
continue; // skip
2003-06-30 18:08:27 +00:00
switch( GAMESTATE->m_SongOptions.m_LifeType )
{
case SongOptions::LIFE_BAR:
m_pLifeMeter[p] = new LifeMeterBar;
break;
case SongOptions::LIFE_BATTERY:
m_pLifeMeter[p] = new LifeMeterBattery;
break;
default:
ASSERT(0);
}
m_pLifeMeter[p]->Load( p );
m_pLifeMeter[p]->SetName( ssprintf("LifeP%d",p+1) );
2003-06-30 18:08:27 +00:00
SET_XY( *m_pLifeMeter[p] );
this->AddChild( m_pLifeMeter[p] );
}
break;
2003-11-19 12:33:52 +00:00
case PLAY_MODE_BATTLE:
case PLAY_MODE_RAVE:
break;
2002-05-20 08:59:37 +00:00
}
m_ShowScoreboard=false;
2004-08-14 22:58:57 +00:00
2004-08-13 08:24:11 +00:00
//the following is only used in SMLAN/SMOnline
if( NSMAN->useSMserver && ( !GAMESTATE->PlayerUsingBothSides() ) )
2004-08-13 08:24:11 +00:00
{
2004-12-01 20:42:15 +00:00
PlayerNumber pn = GAMESTATE->GetFirstDisabledPlayer();
if( pn != PLAYER_INVALID )
{
FOREACH_NSScoreBoardColumn( col )
{
2004-12-01 20:42:15 +00:00
m_Scoreboard[col].LoadFromFont( THEME->GetPathF(m_sName,"scoreboard") );
m_Scoreboard[col].SetShadowLength( 0 );
m_Scoreboard[col].SetName( ssprintf("ScoreboardC%iP%i",col+1,pn+1) );
SET_XY( m_Scoreboard[col] );
this->AddChild( &m_Scoreboard[col] );
m_Scoreboard[col].SetText( NSMAN->m_Scoreboard[col] );
m_Scoreboard[col].SetVertAlign( align_top );
m_ShowScoreboard = true;
}
2004-12-01 20:42:15 +00:00
}
2004-08-13 08:24:11 +00:00
}
2002-07-23 01:41:40 +00:00
2004-07-25 06:29:50 +00:00
m_MaxCombo.LoadFromFont( THEME->GetPathF(m_sName,"max combo") );
2003-04-13 21:17:14 +00:00
m_MaxCombo.SetName( "MaxCombo" );
SET_XY( m_MaxCombo );
2005-02-16 03:25:45 +00:00
m_MaxCombo.SetText( ssprintf("%d", STATSMAN->m_CurStageStats.m_player[GAMESTATE->m_MasterPlayerNumber].iMaxCombo) ); // TODO: Make this work for both players
this->AddChild( &m_MaxCombo );
2004-05-16 12:34:02 +00:00
FOREACH_EnabledPlayer(p)
2002-05-20 08:59:37 +00:00
{
2003-11-26 06:40:03 +00:00
//
// primary score display
//
2002-08-28 22:42:40 +00:00
switch( GAMESTATE->m_PlayMode )
{
case PLAY_MODE_REGULAR:
case PLAY_MODE_NONSTOP:
2003-11-19 12:33:52 +00:00
case PLAY_MODE_BATTLE:
2003-11-26 06:40:03 +00:00
case PLAY_MODE_RAVE:
2003-10-05 05:24:50 +00:00
if( PREFSMAN->m_bPercentageScoring )
2003-11-26 06:40:03 +00:00
m_pPrimaryScoreDisplay[p] = new ScoreDisplayPercentage;
2003-10-05 05:24:50 +00:00
else
2003-11-26 06:40:03 +00:00
m_pPrimaryScoreDisplay[p] = new ScoreDisplayNormal;
2002-08-28 22:42:40 +00:00
break;
case PLAY_MODE_ONI:
case PLAY_MODE_ENDLESS:
2003-11-26 06:40:03 +00:00
m_pPrimaryScoreDisplay[p] = new ScoreDisplayOni;
2003-04-07 05:14:27 +00:00
break;
2002-08-28 22:42:40 +00:00
default:
ASSERT(0);
}
m_pPrimaryScoreDisplay[p]->Init( GAMESTATE->m_pPlayerState[p] );
m_pPrimaryScoreDisplay[p]->SetName( ssprintf("ScoreP%d",p+1) );
2003-11-26 06:40:03 +00:00
SET_XY( *m_pPrimaryScoreDisplay[p] );
2003-12-22 05:20:13 +00:00
if( GAMESTATE->m_PlayMode != PLAY_MODE_RAVE || SHOW_SCORE_IN_RAVE ) /* XXX: ugly */
this->AddChild( m_pPrimaryScoreDisplay[p] );
2003-11-26 06:40:03 +00:00
//
// secondary score display
//
switch( GAMESTATE->m_PlayMode )
{
case PLAY_MODE_RAVE:
m_pSecondaryScoreDisplay[p] = new ScoreDisplayRave;
break;
}
if( m_pSecondaryScoreDisplay[p] )
{
m_pSecondaryScoreDisplay[p]->Init( GAMESTATE->m_pPlayerState[p] );
m_pSecondaryScoreDisplay[p]->SetName( ssprintf("SecondaryScoreP%d",p+1) );
2003-11-26 06:40:03 +00:00
SET_XY( *m_pSecondaryScoreDisplay[p] );
this->AddChild( m_pSecondaryScoreDisplay[p] );
}
}
2003-11-29 11:16:36 +00:00
//
// Add stage / SongNumber
//
m_sprStage.SetName( "Stage" );
2003-11-29 11:16:36 +00:00
SET_XY( m_sprStage );
2003-12-18 23:19:02 +00:00
m_sprCourseSongNumber.SetName( "CourseSongNumber" );
SET_XY( m_sprCourseSongNumber );
2003-11-29 11:16:36 +00:00
2004-05-16 02:51:55 +00:00
FOREACH_EnabledPlayer(p)
2003-11-29 11:16:36 +00:00
{
2004-07-25 06:29:50 +00:00
m_textCourseSongNumber[p].LoadFromFont( THEME->GetPathF(m_sName,"song num") );
m_textCourseSongNumber[p].SetShadowLength( 0 );
m_textCourseSongNumber[p].SetName( ssprintf("SongNumberP%d",p+1) );
2003-11-29 11:16:36 +00:00
SET_XY( m_textCourseSongNumber[p] );
m_textCourseSongNumber[p].SetText( "" );
m_textCourseSongNumber[p].SetDiffuse( RageColor(0,0.5f,1,1) ); // light blue
}
2004-05-16 02:51:55 +00:00
FOREACH_EnabledPlayer(p)
{
m_textStepsDescription[p].LoadFromFont( THEME->GetPathF(m_sName,"StepsDescription") );
m_textStepsDescription[p].SetName( ssprintf("StepsDescriptionP%i",p+1) );
SET_XY( m_textStepsDescription[p] );
this->AddChild( &m_textStepsDescription[p] );
}
2003-11-29 11:16:36 +00:00
switch( GAMESTATE->m_PlayMode )
{
case PLAY_MODE_REGULAR:
2003-11-29 11:16:36 +00:00
case PLAY_MODE_BATTLE:
case PLAY_MODE_RAVE:
m_sprStage.Load( THEME->GetPathG(m_sName,"stage "+GAMESTATE->GetStageText()) );
2003-11-29 11:16:36 +00:00
this->AddChild( &m_sprStage );
break;
case PLAY_MODE_NONSTOP:
case PLAY_MODE_ONI:
case PLAY_MODE_ENDLESS:
2003-12-18 23:19:02 +00:00
this->AddChild( &m_sprCourseSongNumber );
FOREACH_EnabledPlayer( p )
this->AddChild( &m_textCourseSongNumber[p] );
2003-11-29 11:16:36 +00:00
break;
default:
ASSERT(0); // invalid GameMode
}
m_sprStageFrame.Load( THEME->GetPathG(m_sName,"stage frame") );
2004-02-15 00:48:24 +00:00
m_sprStageFrame->SetName( "StageFrame" );
2004-02-14 00:39:24 +00:00
SET_XY( m_sprStageFrame );
2004-02-15 00:48:24 +00:00
this->AddChild( m_sprStageFrame );
2003-11-29 11:16:36 +00:00
//
// Player/Song options
//
FOREACH_EnabledPlayer(p)
{
m_textPlayerOptions[p].LoadFromFont( THEME->GetPathF(m_sName,"player options") );
m_textPlayerOptions[p].SetShadowLength( 0 );
m_textPlayerOptions[p].SetName( ssprintf("PlayerOptionsP%d",p+1) );
2003-04-13 21:17:14 +00:00
SET_XY( m_textPlayerOptions[p] );
this->AddChild( &m_textPlayerOptions[p] );
2002-05-20 08:59:37 +00:00
}
m_textSongOptions.LoadFromFont( THEME->GetPathF(m_sName,"song options") );
m_textSongOptions.SetShadowLength( 0 );
m_textSongOptions.SetName( "SongOptions" );
2003-04-13 21:17:14 +00:00
SET_XY( m_textSongOptions );
m_textSongOptions.SetText( GAMESTATE->m_SongOptions.GetString() );
this->AddChild( &m_textSongOptions );
2002-06-14 22:25:22 +00:00
FOREACH_EnabledPlayer( pn )
2004-03-17 06:01:17 +00:00
{
m_ActiveAttackList[pn].LoadFromFont( THEME->GetPathF(m_sName,"ActiveAttackList") );
m_ActiveAttackList[pn].Init( GAMESTATE->m_pPlayerState[pn] );
m_ActiveAttackList[pn].SetName( ssprintf("ActiveAttackListP%d",pn+1) );
SET_XY( m_ActiveAttackList[pn] );
this->AddChild( &m_ActiveAttackList[pn] );
2004-03-17 06:01:17 +00:00
}
2002-06-14 22:25:22 +00:00
2003-11-29 11:16:36 +00:00
FOREACH_EnabledPlayer(p)
2002-06-14 22:25:22 +00:00
{
m_DifficultyIcon[p].Load( THEME->GetPathG(m_sName,ssprintf("difficulty icons %dx%d",NUM_PLAYERS,NUM_DIFFICULTIES)) );
/* Position it in LoadNextSong. */
2002-10-06 16:56:58 +00:00
this->AddChild( &m_DifficultyIcon[p] );
m_DifficultyMeter[p].Load( m_sName + ssprintf(" DifficultyMeterP%d",p+1) );
/* Position it in LoadNextSong. */
this->AddChild( &m_DifficultyMeter[p] );
2002-06-14 22:25:22 +00:00
}
2004-12-01 20:42:15 +00:00
if( PREFSMAN->m_bShowLyrics )
this->AddChild( &m_LyricDisplay );
m_textAutoPlay.LoadFromFont( THEME->GetPathF(m_sName,"autoplay") );
2003-04-13 21:17:14 +00:00
m_textAutoPlay.SetName( "AutoPlay" );
SET_XY( m_textAutoPlay );
2005-01-03 23:20:11 +00:00
if( !GAMESTATE->m_bDemonstrationOrJukebox ) // only load if we're not in demonstration or jukebox
this->AddChild( &m_textAutoPlay );
UpdateAutoPlayText();
2002-06-24 22:04:31 +00:00
2002-05-20 08:59:37 +00:00
2003-11-17 03:34:13 +00:00
m_BPMDisplay.SetName( "BPMDisplay" );
2003-11-14 18:31:28 +00:00
m_BPMDisplay.Load();
2003-04-13 21:17:14 +00:00
SET_XY( m_BPMDisplay );
2003-03-09 00:55:49 +00:00
this->AddChild( &m_BPMDisplay );
2004-12-18 08:15:19 +00:00
m_fLastBPS = 0;
2003-03-09 00:55:49 +00:00
2003-07-15 20:05:00 +00:00
ZERO( m_pInventory );
2005-03-18 03:17:52 +00:00
FOREACH_PlayerNumber(p)
{
2003-11-20 06:50:05 +00:00
// switch( GAMESTATE->m_PlayMode )
// {
// case PLAY_MODE_BATTLE:
// m_pInventory[p] = new Inventory;
// m_pInventory[p]->Load( p );
2003-11-20 06:50:05 +00:00
// this->AddChild( m_pInventory[p] );
// break;
// }
}
2002-05-20 08:59:37 +00:00
2005-01-03 23:20:11 +00:00
if( !GAMESTATE->m_bDemonstrationOrJukebox ) // only load if we're going to use it
2003-03-09 00:55:49 +00:00
{
m_Ready.Load( THEME->GetPathB(m_sName,"ready") );
2003-03-09 00:55:49 +00:00
this->AddChild( &m_Ready );
2002-05-20 08:59:37 +00:00
m_Go.Load( THEME->GetPathB(m_sName,"go") );
2003-03-09 00:55:49 +00:00
this->AddChild( &m_Go );
2002-05-20 08:59:37 +00:00
m_Cleared.Load( THEME->GetPathB(m_sName,"cleared") );
2004-05-02 03:01:27 +00:00
m_Cleared.SetDrawOrder( DRAW_ORDER_TRANSITIONS-1 ); // on top of everything else
2003-03-09 00:55:49 +00:00
this->AddChild( &m_Cleared );
m_Failed.Load( THEME->GetPathB(m_sName,"failed") );
2004-05-02 03:01:27 +00:00
m_Failed.SetDrawOrder( DRAW_ORDER_TRANSITIONS-1 ); // on top of everything else
2003-03-09 00:55:49 +00:00
this->AddChild( &m_Failed );
2002-07-27 19:29:51 +00:00
2003-10-17 08:03:46 +00:00
if( PREFSMAN->m_bAllowExtraStage && GAMESTATE->IsFinalStage() ) // only load if we're going to use it
m_Extra.Load( THEME->GetPathB(m_sName,"extra1") );
2003-10-17 08:03:46 +00:00
if( PREFSMAN->m_bAllowExtraStage && GAMESTATE->IsExtraStage() ) // only load if we're going to use it
m_Extra.Load( THEME->GetPathB(m_sName,"extra2") );
2003-03-09 00:55:49 +00:00
this->AddChild( &m_Extra );
2002-08-01 13:42:56 +00:00
2003-04-14 22:12:54 +00:00
// only load if we're going to use it
switch( GAMESTATE->m_PlayMode )
{
2003-08-19 04:27:50 +00:00
case PLAY_MODE_BATTLE:
case PLAY_MODE_RAVE:
2004-05-16 08:48:54 +00:00
FOREACH_PlayerNumber(p)
2003-04-14 22:12:54 +00:00
{
m_Win[p].Load( THEME->GetPathB(m_sName,ssprintf("win p%d",p+1)) );
2003-04-14 22:12:54 +00:00
this->AddChild( &m_Win[p] );
}
m_Draw.Load( THEME->GetPathB(m_sName,"draw") );
this->AddChild( &m_Draw );
2003-04-14 22:12:54 +00:00
break;
}
m_textDebug.LoadFromFont( THEME->GetPathF("Common","normal") );
2003-04-13 21:17:14 +00:00
m_textDebug.SetName( "Debug" );
SET_XY( m_textDebug );
2005-03-12 07:27:48 +00:00
m_textDebug.SetDrawOrder( DRAW_ORDER_TRANSITIONS-1 ); // just under transitions, over the foreground
this->AddChild( &m_textDebug );
2003-03-09 00:55:49 +00:00
2003-03-30 20:18:46 +00:00
if( GAMESTATE->IsExtraStage() || GAMESTATE->IsExtraStage2() ) // only load if we're going to use it
2003-03-09 00:55:49 +00:00
{
m_textSurviveTime.LoadFromFont( THEME->GetPathF(m_sName,"survive time") );
m_textSurviveTime.SetShadowLength( 0 );
2003-04-13 21:17:14 +00:00
m_textSurviveTime.SetName( "SurviveTime" );
SET_XY( m_textSurviveTime );
2004-05-02 03:01:27 +00:00
m_textSurviveTime.SetDrawOrder( DRAW_ORDER_TRANSITIONS-1 );
2003-03-09 00:55:49 +00:00
m_textSurviveTime.SetDiffuse( RageColor(1,1,1,0) );
this->AddChild( &m_textSurviveTime );
}
}
m_SongBackground.Init();
2003-02-04 21:36:30 +00:00
2005-01-03 23:20:11 +00:00
if( !GAMESTATE->m_bDemonstrationOrJukebox ) // only load if we're going to use it
2003-01-19 04:44:22 +00:00
{
m_soundAssistTick.Load( THEME->GetPathS(m_sName,"assist tick"), true );
2003-05-13 13:35:32 +00:00
switch( GAMESTATE->m_PlayMode )
2003-05-13 13:35:32 +00:00
{
2003-08-19 04:27:50 +00:00
case PLAY_MODE_BATTLE:
m_soundBattleTrickLevel1.Load( THEME->GetPathS(m_sName,"battle trick level1"), true );
m_soundBattleTrickLevel2.Load( THEME->GetPathS(m_sName,"battle trick level2"), true );
m_soundBattleTrickLevel3.Load( THEME->GetPathS(m_sName,"battle trick level3"), true );
break;
2003-05-13 13:35:32 +00:00
}
2003-03-09 00:55:49 +00:00
}
FOREACH_EnabledPlayer(pn)
2005-03-18 03:17:52 +00:00
m_Player[pn].Init(
PLAYER_TYPE,
GAMESTATE->m_pPlayerState[pn],
&STATSMAN->m_CurStageStats.m_player[pn],
m_pLifeMeter[pn],
m_pCombinedLifeMeter,
m_pPrimaryScoreDisplay[pn],
m_pSecondaryScoreDisplay[pn],
m_pInventory[pn],
m_pPrimaryScoreKeeper[pn],
m_pSecondaryScoreKeeper[pn] );
//
// fill in m_apSongsQueue, m_vpStepsQueue, m_asModifiersQueue
//
InitSongQueues();
FOREACH_EnabledPlayer(pn)
ASSERT( !m_vpStepsQueue[pn].empty() );
FOREACH_EnabledPlayer(pn)
{
if( m_pPrimaryScoreKeeper[pn] )
m_pPrimaryScoreKeeper[pn]->Load( m_apSongsQueue, m_vpStepsQueue[pn], m_asModifiersQueue[pn] );
if( m_pSecondaryScoreKeeper[pn] )
m_pSecondaryScoreKeeper[pn]->Load( m_apSongsQueue, m_vpStepsQueue[pn], m_asModifiersQueue[pn] );
}
2005-03-18 02:57:03 +00:00
/* LoadNextSong first, since that positions some elements which need to be
* positioned before we TweenOnScreen. */
LoadNextSong();
TweenOnScreen();
this->SortByDrawOrder();
m_GiveUpTimer.SetZero();
// Get the transitions rolling on the first update.
// We can't do this in the constructor because ScreenGameplay is constructed
// in the middle of ScreenStage.
2002-05-20 08:59:37 +00:00
}
2005-01-03 23:29:40 +00:00
//
// fill in m_apSongsQueue, m_vpStepsQueue, m_asModifiersQueue
//
void ScreenGameplay::InitSongQueues()
{
LOG->Trace("InitSongQueues");
if( GAMESTATE->IsCourseMode() )
{
Course* pCourse = GAMESTATE->m_pCurCourse;
ASSERT( pCourse );
m_apSongsQueue.clear();
PlayerNumber pnMaster = GAMESTATE->m_MasterPlayerNumber;
Trail *pTrail = GAMESTATE->m_pCurTrail[pnMaster];
2005-01-31 04:41:25 +00:00
ASSERT( pTrail );
2005-01-03 23:29:40 +00:00
FOREACH_CONST( TrailEntry, pTrail->m_vEntries, e )
2005-01-31 04:41:25 +00:00
{
ASSERT( e->pSong );
2005-01-03 23:29:40 +00:00
m_apSongsQueue.push_back( e->pSong );
2005-01-31 04:41:25 +00:00
}
2005-01-03 23:29:40 +00:00
FOREACH_EnabledPlayer(p)
{
Trail *pTrail = GAMESTATE->m_pCurTrail[p];
ASSERT( pTrail );
m_vpStepsQueue[p].clear();
m_asModifiersQueue[p].clear();
FOREACH_CONST( TrailEntry, pTrail->m_vEntries, e )
{
2005-01-31 04:41:25 +00:00
ASSERT( e->pSteps );
2005-01-03 23:29:40 +00:00
m_vpStepsQueue[p].push_back( e->pSteps );
AttackArray a;
e->GetAttackArray( a );
m_asModifiersQueue[p].push_back( a );
}
}
}
else
{
m_apSongsQueue.push_back( GAMESTATE->m_pCurSong );
FOREACH_PlayerNumber(p)
{
m_vpStepsQueue[p].push_back( GAMESTATE->m_pCurSteps[p] );
m_asModifiersQueue[p].push_back( AttackArray() );
}
}
}
2002-05-20 08:59:37 +00:00
ScreenGameplay::~ScreenGameplay()
{
if( this->IsFirstUpdate() )
{
/* We never received any updates. That means we were deleted without being
* used, and never actually played. (This can happen when backing out of
* ScreenStage.) Cancel the stage. */
GAMESTATE->CancelStage();
}
LOG->Trace( "ScreenGameplay::~ScreenGameplay()" );
2002-07-23 01:41:40 +00:00
2005-02-06 10:10:38 +00:00
if( !GAMESTATE->m_bDemonstrationOrJukebox )
MEMCARDMAN->UnPauseMountingThread();
2004-05-16 08:48:54 +00:00
FOREACH_PlayerNumber(p)
2002-07-23 01:41:40 +00:00
{
2002-08-28 22:42:40 +00:00
SAFE_DELETE( m_pLifeMeter[p] );
2003-11-26 06:40:03 +00:00
SAFE_DELETE( m_pPrimaryScoreDisplay[p] );
SAFE_DELETE( m_pSecondaryScoreDisplay[p] );
SAFE_DELETE( m_pSecondaryScoreDisplay[p] );
2003-06-30 18:08:27 +00:00
SAFE_DELETE( m_pPrimaryScoreKeeper[p] );
SAFE_DELETE( m_pSecondaryScoreKeeper[p] );
SAFE_DELETE( m_pInventory[p] );
2002-07-23 01:41:40 +00:00
}
2003-06-30 18:08:27 +00:00
SAFE_DELETE( m_pCombinedLifeMeter );
2004-11-05 06:36:49 +00:00
if( m_pSoundMusic )
m_pSoundMusic->StopPlaying();
2003-05-13 13:35:32 +00:00
2004-01-12 09:36:01 +00:00
m_soundAssistTick.StopPlaying(); /* Stop any queued assist ticks. */
2004-12-03 01:29:23 +00:00
NSMAN->ReportSongOver();
2002-05-20 08:59:37 +00:00
}
2002-07-28 20:28:37 +00:00
bool ScreenGameplay::IsLastSong()
2002-06-24 22:04:31 +00:00
{
2003-03-26 23:08:05 +00:00
if( GAMESTATE->m_pCurCourse && GAMESTATE->m_pCurCourse->m_bRepeat )
return false;
return GAMESTATE->GetCourseSongIndex()+1 == (int)m_apSongsQueue.size(); // GetCourseSongIndex() is 0-based but size() is not
2002-07-28 20:28:37 +00:00
}
2002-06-24 22:04:31 +00:00
void ScreenGameplay::SetupSong( PlayerNumber p, int iSongIndex )
2003-12-23 02:18:27 +00:00
{
/* This is the first beat that can be changed without it being visible. Until
* we draw for the first time, any beat can be changed. */
GAMESTATE->m_pPlayerState[p]->m_fLastDrawnBeat = -100;
GAMESTATE->m_pCurSteps[p].Set( m_vpStepsQueue[p][iSongIndex] );
2003-12-23 02:18:27 +00:00
/* Load new NoteData into Player. Do this before
* RebuildPlayerOptionsFromActiveAttacks or else transform mods will get
* propogated to GAMESTATE->m_PlayerOptions too early and be double-applied
* to the NoteData:
* once in Player::Load, then again in Player::ApplyActiveAttacks. This
* is very bad for transforms like AddMines.
*/
2004-10-23 17:43:49 +00:00
NoteData originalNoteData;
GAMESTATE->m_pCurSteps[p]->GetNoteData( originalNoteData );
const Style* pStyle = GAMESTATE->GetCurrentStyle();
2004-10-24 10:45:30 +00:00
NoteData ndTransformed;
pStyle->GetTransformedNoteDataForStyle( p, originalNoteData, ndTransformed );
// load player
{
NoteData nd = ndTransformed;
NoteDataUtil::RemoveAllTapsOfType( nd, TapNote::autoKeysound );
m_Player[p].Load( nd );
2004-10-24 10:45:30 +00:00
}
// load auto keysounds
{
NoteData nd = ndTransformed;
NoteDataUtil::RemoveAllTapsExceptForType( nd, TapNote::autoKeysound );
m_AutoKeysounds.Load( p, nd );
}
// Put course options into effect. Do this after Player::Load so
// that mods aren't double-applied.
GAMESTATE->m_pPlayerState[p]->m_ModsToApply.clear();
2003-12-23 02:18:27 +00:00
for( unsigned i=0; i<m_asModifiersQueue[p][iSongIndex].size(); ++i )
{
Attack a = m_asModifiersQueue[p][iSongIndex][i];
if( a.fStartSecond == 0 )
a.fStartSecond = -1; // now
GAMESTATE->LaunchAttack( p, a );
GAMESTATE->m_SongOptions.FromString( a.sModifier );
2003-12-23 02:18:27 +00:00
}
// UGLY: Force updating the BeatToNoteSkin mapping and cache NoteSkins now, or else
// we'll do it on the first update and skip.
m_Player[p].ApplyWaitingTransforms();
/* Update attack bOn flags. */
GAMESTATE->Update(0);
GAMESTATE->RebuildPlayerOptionsFromActiveAttacks( p );
/* Hack: Course modifiers that are set to start immediately shouldn't tween on. */
GAMESTATE->m_pPlayerState[p]->m_CurrentPlayerOptions = GAMESTATE->m_pPlayerState[p]->m_PlayerOptions;
2003-12-23 02:18:27 +00:00
}
2004-02-14 00:39:24 +00:00
void ScreenGameplay::LoadCourseSongNumber( int SongNumber )
{
if( !GAMESTATE->IsCourseMode() )
return;
2005-02-26 19:31:34 +00:00
const CString path = THEME->GetPathG( m_sName, ssprintf("course song %i",SongNumber+1), true );
2004-02-14 00:39:24 +00:00
if( path != "" )
m_sprCourseSongNumber.Load( path );
else
m_sprCourseSongNumber.UnloadTexture();
}
void ScreenGameplay::LoadNextSong()
2002-07-28 20:28:37 +00:00
{
GAMESTATE->ResetMusicStatistics();
FOREACH_EnabledPlayer( p )
{
2005-02-16 03:25:45 +00:00
STATSMAN->m_CurStageStats.m_player[p].iSongsPlayed++;
m_textCourseSongNumber[p].SetText( ssprintf("%d", STATSMAN->m_CurStageStats.m_player[p].iSongsPlayed) );
}
2005-02-25 04:18:28 +00:00
LoadCourseSongNumber( GAMESTATE->GetCourseSongIndex() );
2003-12-18 23:19:02 +00:00
2003-03-26 23:08:05 +00:00
int iPlaySongIndex = GAMESTATE->GetCourseSongIndex();
iPlaySongIndex %= m_apSongsQueue.size();
GAMESTATE->m_pCurSong.Set( m_apSongsQueue[iPlaySongIndex] );
2005-02-16 03:25:45 +00:00
STATSMAN->m_CurStageStats.vpSongs.push_back( GAMESTATE->m_pCurSong );
// No need to do this here. We do it in SongFinished().
//GAMESTATE->RemoveAllActiveAttacks();
2003-03-26 23:08:05 +00:00
// Restore the player's originally selected options.
GAMESTATE->RestoreSelectedOptions();
2002-06-14 22:25:22 +00:00
/* If we're in battery mode, force FailImmediate. We assume in PlayerMinus::Step that
* failed players can't step. */
if( GAMESTATE->m_SongOptions.m_LifeType == SongOptions::LIFE_BATTERY )
GAMESTATE->m_SongOptions.m_FailType = SongOptions::FAIL_IMMEDIATE;
m_textSongOptions.SetText( GAMESTATE->m_SongOptions.GetString() );
2002-07-28 20:28:37 +00:00
FOREACH_EnabledPlayer( p )
2002-06-14 22:25:22 +00:00
{
SetupSong( p, iPlaySongIndex );
2002-06-14 22:25:22 +00:00
Song* pSong = GAMESTATE->m_pCurSong;
Steps* pSteps = GAMESTATE->m_pCurSteps[p];
2005-02-16 03:25:45 +00:00
STATSMAN->m_CurStageStats.m_player[p].vpSteps.push_back( pSteps );
2003-03-26 23:08:05 +00:00
ASSERT( GAMESTATE->m_pCurSteps[p] );
m_textStepsDescription[p].SetText( GAMESTATE->m_pCurSteps[p]->GetDescription() );
2004-01-31 09:53:48 +00:00
/* Increment the play count even if the player fails. (It's still popular,
* even if the people playing it aren't good at it.) */
2005-01-03 23:20:11 +00:00
if( !GAMESTATE->m_bDemonstrationOrJukebox )
PROFILEMAN->IncrementStepsPlayCount( pSong, pSteps, p );
2003-03-26 23:08:05 +00:00
m_textPlayerOptions[p].SetText( GAMESTATE->m_pPlayerState[p]->m_PlayerOptions.GetString() );
m_ActiveAttackList[p].Refresh();
// reset oni game over graphic
m_sprOniGameOver[p].SetY( SCREEN_TOP - m_sprOniGameOver[p].GetZoomedHeight()/2 );
m_sprOniGameOver[p].SetDiffuse( RageColor(1,1,1,0) ); // 0 alpha so we don't waste time drawing while not visible
2002-08-01 21:55:40 +00:00
2005-02-16 03:25:45 +00:00
if( GAMESTATE->m_SongOptions.m_LifeType==SongOptions::LIFE_BATTERY && STATSMAN->m_CurStageStats.m_player[p].bFailed ) // already failed
2004-06-08 07:16:28 +00:00
ShowOniGameOver(p);
2002-08-01 21:55:40 +00:00
if( GAMESTATE->m_SongOptions.m_LifeType==SongOptions::LIFE_BAR &&
GAMESTATE->m_PlayMode == PLAY_MODE_REGULAR &&
!GAMESTATE->IsEventMode() &&
!GAMESTATE->m_bDemonstrationOrJukebox )
{
m_pLifeMeter[p]->UpdateNonstopLifebar(
GAMESTATE->GetStageIndex(),
PREFSMAN->m_iNumArcadeStages,
PREFSMAN->m_iProgressiveStageLifebar);
}
if( GAMESTATE->m_SongOptions.m_LifeType==SongOptions::LIFE_BAR && GAMESTATE->m_PlayMode == PLAY_MODE_NONSTOP )
{
m_pLifeMeter[p]->UpdateNonstopLifebar(
GAMESTATE->GetCourseSongIndex(),
GAMESTATE->m_pCurCourse->GetEstimatedNumStages(),
PREFSMAN->m_iProgressiveNonstopLifebar);
}
2002-08-01 21:55:40 +00:00
m_DifficultyIcon[p].SetFromSteps( p, GAMESTATE->m_pCurSteps[p] );
m_DifficultyMeter[p].SetName( m_sName + ssprintf(" DifficultyMeterP%d",p+1) );
m_DifficultyMeter[p].SetFromSteps( GAMESTATE->m_pCurSteps[p] );
2002-06-14 22:25:22 +00:00
/* The actual note data for scoring is the base class of Player. This includes
* transforms, like Wide. Otherwise, the scoring will operate on the wrong data. */
2004-10-23 17:43:49 +00:00
m_pPrimaryScoreKeeper[p]->OnNextSong( GAMESTATE->GetCourseSongIndex(), GAMESTATE->m_pCurSteps[p], &m_Player[p].m_NoteData );
if( m_pSecondaryScoreKeeper[p] )
2004-10-23 17:43:49 +00:00
m_pSecondaryScoreKeeper[p]->OnNextSong( GAMESTATE->GetCourseSongIndex(), GAMESTATE->m_pCurSteps[p], &m_Player[p].m_NoteData );
2003-07-21 19:07:10 +00:00
2005-01-03 23:20:11 +00:00
if( GAMESTATE->m_bDemonstrationOrJukebox )
{
GAMESTATE->m_pPlayerState[p]->m_PlayerController = PC_CPU;
GAMESTATE->m_pPlayerState[p]->m_iCpuSkill = 5;
}
else if( GAMESTATE->IsCpuPlayer(p) )
{
GAMESTATE->m_pPlayerState[p]->m_PlayerController = PC_CPU;
int iMeter = GAMESTATE->m_pCurSteps[p]->GetMeter();
int iNewSkill = SCALE( iMeter, MIN_METER, MAX_METER, 0, NUM_SKILL_LEVELS-1 );
/* Watch out: songs aren't actually bound by MAX_METER. */
iNewSkill = clamp( iNewSkill, 0, NUM_SKILL_LEVELS-1 );
GAMESTATE->m_pPlayerState[p]->m_iCpuSkill = iNewSkill;
2003-04-07 21:24:14 +00:00
}
else if( PREFSMAN->m_bAutoPlay )
{
GAMESTATE->m_pPlayerState[p]->m_PlayerController = PC_AUTOPLAY;
}
else
{
GAMESTATE->m_pPlayerState[p]->m_PlayerController = PC_HUMAN;
}
2002-06-14 22:25:22 +00:00
}
const bool bReverse[NUM_PLAYERS] =
{
GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerOptions.m_fScrolls[PlayerOptions::SCROLL_REVERSE] == 1,
GAMESTATE->m_pPlayerState[PLAYER_2]->m_PlayerOptions.m_fScrolls[PlayerOptions::SCROLL_REVERSE] == 1
};
2004-12-01 20:42:15 +00:00
FOREACH_EnabledPlayer( p )
{
2004-12-01 20:42:15 +00:00
m_DifficultyIcon[p].SetName( ssprintf("DifficultyP%d%s",p+1,bReverse[p]?"Reverse":"") );
SET_XY( m_DifficultyIcon[p] );
2004-12-01 20:42:15 +00:00
m_DifficultyMeter[p].SetName( ssprintf("DifficultyMeterP%d%s",p+1,bReverse[p]?"Reverse":"") );
SET_XY( m_DifficultyMeter[p] );
}
const bool bBothReverse = bReverse[PLAYER_1] && bReverse[PLAYER_2];
const bool bOneReverse = !bBothReverse && (bReverse[PLAYER_1] || bReverse[PLAYER_2]);
2003-04-13 00:44:50 +00:00
2003-03-19 22:48:43 +00:00
/* XXX: We want to put the lyrics out of the way, but it's likely that one
* player is in reverse and the other isn't. What to do? */
m_LyricDisplay.SetName( ssprintf( "Lyrics%s", bBothReverse? "Reverse": bOneReverse? "OneReverse": "") );
2003-04-13 21:17:14 +00:00
SET_XY( m_LyricDisplay );
2003-03-19 22:48:43 +00:00
m_SongFinished.Load( THEME->GetPathB(m_sName,"song finished") );
2003-03-19 19:58:22 +00:00
// Load lyrics
// XXX: don't load this here
LyricsLoader LL;
if( GAMESTATE->m_pCurSong->HasLyrics() )
LL.LoadFromLRCFile(GAMESTATE->m_pCurSong->GetLyricsPath(), *GAMESTATE->m_pCurSong);
2003-04-13 00:44:50 +00:00
/* Set up song-specific graphics. */
// Check to see if any players are in beginner mode.
// Note: steps can be different if turn modifiers are used.
2003-12-02 19:11:51 +00:00
if( PREFSMAN->m_bShowBeginnerHelper )
{
FOREACH_HumanPlayer( p )
{
2004-05-24 06:12:17 +00:00
if( GAMESTATE->m_pCurSteps[p]->GetDifficulty() == DIFFICULTY_BEGINNER )
2004-10-23 17:43:49 +00:00
m_BeginnerHelper.AddPlayer( p, &m_Player[p].m_NoteData );
}
2003-12-02 19:11:51 +00:00
}
m_SongBackground.Unload();
2005-03-11 02:06:39 +00:00
if( !PREFSMAN->m_bShowBeginnerHelper || !m_BeginnerHelper.Initialize(2) )
{
2005-03-11 02:06:39 +00:00
m_BeginnerHelper.SetHidden( true );
/* BeginnerHelper disabled, or failed to load. */
m_SongBackground.LoadFromSong( GAMESTATE->m_pCurSong );
2005-03-11 02:06:39 +00:00
2005-01-03 23:20:11 +00:00
if( !GAMESTATE->m_bDemonstrationOrJukebox )
2004-04-19 20:28:10 +00:00
{
/* This will fade from a preset brightness to the actual brightness (based
* on prefs and "cover"). The preset brightness may be 0 (to fade from
* black), or it might be 1, if the stage screen has the song BG and we're
* coming from it (like Pump). This used to be done in SM_PlayReady, but
* that means it's impossible to snap to the new brightness immediately. */
m_SongBackground.SetBrightness( INITIAL_BACKGROUND_BRIGHTNESS );
m_SongBackground.FadeToActualBrightness();
2004-04-19 20:28:10 +00:00
}
}
2005-03-11 02:06:39 +00:00
else
m_BeginnerHelper.SetHidden( false );
m_SongForeground.LoadFromSong( GAMESTATE->m_pCurSong );
2003-04-13 00:44:50 +00:00
2004-02-16 05:29:33 +00:00
m_fTimeSinceLastDancingComment = 0;
/* m_soundMusic and m_SongBackground take a very long time to load,
* so cap fDelta at 0 so m_NextSong will show up on screen.
* -Chris */
2003-04-13 00:44:50 +00:00
m_bZeroDeltaOnNextUpdate = true;
2004-03-30 07:44:29 +00:00
//
// Load cabinet lights data
2004-03-30 07:44:29 +00:00
//
if( LIGHTSMAN->IsEnabled() )
2004-04-20 02:35:30 +00:00
{
m_CabinetLightsNoteData.Init();
ASSERT( GAMESTATE->m_pCurSong );
Steps *pSteps = GAMESTATE->m_pCurSong->GetClosestNotes( STEPS_TYPE_LIGHTS_CABINET, StringToDifficulty(PREFSMAN->m_sLightsStepsDifficulty) );
if( pSteps != NULL )
{
2004-10-23 17:43:49 +00:00
pSteps->GetNoteData( m_CabinetLightsNoteData );
}
else
{
pSteps = GAMESTATE->m_pCurSong->GetClosestNotes( GAMESTATE->GetCurrentStyle()->m_StepsType, StringToDifficulty(PREFSMAN->m_sLightsStepsDifficulty) );
if( pSteps )
{
NoteData TapNoteData;
2004-10-23 17:43:49 +00:00
pSteps->GetNoteData( TapNoteData );
NoteDataUtil::LoadTransformedLights( TapNoteData, m_CabinetLightsNoteData, GameManager::StepsTypeToNumTracks(STEPS_TYPE_LIGHTS_CABINET) );
}
}
2004-04-20 02:35:30 +00:00
}
2005-03-18 07:08:05 +00:00
/* Load the music last, since it may start streaming and we don't want the music
* to compete with other loading. */
m_AutoKeysounds.FinishLoading();
m_pSoundMusic = m_AutoKeysounds.GetSound();
}
2003-01-25 08:32:57 +00:00
float ScreenGameplay::StartPlayingSong(float MinTimeToNotes, float MinTimeToMusic)
{
2003-01-25 08:32:57 +00:00
ASSERT(MinTimeToNotes >= 0);
ASSERT(MinTimeToMusic >= 0);
/* XXX: We want the first beat *in use*, so we don't delay needlessly. */
const float fFirstBeat = GAMESTATE->m_pCurSong->m_fFirstBeat;
const float fFirstSecond = GAMESTATE->m_pCurSong->GetElapsedTimeFromBeat( fFirstBeat );
2003-01-25 08:32:57 +00:00
float fStartSecond = fFirstSecond - MinTimeToNotes;
2002-12-29 23:31:29 +00:00
2003-01-25 08:32:57 +00:00
fStartSecond = min(fStartSecond, -MinTimeToMusic);
RageSoundParams p;
p.AccurateSync = true;
p.SetPlaybackRate( GAMESTATE->m_SongOptions.m_fMusicRate );
p.StopMode = RageSoundParams::M_CONTINUE;
p.m_StartSecond = fStartSecond;
2005-02-24 21:44:08 +00:00
ASSERT( !m_pSoundMusic->IsPlaying() );
2004-10-25 03:47:22 +00:00
m_pSoundMusic->Play( &p );
2004-01-29 05:20:27 +00:00
/* Make sure GAMESTATE->m_fMusicSeconds is set up. */
GAMESTATE->m_fMusicSeconds = -5000;
UpdateSongPosition(0);
2004-01-29 05:20:27 +00:00
ASSERT( GAMESTATE->m_fMusicSeconds > -4000 ); /* make sure the "fake timer" code doesn't trigger */
/* Return the amount of time until the first beat. */
2003-01-25 08:10:35 +00:00
return fFirstSecond - fStartSecond;
2002-06-14 22:25:22 +00:00
}
void ScreenGameplay::PauseGame( bool bPause )
{
if( m_bPaused == bPause )
{
LOG->Trace( "ScreenGameplay::PauseGame(%i) received, but already in that state; ignored", bPause );
return;
}
2005-03-11 04:12:48 +00:00
/* Don't pause if we're already tweening out. */
if( bPause && m_DancingState == STATE_OUTRO )
return;
2005-04-01 02:34:22 +00:00
AbortGiveUp( false );
2005-03-11 04:12:48 +00:00
m_bPaused = bPause;
m_pSoundMusic->Pause( bPause );
2005-03-11 03:33:41 +00:00
if( bPause )
this->PlayCommand( "Pause" );
else
this->PlayCommand( "Unpause" );
2005-03-11 03:54:40 +00:00
FOREACH_EnabledPlayer(p)
m_Player[p].SetPaused( m_bPaused );
}
2002-10-12 00:32:47 +00:00
// play assist ticks
2004-01-12 09:36:01 +00:00
void ScreenGameplay::PlayTicks()
2002-10-12 00:32:47 +00:00
{
2004-01-12 09:36:01 +00:00
if( !GAMESTATE->m_SongOptions.m_bAssistTick )
return;
/* 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. This is just to make sure that we request the sound early enough for it to
* come out on time; the actual precise timing is handled by SetStartTime. */
2002-10-12 00:32:47 +00:00
float fPositionSeconds = GAMESTATE->m_fMusicSeconds;
2004-01-12 09:36:01 +00:00
fPositionSeconds += SOUND->GetPlayLatency() + (float)TICK_EARLY_SECONDS + 0.250f;
const float fSongBeat = GAMESTATE->m_pCurSong->GetBeatFromElapsedTime( fPositionSeconds );
2002-10-12 00:32:47 +00:00
2004-01-12 09:36:01 +00:00
const int iSongRow = max( 0, BeatToNoteRowNotRounded( fSongBeat ) );
2004-04-04 04:12:26 +00:00
static int iRowLastCrossed = -1;
if( iSongRow < iRowLastCrossed )
iRowLastCrossed = -1;
2002-10-12 00:32:47 +00:00
2004-01-12 09:36:01 +00:00
int iTickRow = -1;
2004-12-03 23:50:20 +00:00
// for each index we crossed since the last update:
2005-01-31 19:12:30 +00:00
FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( m_Player[GAMESTATE->m_MasterPlayerNumber].m_NoteData, r, iRowLastCrossed+1, iSongRow+1 )
2004-10-23 17:43:49 +00:00
if( m_Player[GAMESTATE->m_MasterPlayerNumber].m_NoteData.IsThereATapOrHoldHeadAtRow( r ) )
2004-01-12 09:36:01 +00:00
iTickRow = r;
2002-10-12 00:32:47 +00:00
2004-01-12 09:36:01 +00:00
iRowLastCrossed = iSongRow;
2002-10-12 00:32:47 +00:00
2004-01-12 09:36:01 +00:00
if( iTickRow != -1 )
{
const float fTickBeat = NoteRowToBeat( iTickRow );
const float fTickSecond = GAMESTATE->m_pCurSong->m_Timing.GetElapsedTimeFromBeat( fTickBeat );
float fSecondsUntil = fTickSecond - GAMESTATE->m_fMusicSeconds;
2004-01-20 03:10:55 +00:00
fSecondsUntil /= GAMESTATE->m_SongOptions.m_fMusicRate; /* 2x music rate means the time until the tick is halved */
2004-01-12 09:36:01 +00:00
RageSoundParams p;
2004-04-04 04:11:43 +00:00
p.StartTime = GAMESTATE->m_LastBeatUpdate + (fSecondsUntil - (float)TICK_EARLY_SECONDS);
m_soundAssistTick.Play( &p );
2002-10-12 00:32:47 +00:00
}
}
2002-06-14 22:25:22 +00:00
2004-02-16 05:29:33 +00:00
/* Play announcer "type" if it's been at least fSeconds since the last announcer. */
void ScreenGameplay::PlayAnnouncer( CString type, float fSeconds )
{
if( GAMESTATE->m_fOpponentHealthPercent == 0 )
return; // Shut the announcer up
2004-03-08 04:30:57 +00:00
/* Don't play in demonstration. */
if( GAMESTATE->m_bDemonstrationOrJukebox )
return;
2004-02-16 05:29:33 +00:00
/* Don't play before the first beat, or after we're finished. */
if( m_DancingState != STATE_DANCING )
return;
2004-02-21 17:21:03 +00:00
if( GAMESTATE->m_pCurSong == NULL || // this will be true on ScreenDemonstration sometimes
GAMESTATE->m_fSongBeat < GAMESTATE->m_pCurSong->m_fFirstBeat )
2004-02-16 05:29:33 +00:00
return;
if( m_fTimeSinceLastDancingComment < fSeconds )
return;
m_fTimeSinceLastDancingComment = 0;
2004-04-12 20:11:36 +00:00
SOUND->PlayOnceFromAnnouncer( type );
2004-02-16 05:29:33 +00:00
if( m_pCombinedLifeMeter )
m_pCombinedLifeMeter->OnTaunt();
}
void ScreenGameplay::UpdateSongPosition( float fDeltaTime )
{
2004-10-25 03:47:22 +00:00
if( !m_pSoundMusic->IsPlaying() )
return;
RageTimer tm;
2004-10-25 03:47:22 +00:00
const float fSeconds = m_pSoundMusic->GetPositionSeconds( NULL, &tm );
const float fAdjust = SOUND->GetFrameTimingAdjustment( fDeltaTime );
GAMESTATE->UpdateSongPosition( fSeconds+fAdjust, GAMESTATE->m_pCurSong->m_Timing, tm+fAdjust );
}
2002-05-20 08:59:37 +00:00
void ScreenGameplay::Update( float fDeltaTime )
{
if( GAMESTATE->m_pCurSong == NULL )
{
/* ScreenDemonstration will move us to the next screen. We just need to
* survive for one update without crashing. We need to call Screen::Update
* to make sure we receive the next-screen message. */
Screen::Update( fDeltaTime );
return;
}
if( m_bFirstUpdate )
{
2004-04-12 20:11:36 +00:00
SOUND->PlayOnceFromAnnouncer( "gameplay intro" ); // crowd cheer
//
// Get the transitions rolling
//
2005-01-03 23:20:11 +00:00
if( GAMESTATE->m_bDemonstrationOrJukebox )
{
StartPlayingSong( 0, 0 ); // *kick* (no transitions)
}
else if ( NSMAN->useSMserver )
{
//If we're using networking, we must not have any
//delay. If we do this can cause inconsistancy
//on different computers and differet themes
StartPlayingSong( 0, 0 );
m_pSoundMusic->Stop();
float startOffset = g_fNetStartOffset;
NSMAN->StartRequest(1);
RageSoundParams p;
p.AccurateSync = true;
p.SetPlaybackRate( 1.0 ); //Force 1.0 playback speed
p.StopMode = RageSoundParams::M_CONTINUE;
p.m_StartSecond = startOffset;
m_pSoundMusic->Play( &p );
UpdateSongPosition(0);
}
else
{
float fMinTimeToMusic = m_In.GetLengthSeconds(); // start of m_Ready
float fMinTimeToNotes = fMinTimeToMusic + m_Ready.GetLengthSeconds() + m_Go.GetLengthSeconds()+2; // end of Go
/*
* Tell the music to start, but don't actually make any noise for
* at least 2.5 (or 1.5) seconds. (This is so we scroll on screen smoothly.)
*
* This is only a minimum: the music might be started later, to meet
* the minimum-time-to-notes value. If you're writing song data,
* and you want to make sure we get ideal timing here, make sure there's
* a bit of space at the beginning of the music with no steps.
*/
/*float delay =*/ StartPlayingSong( fMinTimeToNotes, fMinTimeToMusic );
}
}
UpdateSongPosition( fDeltaTime );
2003-04-13 00:44:50 +00:00
if( m_bZeroDeltaOnNextUpdate )
{
Screen::Update( 0 );
m_bZeroDeltaOnNextUpdate = false;
}
else
2004-10-24 10:20:24 +00:00
{
2003-04-13 00:44:50 +00:00
Screen::Update( fDeltaTime );
2004-10-24 10:20:24 +00:00
}
2003-02-10 22:08:10 +00:00
/* This happens if ScreenDemonstration::HandleScreenMessage sets a new screen when
* PREFSMAN->m_bDelayedScreenLoad. */
if( GAMESTATE->m_pCurSong == NULL )
return;
/* This can happen if ScreenDemonstration::HandleScreenMessage sets a new screen when
* !PREFSMAN->m_bDelayedScreenLoad. (The new screen was loaded when we called Screen::Update,
* and the ctor might set a new GAMESTATE->m_pCurSong, so the above check can fail.) */
if( SCREENMAN->GetTopScreen() != this )
return;
2003-02-10 22:08:10 +00:00
2005-03-11 03:54:40 +00:00
/* Update actors when paused, but never move on to another state. */
if( m_bPaused )
return;
2005-02-28 08:43:49 +00:00
if( GAMESTATE->m_MasterPlayerNumber != PLAYER_INVALID && !m_MaxCombo.GetHidden() )
2005-02-16 03:25:45 +00:00
m_MaxCombo.SetText( ssprintf("%d", STATSMAN->m_CurStageStats.m_player[GAMESTATE->m_MasterPlayerNumber].iMaxCombo) ); /* MAKE THIS WORK FOR BOTH PLAYERS! */
2003-02-10 22:08:10 +00:00
//LOG->Trace( "m_fOffsetInBeats = %f, m_fBeatsPerSecond = %f, m_Music.GetPositionSeconds = %f", m_fOffsetInBeats, m_fBeatsPerSecond, m_Music.GetPositionSeconds() );
2002-05-20 08:59:37 +00:00
2004-10-24 10:45:30 +00:00
m_AutoKeysounds.Update(fDeltaTime);
2004-06-08 07:16:28 +00:00
//
// update GameState HealthState
//
2004-05-16 12:34:02 +00:00
FOREACH_EnabledPlayer(p)
{
if(
(m_pLifeMeter[p] && m_pLifeMeter[p]->IsFailing()) ||
(m_pCombinedLifeMeter && m_pCombinedLifeMeter->IsFailing(p)) )
{
GAMESTATE->m_pPlayerState[p]->m_HealthState = PlayerState::DEAD;
2004-05-16 12:34:02 +00:00
}
2004-06-08 07:16:28 +00:00
else if(
(m_pLifeMeter[p] && m_pLifeMeter[p]->IsHot()) ||
(m_pCombinedLifeMeter && m_pCombinedLifeMeter->IsHot(p)) )
2004-05-16 12:34:02 +00:00
{
GAMESTATE->m_pPlayerState[p]->m_HealthState = PlayerState::HOT;
2004-05-16 12:34:02 +00:00
}
else if(
(m_pLifeMeter[p] && m_pLifeMeter[p]->IsInDanger()) ||
2004-06-08 07:16:28 +00:00
(m_pCombinedLifeMeter && m_pCombinedLifeMeter->IsInDanger(p)) )
2004-05-16 12:34:02 +00:00
{
GAMESTATE->m_pPlayerState[p]->m_HealthState = PlayerState::DANGER;
2004-05-16 12:34:02 +00:00
}
else
{
GAMESTATE->m_pPlayerState[p]->m_HealthState = PlayerState::ALIVE;
}
}
2004-06-08 07:16:28 +00:00
2002-05-20 08:59:37 +00:00
switch( m_DancingState )
{
case STATE_DANCING:
2005-02-16 03:25:45 +00:00
/* Set STATSMAN->m_CurStageStats.bFailed for failed players. In, FAIL_IMMEDIATE, send
* SM_BeginFailed if all players failed, and kill dead Oni players. */
FOREACH_EnabledPlayer( pn )
{
SongOptions::FailType ft = GAMESTATE->GetPlayerFailType(pn);
if( ft == SongOptions::FAIL_OFF )
continue;
// check for individual fail
if( (m_pLifeMeter[pn] && !m_pLifeMeter[pn]->IsFailing()) ||
(m_pCombinedLifeMeter && !m_pCombinedLifeMeter->IsFailing(pn)) )
continue; /* isn't failing */
if( STATSMAN->m_CurStageStats.m_player[pn].bFailed )
continue; /* failed and is already dead */
/* If recovery is enabled, only set fail if both are failing.
* There's no way to recover mid-song in battery mode. */
if( GAMESTATE->m_SongOptions.m_LifeType != SongOptions::LIFE_BATTERY &&
PREFSMAN->m_bTwoPlayerRecovery && !GAMESTATE->AllAreDead() )
continue;
LOG->Trace("Player %d failed", (int)pn);
STATSMAN->m_CurStageStats.m_player[pn].bFailed = true; // fail
if( ft == SongOptions::LIFE_BATTERY &&
ft == SongOptions::FAIL_IMMEDIATE )
{
if( !STATSMAN->m_CurStageStats.AllFailedEarlier() ) // if not the last one to fail
{
// kill them!
SOUND->PlayOnceFromDir( THEME->GetPathS(m_sName,"oni die") );
ShowOniGameOver(pn);
m_Player[pn].m_NoteData.Init(); // remove all notes and scoring
m_Player[pn].FadeToFail(); // tell the NoteField to fade to white
}
}
}
bool bAllFailed = true;
FOREACH_EnabledPlayer( pn )
2004-07-31 19:14:53 +00:00
{
SongOptions::FailType ft = GAMESTATE->GetPlayerFailType(pn);
switch( ft )
{
case SongOptions::FAIL_IMMEDIATE:
if( GAMESTATE->m_pPlayerState[pn]->m_HealthState < PlayerState::DEAD )
bAllFailed = false;
break;
case SongOptions::FAIL_COMBO_OF_30_MISSES:
if( STATSMAN->m_CurStageStats.m_player[pn].iCurMissCombo < 30 )
bAllFailed = false;
break;
case SongOptions::FAIL_END_OF_SONG:
bAllFailed = false; // wait until the end of the song to fail.
break;
case SongOptions::FAIL_OFF:
bAllFailed = false; // never fail.
break;
default:
ASSERT(0);
}
2004-07-31 19:14:53 +00:00
}
if( bAllFailed )
SCREENMAN->PostMessageToTopScreen( SM_BeginFailed, 0 );
//
2003-03-30 20:54:37 +00:00
// Update living players' alive time
//
2004-05-16 12:42:16 +00:00
FOREACH_EnabledPlayer(pn)
2005-02-16 03:25:45 +00:00
if(!STATSMAN->m_CurStageStats.m_player[pn].bFailed)
STATSMAN->m_CurStageStats.m_player[pn].fAliveSeconds += fDeltaTime * GAMESTATE->m_SongOptions.m_fMusicRate;
2003-12-09 10:20:18 +00:00
// update fGameplaySeconds
2005-02-16 03:25:45 +00:00
STATSMAN->m_CurStageStats.fGameplaySeconds += fDeltaTime;
2003-12-09 10:20:18 +00:00
2002-07-27 19:29:51 +00:00
//
2002-05-20 08:59:37 +00:00
// Check for end of song
2002-07-27 19:29:51 +00:00
//
2004-03-03 08:03:47 +00:00
float fSecondsToStop = GAMESTATE->m_pCurSong->GetElapsedTimeFromBeat( GAMESTATE->m_pCurSong->m_fLastBeat );
/* Make sure we keep going long enough to register a miss for the last note. */
2005-01-15 01:03:48 +00:00
fSecondsToStop += Player::GetMaxStepDistanceSeconds();
if( GAMESTATE->m_fMusicSeconds > fSecondsToStop && !m_SongFinished.IsTransitioning() && !m_NextSong.IsTransitioning() )
m_SongFinished.StartTransitioning( SM_NotesEnded );
//
// update 2d dancing characters
//
2004-05-16 12:34:02 +00:00
FOREACH_EnabledPlayer(p)
{
DancingCharacters *pCharacter = m_SongBackground.GetDancingCharacters();
if( pCharacter != NULL )
{
TapNoteScore tns = m_Player[p].GetLastTapNoteScore();
ANIM_STATES_2D StateMap[NUM_TAP_NOTE_SCORES] =
{
AS2D_MISS, /* TNS_NONE (shouldn't happen) */
AS2D_MISS, /* TNS_HIT_MINE (shouldn't happen) */
AS2D_MISS, /* TNS_MISS */
AS2D_MISS, /* TNS_BOO */
AS2D_GOOD, /* TNS_GOOD */
AS2D_GOOD, /* TNS_GREAT */
AS2D_GREAT, /* TNS_PERFECT */
AS2D_GREAT /* TNS_MARVELOUS */
};
ANIM_STATES_2D state = StateMap[tns];
if( state == AS2D_GREAT && m_pLifeMeter[p] && m_pLifeMeter[p]->GetLife() == 1.0f ) // full life
state = AS2D_FEVER;
pCharacter->Change2DAnimState( p, state );
}
}
//
// Check for enemy death in enemy battle
//
static float fLastSeenEnemyHealth = 1;
if( fLastSeenEnemyHealth != GAMESTATE->m_fOpponentHealthPercent )
{
fLastSeenEnemyHealth = GAMESTATE->m_fOpponentHealthPercent;
if( GAMESTATE->m_fOpponentHealthPercent == 0 )
{
2004-02-16 05:29:33 +00:00
// HACK: Load incorrect directory on purpose for now.
PlayAnnouncer( "gameplay battle damage level3", 0 );
2003-07-09 02:27:05 +00:00
GAMESTATE->RemoveAllActiveAttacks();
2004-05-16 12:34:02 +00:00
FOREACH_CpuPlayer(p)
{
SOUND->PlayOnceFromDir( THEME->GetPathS(m_sName,"oni die") );
ShowOniGameOver( p );
2004-10-23 17:43:49 +00:00
m_Player[p].m_NoteData.Init(); // remove all notes and scoring
2004-05-16 12:34:02 +00:00
m_Player[p].FadeToFail(); // tell the NoteField to fade to white
}
}
}
2002-07-27 19:29:51 +00:00
//
2003-03-09 00:55:49 +00:00
// Check to see if it's time to play a ScreenGameplay comment
2002-07-27 19:29:51 +00:00
//
2004-02-16 05:29:33 +00:00
m_fTimeSinceLastDancingComment += fDeltaTime;
switch( GAMESTATE->m_PlayMode )
2002-05-20 08:59:37 +00:00
{
case PLAY_MODE_REGULAR:
2004-02-16 05:29:33 +00:00
case PLAY_MODE_BATTLE:
case PLAY_MODE_RAVE:
if( GAMESTATE->OneIsHot() )
PlayAnnouncer( "gameplay comment hot", SECONDS_BETWEEN_COMMENTS );
else if( GAMESTATE->AllAreInDangerOrWorse() )
PlayAnnouncer( "gameplay comment danger", SECONDS_BETWEEN_COMMENTS );
else
PlayAnnouncer( "gameplay comment good", SECONDS_BETWEEN_COMMENTS );
break;
case PLAY_MODE_NONSTOP:
case PLAY_MODE_ONI:
case PLAY_MODE_ENDLESS:
PlayAnnouncer( "gameplay comment oni", SECONDS_BETWEEN_COMMENTS );
break;
default:
ASSERT(0);
2002-05-20 08:59:37 +00:00
}
}
2003-12-25 05:53:30 +00:00
//
// update give up timer
//
2005-03-29 04:51:59 +00:00
if( !m_GiveUpTimer.IsZero() && m_GiveUpTimer.Ago() > 2.5f )
{
m_GiveUpTimer.SetZero();
if( GIVING_UP_FAILS )
{
/* Unless we're in FailOff, giving up means failing the song. */
switch( GAMESTATE->m_SongOptions.m_FailType )
{
case SongOptions::FAIL_IMMEDIATE:
case SongOptions::FAIL_COMBO_OF_30_MISSES:
case SongOptions::FAIL_END_OF_SONG:
FOREACH_EnabledPlayer(pn)
STATSMAN->m_CurStageStats.m_player[pn].bFailed = true; // fail
}
this->PostScreenMessage( SM_NotesEnded, 0 );
2005-03-11 04:53:45 +00:00
}
else
{
BackOutFromGameplay();
return;
}
}
2004-12-18 08:15:19 +00:00
//
// update bpm display
//
2005-02-28 08:43:49 +00:00
if( m_fLastBPS != GAMESTATE->m_fCurBPS && !m_BPMDisplay.GetHidden() )
2004-12-18 08:15:19 +00:00
{
m_fLastBPS = GAMESTATE->m_fCurBPS;
m_BPMDisplay.SetConstantBpm( GAMESTATE->m_fCurBPS * 60.0f );
2004-12-18 08:15:19 +00:00
}
2003-12-25 05:53:30 +00:00
//
2004-01-12 09:36:01 +00:00
// play assist ticks
2003-12-25 05:53:30 +00:00
//
2004-01-12 09:36:01 +00:00
PlayTicks();
2003-11-20 11:55:45 +00:00
2003-12-25 05:53:30 +00:00
//
// update lights
//
UpdateLights();
if( NSMAN->useSMserver )
{
FOREACH_EnabledPlayer( pn2 )
if( m_pLifeMeter[pn2] )
NSMAN->m_playerLife[pn2] = int(m_pLifeMeter[pn2]->GetLife()*10000);
FOREACH_NSScoreBoardColumn(cn)
if( m_ShowScoreboard && NSMAN->ChangedScoreboard(cn) )
m_Scoreboard[cn].SetText( NSMAN->m_Scoreboard[cn] );
}
}
void ScreenGameplay::UpdateLights()
{
if( !LIGHTSMAN->IsEnabled() )
return;
2004-06-28 07:26:00 +00:00
const Style* pStyle = GAMESTATE->GetCurrentStyle();
bool bBlinkCabinetLight[NUM_CABINET_LIGHTS];
bool bBlinkGameButton[MAX_GAME_CONTROLLERS][MAX_GAME_BUTTONS];
ZERO( bBlinkCabinetLight );
ZERO( bBlinkGameButton );
2004-03-30 07:44:29 +00:00
bool bCrossedABeat = false;
2004-01-12 09:36:01 +00:00
{
float fPositionSeconds = GAMESTATE->m_fMusicSeconds + LIGHTS_FALLOFF_SECONDS/2; // trigger the light a tiny bit early
2004-01-12 09:36:01 +00:00
float fSongBeat = GAMESTATE->m_pCurSong->GetBeatFromElapsedTime( fPositionSeconds );
int iRowNow = BeatToNoteRowNotRounded( fSongBeat );
iRowNow = max( 0, iRowNow );
static int iRowLastCrossed = 0;
2004-03-30 07:44:29 +00:00
float fBeatLast = roundf(NoteRowToBeat(iRowLastCrossed));
float fBeatNow = roundf(NoteRowToBeat(iRowNow));
bCrossedABeat = fBeatLast != fBeatNow;
2004-01-12 09:36:01 +00:00
2004-12-03 23:39:50 +00:00
FOREACH_CabinetLight( cl )
{
// for each index we crossed since the last update:
FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( m_CabinetLightsNoteData, cl, r, iRowLastCrossed, iRowNow )
2004-12-03 23:39:50 +00:00
{
bool bBlink = (m_CabinetLightsNoteData.GetTapNote( cl, r ).type != TapNote::empty );
2004-07-18 01:39:32 +00:00
bBlinkCabinetLight[cl] |= bBlink;
}
2005-01-23 06:31:41 +00:00
if( m_CabinetLightsNoteData.IsHoldNoteAtBeat( cl, iRowNow ) )
bBlinkCabinetLight[cl] |= true;
}
2004-12-03 23:43:35 +00:00
FOREACH_EnabledPlayer( pn )
{
2004-12-03 23:43:35 +00:00
for( int t=0; t<m_Player[pn].m_NoteData.GetNumTracks(); t++ )
{
2004-12-03 23:43:35 +00:00
// for each index we crossed since the last update:
FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( m_Player[pn].m_NoteData, t, r, iRowLastCrossed+1, iRowNow )
{
2004-10-23 17:43:49 +00:00
TapNote tn = m_Player[pn].m_NoteData.GetTapNote(t,r);
bool bBlink = (tn.type != TapNote::empty && tn.type != TapNote::mine);
if( bBlink )
{
StyleInput si( pn, t );
2004-06-28 07:26:00 +00:00
GameInput gi = pStyle->StyleInputToGameInput( si );
bBlinkGameButton[gi.controller][gi.button] |= bBlink;
}
}
}
2004-01-12 09:36:01 +00:00
}
iRowLastCrossed = iRowNow;
}
{
// check for active HoldNotes
float fPositionSeconds = GAMESTATE->m_fMusicSeconds + LIGHTS_FALLOFF_SECONDS/2; // trigger the light a tiny bit early
float fSongBeat = GAMESTATE->m_pCurSong->GetBeatFromElapsedTime( fPositionSeconds );
const int iSongRow = BeatToNoteRow( fSongBeat );
FOREACH_EnabledPlayer( pn )
{
// check if a hold should be active
2005-01-25 05:02:35 +00:00
for( int t=0; t < m_Player[pn].m_NoteData.GetNumTracks(); ++t )
{
2005-01-25 05:02:35 +00:00
if( m_Player[pn].m_NoteData.IsHoldNoteAtBeat( t, iSongRow ) )
{
2005-01-25 05:02:35 +00:00
StyleInput si( pn, t );
2004-06-28 07:26:00 +00:00
GameInput gi = pStyle->StyleInputToGameInput( si );
bBlinkGameButton[gi.controller][gi.button] |= true;
}
}
}
}
2004-10-15 14:37:33 +00:00
// Before the first beat of the song, blink all cabinet lights (except for
// menu buttons) on the beat.
bool bOverrideCabinetBlink = (GAMESTATE->m_fSongBeat < GAMESTATE->m_pCurSong->m_fFirstBeat) && bCrossedABeat;
2004-10-15 14:37:33 +00:00
FOREACH_CabinetLight( cl )
{
switch( cl )
{
case LIGHT_BUTTONS_LEFT:
case LIGHT_BUTTONS_RIGHT:
// don't blink
break;
default:
bBlinkCabinetLight[cl] |= bOverrideCabinetBlink;
break;
}
}
2004-03-30 07:44:29 +00:00
2004-10-15 14:37:33 +00:00
// Send blink data.
2004-04-20 02:35:30 +00:00
FOREACH_CabinetLight( cl )
{
2004-10-15 14:37:33 +00:00
if( bBlinkCabinetLight[cl] )
LIGHTSMAN->BlinkCabinetLight( cl );
}
FOREACH_GameController( gc )
{
FOREACH_GameButton( gb )
{
if( bBlinkGameButton[gc][gb] )
LIGHTSMAN->BlinkGameButton( GameInput(gc,gb) );
}
2004-04-20 02:35:30 +00:00
}
2002-05-20 08:59:37 +00:00
}
void ScreenGameplay::BackOutFromGameplay()
{
m_DancingState = STATE_OUTRO;
AbortGiveUp( false );
m_pSoundMusic->StopPlaying();
m_soundAssistTick.StopPlaying(); /* Stop any queued assist ticks. */
this->ClearMessageQueue();
m_Cancel.StartTransitioning( SM_SaveChangedBeforeGoingBack );
}
void ScreenGameplay::AbortGiveUp( bool bShowText )
{
if( m_GiveUpTimer.IsZero() )
return;
m_textDebug.StopTweening();
if( bShowText )
m_textDebug.SetText( GIVE_UP_ABORTED_TEXT );
// otherwise tween out the text that's there
m_textDebug.BeginTweening( 1/2.f );
m_textDebug.SetDiffuse( RageColor(1,1,1,0) );
m_GiveUpTimer.SetZero();
}
2002-05-20 08:59:37 +00:00
void ScreenGameplay::Input( const DeviceInput& DeviceI, const InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI )
{
//LOG->Trace( "ScreenGameplay::Input()" );
2003-01-19 21:57:13 +00:00
2004-09-09 22:21:50 +00:00
if( type == IET_LEVEL_CHANGED )
return;
2005-03-11 03:54:40 +00:00
if( m_bPaused )
{
/* If we're paused, only accept MENU_BUTTON_START to unpause. */
if( MenuI.IsValid() && MenuI.button == MENU_BUTTON_START && type == IET_FIRST_PRESS )
this->PauseGame( false );
return;
}
2003-01-19 21:57:13 +00:00
if( MenuI.IsValid() &&
m_DancingState != STATE_OUTRO &&
GAMESTATE->IsHumanPlayer(MenuI.player) &&
!m_Cancel.IsTransitioning() )
2003-01-19 21:57:13 +00:00
{
/* Allow bailing out by holding the START button of all active players. This
* gives a way to "give up" when a back button isn't available. Doing this is
* treated as failing the song, unlike BACK, since it's always available.
*
* However, if this is also a style button, don't do this. (pump center = start) */
bool bHoldingGiveUp = false;
bHoldingGiveUp |= ( START_GIVES_UP && MenuI.button == MENU_BUTTON_START && !StyleI.IsValid() );
bHoldingGiveUp |= ( BACK_GIVES_UP && MenuI.button == MENU_BUTTON_BACK && !StyleI.IsValid() );
if( bHoldingGiveUp )
{
/* No PREFSMAN->m_bDelayedEscape; always delayed. */
if( type==IET_RELEASE )
AbortGiveUp( true );
else if( type==IET_FIRST_PRESS && m_GiveUpTimer.IsZero() )
{
2005-03-12 00:04:27 +00:00
m_textDebug.SetText( GIVE_UP_TEXT );
m_textDebug.StopTweening();
m_textDebug.SetDiffuse( RageColor(1,1,1,0) );
m_textDebug.BeginTweening( 1/8.f );
m_textDebug.SetDiffuse( RageColor(1,1,1,1) );
m_GiveUpTimer.Touch(); /* start the timer */
}
return;
}
/* Only handle MENU_BUTTON_BACK as a regular BACK button if BACK_GIVES_UP is
* disabled. */
if( MenuI.button == MENU_BUTTON_BACK && !BACK_GIVES_UP )
2003-01-19 21:57:13 +00:00
{
if( ((!PREFSMAN->m_bDelayedBack && type==IET_FIRST_PRESS) ||
(DeviceI.device==DEVICE_KEYBOARD && (type==IET_SLOW_REPEAT||type==IET_FAST_REPEAT)) ||
(DeviceI.device!=DEVICE_KEYBOARD && type==IET_FAST_REPEAT)) )
{
LOG->Trace("Player %i went back", MenuI.player+1);
BackOutFromGameplay();
}
else if( PREFSMAN->m_bDelayedBack && type==IET_FIRST_PRESS )
{
m_textDebug.SetText( "Continue holding BACK to quit" );
m_textDebug.StopTweening();
m_textDebug.SetDiffuse( RageColor(1,1,1,0) );
m_textDebug.BeginTweening( 1/8.f );
m_textDebug.SetDiffuse( RageColor(1,1,1,1) );
}
else if( PREFSMAN->m_bDelayedBack && type==IET_RELEASE )
{
m_textDebug.StopTweening();
m_textDebug.BeginTweening( 1/8.f );
m_textDebug.SetDiffuse( RageColor(1,1,1,0) );
}
2004-02-15 02:06:39 +00:00
return;
}
2003-01-19 21:57:13 +00:00
}
/* Nothing below cares about releases. */
2003-01-19 21:57:13 +00:00
if(type == IET_RELEASE) return;
2002-05-20 08:59:37 +00:00
2002-06-24 22:04:31 +00:00
// Handle special keys to adjust the offset
2002-07-03 21:27:26 +00:00
if( DeviceI.device == DEVICE_KEYBOARD )
2002-06-24 22:04:31 +00:00
{
switch( DeviceI.button )
{
2004-09-09 17:48:26 +00:00
case KEY_F5:
2004-03-07 04:34:49 +00:00
this->HandleScreenMessage( SM_NotesEnded );
break;
2004-09-09 17:48:26 +00:00
case KEY_F6:
2002-10-01 01:55:39 +00:00
m_bChangedOffsetOrBPM = true;
GAMESTATE->m_SongOptions.m_bAutoSync = !GAMESTATE->m_SongOptions.m_bAutoSync; // toggle
UpdateAutoPlayText();
2002-10-01 01:55:39 +00:00
break;
2004-09-09 17:48:26 +00:00
case KEY_F7:
GAMESTATE->m_SongOptions.m_bAssistTick ^= 1;
/* Store this change, so it sticks if we change songs: */
GAMESTATE->m_StoredSongOptions.m_bAssistTick = GAMESTATE->m_SongOptions.m_bAssistTick;
m_textDebug.SetText( ssprintf("Assist Tick is %s", GAMESTATE->m_SongOptions.m_bAssistTick?"ON":"OFF") );
m_textDebug.StopTweening();
2003-11-03 02:10:03 +00:00
m_textDebug.SetDiffuse( RageColor(1,1,1,1) );
m_textDebug.BeginTweening( 3 ); // sleep
m_textDebug.BeginTweening( 0.5f ); // fade out
2003-04-12 06:16:12 +00:00
m_textDebug.SetDiffuse( RageColor(1,1,1,0) );
break;
2004-09-09 17:48:26 +00:00
case KEY_F8:
2003-04-07 21:24:14 +00:00
{
PREFSMAN->m_bAutoPlay = !PREFSMAN->m_bAutoPlay;
UpdateAutoPlayText();
2004-02-01 03:14:37 +00:00
bool bIsHoldingShift =
2004-09-09 17:48:26 +00:00
INPUTFILTER->IsBeingPressed( DeviceInput(DEVICE_KEYBOARD, KEY_RSHIFT)) ||
INPUTFILTER->IsBeingPressed( DeviceInput(DEVICE_KEYBOARD, KEY_LSHIFT));
2004-05-16 12:34:02 +00:00
FOREACH_HumanPlayer(p)
2004-02-01 03:14:37 +00:00
{
2004-05-16 12:34:02 +00:00
if( bIsHoldingShift )
GAMESTATE->m_pPlayerState[p]->m_PlayerController = PREFSMAN->m_bAutoPlay ? PC_CPU : PC_HUMAN;
2004-05-16 12:34:02 +00:00
else
GAMESTATE->m_pPlayerState[p]->m_PlayerController = PREFSMAN->m_bAutoPlay ? PC_AUTOPLAY : PC_HUMAN;
2004-02-01 03:14:37 +00:00
}
2003-04-07 21:24:14 +00:00
}
2002-07-27 19:29:51 +00:00
break;
2004-09-09 17:48:26 +00:00
case KEY_F9:
case KEY_F10:
2002-07-27 19:29:51 +00:00
{
m_bChangedOffsetOrBPM = true;
float fOffsetDelta;
switch( DeviceI.button )
{
2004-09-09 17:48:26 +00:00
case KEY_F9: fOffsetDelta = -0.020f; break;
case KEY_F10: fOffsetDelta = +0.020f; break;
2002-09-07 10:43:16 +00:00
default: ASSERT(0); return;
2002-07-27 19:29:51 +00:00
}
2004-09-09 17:48:26 +00:00
if( INPUTFILTER->IsBeingPressed( DeviceInput(DEVICE_KEYBOARD, KEY_RALT)) ||
INPUTFILTER->IsBeingPressed( DeviceInput(DEVICE_KEYBOARD, KEY_LALT)) )
2003-06-17 06:24:13 +00:00
fOffsetDelta /= 2; /* .010 */
else if( type == IET_FAST_REPEAT )
fOffsetDelta *= 10;
2002-08-02 09:31:06 +00:00
BPMSegment& seg = GAMESTATE->m_pCurSong->GetBPMSegmentAtBeat( GAMESTATE->m_fSongBeat );
2002-07-27 19:29:51 +00:00
seg.m_fBPS += fOffsetDelta;
2002-07-27 19:29:51 +00:00
m_textDebug.SetText( ssprintf("Cur BPM = %.2f", seg.GetBPM()) );
2002-07-27 19:29:51 +00:00
m_textDebug.StopTweening();
2003-11-03 02:10:03 +00:00
m_textDebug.SetDiffuse( RageColor(1,1,1,1) );
m_textDebug.BeginTweening( 3 ); // sleep
m_textDebug.BeginTweening( 0.5f ); // fade out
2003-04-12 06:16:12 +00:00
m_textDebug.SetDiffuse( RageColor(1,1,1,0) );
2002-07-27 19:29:51 +00:00
}
break;
2004-09-09 17:48:26 +00:00
case KEY_F11:
case KEY_F12:
2002-07-03 21:27:26 +00:00
{
2002-07-27 19:29:51 +00:00
m_bChangedOffsetOrBPM = true;
2002-07-03 21:27:26 +00:00
float fOffsetDelta;
switch( DeviceI.button )
{
2004-09-09 17:48:26 +00:00
case KEY_F11: fOffsetDelta = -0.02f; break;
case KEY_F12: fOffsetDelta = +0.02f; break;
2002-09-07 10:43:16 +00:00
default: ASSERT(0); return;
2002-07-03 21:27:26 +00:00
}
2004-09-09 17:48:26 +00:00
if( INPUTFILTER->IsBeingPressed( DeviceInput(DEVICE_KEYBOARD, KEY_RALT)) ||
INPUTFILTER->IsBeingPressed( DeviceInput(DEVICE_KEYBOARD, KEY_LALT)) )
2003-06-10 22:14:09 +00:00
fOffsetDelta /= 20; /* 1ms */
else switch( type )
{
case IET_SLOW_REPEAT: fOffsetDelta *= 10; break;
case IET_FAST_REPEAT: fOffsetDelta *= 40; break;
}
2002-07-03 21:27:26 +00:00
2003-12-18 04:48:26 +00:00
GAMESTATE->m_pCurSong->m_Timing.m_fBeat0OffsetInSeconds += fOffsetDelta;
2002-07-03 21:27:26 +00:00
2003-12-18 04:48:26 +00:00
m_textDebug.SetText( ssprintf("Offset = %.3f", GAMESTATE->m_pCurSong->m_Timing.m_fBeat0OffsetInSeconds) );
2002-07-03 21:27:26 +00:00
m_textDebug.StopTweening();
2003-11-03 02:10:03 +00:00
m_textDebug.SetDiffuse( RageColor(1,1,1,1) );
m_textDebug.BeginTweening( 3 ); // sleep
m_textDebug.BeginTweening( 0.5f ); // fade out
2003-04-12 06:16:12 +00:00
m_textDebug.SetDiffuse( RageColor(1,1,1,0) );
2002-07-03 21:27:26 +00:00
}
2002-06-24 22:04:31 +00:00
break;
}
}
2002-07-27 19:29:51 +00:00
//
2003-02-25 00:33:42 +00:00
// handle a step or battle item activate
2002-07-27 19:29:51 +00:00
//
2003-01-25 11:05:12 +00:00
if( type==IET_FIRST_PRESS &&
StyleI.IsValid() &&
GAMESTATE->IsHumanPlayer( StyleI.player ) )
{
AbortGiveUp( true );
if( !PREFSMAN->m_bAutoPlay )
m_Player[StyleI.player].Step( StyleI.col, DeviceI.ts );
}
2003-11-20 06:50:05 +00:00
// else if( type==IET_FIRST_PRESS &&
// !PREFSMAN->m_bAutoPlay &&
// MenuI.IsValifd() &&
// GAMESTATE->IsPlayerEnabled( MenuI.player ) &&
// GAMESTATE->IsBattleMode() )
// {
// int iItemSlot;
// switch( MenuI.button )
// {
// case MENU_BUTTON_LEFT: iItemSlot = 0; break;
// case MENU_BUTTON_START: iItemSlot = 1; break;
// case MENU_BUTTON_RIGHT: iItemSlot = 2; break;
// default: iItemSlot = -1; break;
// }
//
// if( iItemSlot != -1 )
// m_pInventory[MenuI.player]->UseItem( iItemSlot );
// }
2002-05-20 08:59:37 +00:00
}
void ScreenGameplay::UpdateAutoPlayText()
{
2003-03-09 00:55:49 +00:00
CString sText;
2003-03-09 00:55:49 +00:00
if( PREFSMAN->m_bAutoPlay )
sText += "AutoPlay ";
if( GAMESTATE->m_SongOptions.m_bAutoSync )
sText += "AutoSync ";
2003-03-09 00:55:49 +00:00
if( sText.length() > 0 )
sText.resize( sText.length()-5 );
m_textAutoPlay.SetText( sText );
}
void SaveChanges( void* papSongsQueue )
2002-07-27 19:29:51 +00:00
{
vector<Song*>& apSongsQueue = *(vector<Song*>*)papSongsQueue;
2003-09-01 01:47:47 +00:00
for( unsigned i=0; i<apSongsQueue.size(); i++ )
apSongsQueue[i]->Save();
2002-07-27 19:29:51 +00:00
}
void RevertChanges( void* papSongsQueue )
2002-07-27 19:29:51 +00:00
{
vector<Song*>& apSongsQueue = *(vector<Song*>*)papSongsQueue;
2004-07-24 06:40:51 +00:00
FOREACH( Song*, apSongsQueue, pSong )
{
2004-08-11 08:23:14 +00:00
SONGMAN->RevertFromDisk( *pSong );
2004-07-24 06:40:51 +00:00
}
2002-07-27 19:29:51 +00:00
}
void ScreenGameplay::ShowSavePrompt( ScreenMessage SM_SendWhenDone )
2002-07-27 19:29:51 +00:00
{
2002-07-28 20:28:37 +00:00
CString sMessage;
switch( GAMESTATE->m_PlayMode )
{
case PLAY_MODE_REGULAR:
2003-08-19 04:27:50 +00:00
case PLAY_MODE_BATTLE:
2003-04-07 05:14:27 +00:00
case PLAY_MODE_RAVE:
2002-07-28 20:28:37 +00:00
sMessage = ssprintf(
"You have changed the offset or BPM of\n"
"%s\n",
GAMESTATE->m_pCurSong->GetFullDisplayTitle().c_str() );
2003-12-18 04:48:26 +00:00
if( fabs(GAMESTATE->m_pCurSong->m_Timing.m_fBeat0OffsetInSeconds - g_fOldOffset) > 0.001 )
{
sMessage += ssprintf(
"\n"
"Offset was changed from %.3f to %.3f (%.3f).\n",
g_fOldOffset,
2003-12-18 04:48:26 +00:00
GAMESTATE->m_pCurSong->m_Timing.m_fBeat0OffsetInSeconds,
GAMESTATE->m_pCurSong->m_Timing.m_fBeat0OffsetInSeconds - g_fOldOffset );
}
sMessage +=
"\n"
2002-07-28 20:28:37 +00:00
"Would you like to save these changes back\n"
"to the song file?\n"
"Choosing NO will discard your changes.";
2002-07-28 20:28:37 +00:00
break;
case PLAY_MODE_NONSTOP:
2002-07-28 20:28:37 +00:00
case PLAY_MODE_ONI:
case PLAY_MODE_ENDLESS:
sMessage = ssprintf(
"You have changed the offset or BPM of\n"
"one or more songs in this course.\n"
"Would you like to save these changes back\n"
"to the song file(s)?\n"
2002-08-20 06:26:34 +00:00
"Choosing NO will discard your changes." );
2002-07-28 20:28:37 +00:00
break;
default:
ASSERT(0);
}
SCREENMAN->Prompt( SM_SendWhenDone, sMessage, PROMPT_YES_NO, ANSWER_NO, SaveChanges, RevertChanges, &m_apSongsQueue );
2002-07-27 19:29:51 +00:00
}
2003-12-23 02:18:27 +00:00
/*
* Saving StageStats that are affected by the note pattern is a little tricky:
*
* Stats are cumulative for course play.
*
* For regular songs, it doesn't matter how we do it; the pattern doesn't change
* during play.
*
* The pattern changes during play in battle and course mode. We want to include these
* changes, so run stats for a song after the song finishes.
*
* If we fail, be sure to include the current song in stats, with the current modifier set.
*
* So:
*
* 1. At the end of a song in any mode, pass or fail, add stats for that song (from m_Player).
* 2. At the end of gameplay in course mode, add stats for any songs that weren't played,
* applying the modifiers the song would have been played with. This doesn't include songs
* that were played but failed; that was done in #1.
*/
void ScreenGameplay::SongFinished()
{
// save any statistics
2004-05-16 12:34:02 +00:00
FOREACH_EnabledPlayer(p)
{
2004-07-11 07:21:33 +00:00
/* Note that adding stats is only meaningful for the counters (eg. RADAR_NUM_JUMPS),
* not for the percentages (RADAR_AIR). */
RadarValues v;
2004-10-23 17:43:49 +00:00
NoteDataUtil::GetRadarValues( m_Player[p].m_NoteData, GAMESTATE->m_pCurSong->m_fMusicLengthSeconds, v );
2005-02-16 03:25:45 +00:00
STATSMAN->m_CurStageStats.m_player[p].radarPossible += v;
2004-07-11 07:21:33 +00:00
NoteDataWithScoring::GetActualRadarValues( m_Player[p].m_NoteData, p, GAMESTATE->m_pCurSong->m_fMusicLengthSeconds, v );
2005-02-16 03:25:45 +00:00
STATSMAN->m_CurStageStats.m_player[p].radarActual += v;
}
2004-02-16 10:22:18 +00:00
/* Extremely important: if we don't remove attacks before moving on to the next
* screen, they'll still be turned on eventually. */
GAMESTATE->RemoveAllActiveAttacks();
FOREACH_EnabledPlayer( p )
m_ActiveAttackList[p].Refresh();
2003-12-23 02:18:27 +00:00
}
void ScreenGameplay::StageFinished( bool bBackedOut )
2003-12-23 02:18:27 +00:00
{
if( GAMESTATE->IsCourseMode() && GAMESTATE->m_PlayMode != PLAY_MODE_ENDLESS )
{
2004-01-03 04:38:17 +00:00
LOG->Trace("Stage finished at index %i/%i", GAMESTATE->GetCourseSongIndex(), (int) m_apSongsQueue.size() );
2003-12-23 02:18:27 +00:00
/* +1 to skip the current song; that's done already. */
for( unsigned iPlaySongIndex = GAMESTATE->GetCourseSongIndex()+1;
iPlaySongIndex < m_apSongsQueue.size(); ++iPlaySongIndex )
{
LOG->Trace("Running stats for %i", iPlaySongIndex );
2004-05-16 12:34:02 +00:00
FOREACH_EnabledPlayer(p)
2003-12-23 02:18:27 +00:00
{
SetupSong( p, iPlaySongIndex );
m_Player[p].ApplyWaitingTransforms();
SongFinished();
}
}
}
// save current stage stats
if( !bBackedOut )
2005-02-16 03:25:45 +00:00
STATSMAN->m_vPlayedStageStats.push_back( STATSMAN->m_CurStageStats );
2004-01-23 02:04:34 +00:00
/* Reset options. */
GAMESTATE->RestoreSelectedOptions();
}
2002-05-20 08:59:37 +00:00
void ScreenGameplay::HandleScreenMessage( const ScreenMessage SM )
{
CHECKPOINT_M( ssprintf("HandleScreenMessage(%i)", SM) );
if( SM == SM_DoneFadingIn )
2002-05-20 08:59:37 +00:00
{
2004-04-12 20:11:36 +00:00
SOUND->PlayOnceFromAnnouncer( "gameplay ready" );
2003-03-09 00:55:49 +00:00
m_Ready.StartTransitioning( SM_PlayGo );
}
else if( SM == SM_PlayGo )
{
2004-02-16 05:29:33 +00:00
if( GAMESTATE->IsExtraStage() || GAMESTATE->IsExtraStage2() )
2004-04-12 20:11:36 +00:00
SOUND->PlayOnceFromAnnouncer( "gameplay here we go extra" );
2004-02-16 05:29:33 +00:00
else if( GAMESTATE->IsFinalStage() )
2004-04-12 20:11:36 +00:00
SOUND->PlayOnceFromAnnouncer( "gameplay here we go final" );
2004-02-16 05:29:33 +00:00
else
2004-04-12 20:11:36 +00:00
SOUND->PlayOnceFromAnnouncer( "gameplay here we go normal" );
2004-02-16 05:29:33 +00:00
2003-03-09 00:55:49 +00:00
m_Go.StartTransitioning( SM_None );
2003-01-26 04:58:07 +00:00
GAMESTATE->m_bPastHereWeGo = true;
m_DancingState = STATE_DANCING; // STATE CHANGE! Now the user is allowed to press Back
}
else if( SM == SM_NotesEnded ) // received while STATE_DANCING
{
/* Do this in LoadNextSong, so we don't tween off old attacks until
* m_NextSong finishes. */
// GAMESTATE->RemoveAllActiveAttacks();
FOREACH_EnabledPlayer(p)
2002-07-23 01:41:40 +00:00
{
/* If either player's passmark is enabled, check it. */
if( GAMESTATE->m_pPlayerState[p]->m_PlayerOptions.m_fPassmark > 0 &&
m_pLifeMeter[p] &&
m_pLifeMeter[p]->GetLife() < GAMESTATE->m_pPlayerState[p]->m_PlayerOptions.m_fPassmark )
{
LOG->Trace("Player %i failed: life %f is under %f",
p+1, m_pLifeMeter[p]->GetLife(), GAMESTATE->m_pPlayerState[p]->m_PlayerOptions.m_fPassmark );
STATSMAN->m_CurStageStats.m_player[p].bFailed = true;
}
/* Mark failure. This hasn't been done yet if m_bTwoPlayerRecovery is set. */
if( GAMESTATE->GetPlayerFailType(p) != SongOptions::FAIL_OFF &&
(m_pLifeMeter[p] && m_pLifeMeter[p]->IsFailing()) ||
(m_pCombinedLifeMeter && m_pCombinedLifeMeter->IsFailing(p)) )
STATSMAN->m_CurStageStats.m_player[p].bFailed = true;
if( !STATSMAN->m_CurStageStats.m_player[p].bFailed )
STATSMAN->m_CurStageStats.m_player[p].iSongsPassed++;
}
2002-07-27 19:29:51 +00:00
/* If all players have *really* failed (bFailed, not the life meter or
* bFailedEarlier): */
const bool bAllReallyFailed = STATSMAN->m_CurStageStats.AllFailed();
2005-03-23 02:11:33 +00:00
if( !bAllReallyFailed && !IsLastSong() )
{
/* Load the next course song. First, fade out and stop the music. */
float fFadeLengthSeconds = MUSIC_FADE_OUT_SECONDS;
RageSoundParams p = m_pSoundMusic->GetParams();
p.m_FadeLength = fFadeLengthSeconds;
p.m_LengthSeconds = GAMESTATE->m_fMusicSeconds + fFadeLengthSeconds;
m_pSoundMusic->SetParams(p);
SCREENMAN->PostMessageToTopScreen( SM_StartLoadingNextSong, fFadeLengthSeconds );
return;
}
// update dancing characters for win / lose
DancingCharacters *Dancers = m_SongBackground.GetDancingCharacters();
if( Dancers )
2004-05-16 12:34:02 +00:00
FOREACH_EnabledPlayer(p)
{
/* XXX: In battle modes, switch( GAMESTATE->GetStageResult(p) ). */
if( STATSMAN->m_CurStageStats.m_player[p].bFailed )
Dancers->Change2DAnimState( p, AS2D_FAIL ); // fail anim
else if( m_pLifeMeter[p] && m_pLifeMeter[p]->GetLife() == 1.0f ) // full life
Dancers->Change2DAnimState( p, AS2D_WINFEVER ); // full life pass anim
else
Dancers->Change2DAnimState( p, AS2D_WIN ); // pass anim
}
/* End round. */
if( m_DancingState == STATE_OUTRO ) // ScreenGameplay already ended
return; // ignore
m_DancingState = STATE_OUTRO;
AbortGiveUp( false );
2003-04-14 22:12:54 +00:00
GAMESTATE->RemoveAllActiveAttacks();
FOREACH_EnabledPlayer( p )
m_ActiveAttackList[p].Refresh();
LIGHTSMAN->SetLightsMode( LIGHTSMODE_ALL_CLEARED );
2003-11-16 04:45:12 +00:00
if( bAllReallyFailed )
{
this->PostScreenMessage( SM_BeginFailed, 0 );
return;
}
// do they deserve an extra stage?
if( GAMESTATE->HasEarnedExtraStage() )
{
TweenOffScreen();
m_Extra.StartTransitioning( SM_GoToNextScreen );
SOUND->PlayOnceFromAnnouncer( "gameplay extra" );
}
else
{
TweenOffScreen();
switch( GAMESTATE->m_PlayMode )
{
case PLAY_MODE_BATTLE:
case PLAY_MODE_RAVE:
{
PlayerNumber winner = GAMESTATE->GetBestPlayer();
switch( winner )
2003-03-09 00:55:49 +00:00
{
case PLAYER_INVALID:
m_Draw.StartTransitioning( SM_GoToNextScreen );
break;
default:
m_Win[winner].StartTransitioning( SM_GoToNextScreen );
break;
2003-03-09 00:55:49 +00:00
}
2002-07-28 20:28:37 +00:00
}
break;
default:
m_Cleared.StartTransitioning( SM_GoToNextScreen );
break;
2002-07-27 19:29:51 +00:00
}
SOUND->PlayOnceFromAnnouncer( "gameplay cleared" );
2002-05-20 08:59:37 +00:00
}
}
else if( SM == SM_StartLoadingNextSong )
{
m_pSoundMusic->Stop();
/* Next song. */
FOREACH_EnabledPlayer(p)
2005-03-23 02:11:33 +00:00
{
if( !STATSMAN->m_CurStageStats.m_player[p].bFailed )
2005-03-23 02:11:33 +00:00
{
// give a little life back between stages
if( m_pLifeMeter[p] )
m_pLifeMeter[p]->OnSongEnded();
if( m_pCombinedLifeMeter )
m_pCombinedLifeMeter->OnSongEnded();
2005-03-23 02:11:33 +00:00
}
}
2002-05-20 08:59:37 +00:00
int iPlaySongIndex = GAMESTATE->GetCourseSongIndex()+1;
iPlaySongIndex %= m_apSongsQueue.size();
m_apSongsQueue[iPlaySongIndex]->PushSelf( LUA->L );
GAMESTATE->m_Environment->Set( "NextSong" );
MESSAGEMAN->Broadcast( "NextCourseSong" );
GAMESTATE->m_Environment->Unset( "NextSong" );
m_NextSong.PlayCommand( "Start" );
m_NextSong.Reset();
m_NextSong.StartTransitioning( SM_LoadNextSong );
LoadCourseSongNumber( GAMESTATE->GetCourseSongIndex()+1 );
COMMAND( m_sprCourseSongNumber, "ChangeIn" );
}
else if( SM == SM_LoadNextSong )
{
SongFinished();
2004-02-14 00:39:24 +00:00
COMMAND( m_sprCourseSongNumber, "ChangeOut" );
LoadNextSong();
2003-02-09 21:10:56 +00:00
GAMESTATE->m_bPastHereWeGo = true;
m_NextSong.Reset();
m_NextSong.PlayCommand( "Finish" );
m_NextSong.StartTransitioning( SM_None );
2003-02-05 20:50:12 +00:00
/* We're fading in, so don't hit any notes for a few seconds; they'll be
* obscured by the fade. */
StartPlayingSong( m_NextSong.GetLengthSeconds()+2, 0 );
}
else if( SM == SM_PlayToasty )
{
if( PREFSMAN->m_bEasterEggs )
2003-03-16 19:11:51 +00:00
if( !m_Toasty.IsTransitioning() && !m_Toasty.IsFinished() ) // don't play if we've already played it once
m_Toasty.StartTransitioning();
}
else if( SM >= SM_100Combo && SM <= SM_1000Combo )
{
int iCombo = (SM-SM_100Combo+1)*100;
PlayAnnouncer( ssprintf("gameplay %d combo",iCombo), 2 );
}
else if( SM == SM_ComboStopped )
{
2004-02-16 05:29:33 +00:00
PlayAnnouncer( "gameplay combo stopped", 2 );
}
else if( SM == SM_ComboContinuing )
{
2004-02-16 05:29:33 +00:00
PlayAnnouncer( "gameplay combo overflow", 2 );
}
else if( SM >= SM_BattleTrickLevel1 && SM <= SM_BattleTrickLevel3 )
{
int iTrickLevel = SM-SM_BattleTrickLevel1+1;
PlayAnnouncer( ssprintf("gameplay battle trick level%d",iTrickLevel), 3 );
switch( SM )
{
case SM_BattleTrickLevel1: m_soundBattleTrickLevel1.Play(); break;
case SM_BattleTrickLevel2: m_soundBattleTrickLevel2.Play(); break;
case SM_BattleTrickLevel3: m_soundBattleTrickLevel3.Play(); break;
default: ASSERT(0);
}
}
else if( SM >= SM_BattleDamageLevel1 && SM <= SM_BattleDamageLevel3 )
{
int iDamageLevel = SM-SM_BattleDamageLevel1+1;
PlayAnnouncer( ssprintf("gameplay battle damage level%d",iDamageLevel), 3 );
}
else if( SM == SM_SaveChangedBeforeGoingBack )
{
2002-08-01 05:11:11 +00:00
if( m_bChangedOffsetOrBPM )
{
m_bChangedOffsetOrBPM = false;
ShowSavePrompt( SM_GoToScreenAfterBack );
}
else
{
HandleScreenMessage( SM_GoToScreenAfterBack );
}
}
else if( SM == SM_GoToScreenAfterBack )
{
SongFinished();
StageFinished( true );
2004-01-23 02:04:34 +00:00
GAMESTATE->CancelStage();
SCREENMAN->DeletePreparedScreens();
SCREENMAN->SetNewScreen( PREV_SCREEN );
}
else if( SM == SM_GoToNextScreen )
{
2002-07-27 19:29:51 +00:00
if( m_bChangedOffsetOrBPM )
{
m_bChangedOffsetOrBPM = false;
2005-01-30 03:08:42 +00:00
ShowSavePrompt( SM_GoToNextScreen );
2002-07-27 19:29:51 +00:00
}
else
{
SongFinished();
StageFinished( false );
2002-05-20 08:59:37 +00:00
SCREENMAN->SetNewScreen( NEXT_SCREEN );
}
}
else if( SM == SM_LoseFocus )
{
2004-02-09 19:56:28 +00:00
/* We might have turned the song timer off. Be sure to turn it back on. */
SOUND->HandleSongTimer( true );
}
else if( SM == SM_BeginFailed )
{
2002-05-20 08:59:37 +00:00
m_DancingState = STATE_OUTRO;
AbortGiveUp( false );
2004-10-25 03:47:22 +00:00
m_pSoundMusic->StopPlaying();
2004-01-12 09:36:01 +00:00
m_soundAssistTick.StopPlaying(); /* Stop any queued assist ticks. */
2003-04-13 21:17:14 +00:00
TweenOffScreen();
2005-01-30 03:08:42 +00:00
m_Failed.StartTransitioning( SM_GoToNextScreen );
2002-05-20 08:59:37 +00:00
2002-08-01 13:42:56 +00:00
// show the survive time if extra stage
if( GAMESTATE->IsExtraStage() || GAMESTATE->IsExtraStage2() )
{
float fMaxSurviveSeconds = 0;
2004-05-16 12:34:02 +00:00
FOREACH_EnabledPlayer(p)
2005-02-16 03:25:45 +00:00
fMaxSurviveSeconds = max( fMaxSurviveSeconds, STATSMAN->m_CurStageStats.m_player[p].fAliveSeconds );
ASSERT( fMaxSurviveSeconds > 0 );
2004-02-22 19:51:46 +00:00
m_textSurviveTime.SetText( "TIME: " + SecondsToMMSSMsMs(fMaxSurviveSeconds) );
2003-08-07 10:15:16 +00:00
SET_XY_AND_ON_COMMAND( m_textSurviveTime );
2002-08-01 13:42:56 +00:00
}
2003-08-25 17:15:47 +00:00
2004-02-15 23:10:40 +00:00
if( GAMESTATE->IsCourseMode() )
2005-03-11 02:38:08 +00:00
if( GAMESTATE->GetCourseSongIndex() >= int(m_apSongsQueue.size() / 2) )
2004-04-12 20:11:36 +00:00
SOUND->PlayOnceFromAnnouncer( "gameplay oni failed halfway" );
2003-08-25 17:15:47 +00:00
else
2004-04-12 20:11:36 +00:00
SOUND->PlayOnceFromAnnouncer( "gameplay oni failed" );
2003-08-25 17:15:47 +00:00
else
2004-04-12 20:11:36 +00:00
SOUND->PlayOnceFromAnnouncer( "gameplay failed" );
}
else if( SM == SM_StopMusic )
{
2004-10-25 03:47:22 +00:00
m_pSoundMusic->Stop();
}
else if( SM == SM_Pause )
{
2005-03-11 04:12:48 +00:00
/* Ignore SM_Pause when in demonstration. */
if( GAMESTATE->m_bDemonstrationOrJukebox )
return;
2005-03-11 03:54:40 +00:00
if( !m_bPaused )
PauseGame( true );
2002-05-20 08:59:37 +00:00
}
2002-06-14 22:25:22 +00:00
}
2002-05-20 08:59:37 +00:00
2002-06-14 22:25:22 +00:00
void ScreenGameplay::TweenOnScreen()
{
2003-04-13 21:17:14 +00:00
ON_COMMAND( m_sprLifeFrame );
ON_COMMAND( m_sprStage );
2003-12-18 23:19:02 +00:00
ON_COMMAND( m_sprCourseSongNumber );
2004-02-14 00:39:24 +00:00
ON_COMMAND( m_sprStageFrame );
2003-04-13 21:17:14 +00:00
ON_COMMAND( m_textSongOptions );
ON_COMMAND( m_sprScoreFrame );
ON_COMMAND( m_BPMDisplay );
ON_COMMAND( m_MaxCombo );
2003-06-30 18:08:27 +00:00
if( m_pCombinedLifeMeter )
ON_COMMAND( *m_pCombinedLifeMeter );
2004-05-16 12:34:02 +00:00
FOREACH_PlayerNumber(p)
2002-08-28 22:42:40 +00:00
{
2003-06-30 18:08:27 +00:00
if( m_pLifeMeter[p] )
ON_COMMAND( *m_pLifeMeter[p] );
2002-08-28 22:42:40 +00:00
if( !GAMESTATE->IsPlayerEnabled(p) )
continue;
2003-04-13 21:17:14 +00:00
ON_COMMAND( m_textCourseSongNumber[p] );
ON_COMMAND( m_textStepsDescription[p] );
2003-11-26 06:40:03 +00:00
if( m_pPrimaryScoreDisplay[p] )
ON_COMMAND( *m_pPrimaryScoreDisplay[p] );
if( m_pSecondaryScoreDisplay[p] )
ON_COMMAND( *m_pSecondaryScoreDisplay[p] );
2003-04-13 21:17:14 +00:00
ON_COMMAND( m_textPlayerOptions[p] );
2004-03-17 06:01:17 +00:00
ON_COMMAND( m_ActiveAttackList[p] );
2003-04-13 21:17:14 +00:00
ON_COMMAND( m_DifficultyIcon[p] );
ON_COMMAND( m_DifficultyMeter[p] );
2002-08-28 22:42:40 +00:00
}
2004-08-13 08:24:11 +00:00
if (m_ShowScoreboard)
FOREACH_NSScoreBoardColumn( sc )
ON_COMMAND( m_Scoreboard[sc] );
2002-05-20 08:59:37 +00:00
}
2002-06-14 22:25:22 +00:00
void ScreenGameplay::TweenOffScreen()
{
ScreenWithMenuElements::TweenOffScreen();
2003-04-13 21:17:14 +00:00
OFF_COMMAND( m_sprLifeFrame );
OFF_COMMAND( m_sprStage );
2003-12-18 23:19:02 +00:00
OFF_COMMAND( m_sprCourseSongNumber );
2004-02-14 00:39:24 +00:00
OFF_COMMAND( m_sprStageFrame );
2003-04-13 21:17:14 +00:00
OFF_COMMAND( m_textSongOptions );
OFF_COMMAND( m_sprScoreFrame );
OFF_COMMAND( m_BPMDisplay );
OFF_COMMAND( m_MaxCombo );
2003-06-30 18:08:27 +00:00
if( m_pCombinedLifeMeter )
OFF_COMMAND( *m_pCombinedLifeMeter );
2004-05-16 12:34:02 +00:00
FOREACH_PlayerNumber(p)
2003-04-13 21:17:14 +00:00
{
2003-06-30 18:08:27 +00:00
if( m_pLifeMeter[p] )
OFF_COMMAND( *m_pLifeMeter[p] );
2003-04-13 21:17:14 +00:00
if( !GAMESTATE->IsPlayerEnabled(p) )
continue;
OFF_COMMAND( m_textCourseSongNumber[p] );
OFF_COMMAND( m_textStepsDescription[p] );
2003-11-26 06:40:03 +00:00
if( m_pPrimaryScoreDisplay[p] )
OFF_COMMAND( *m_pPrimaryScoreDisplay[p] );
if( m_pSecondaryScoreDisplay[p] )
OFF_COMMAND( *m_pSecondaryScoreDisplay[p] );
2003-04-13 21:17:14 +00:00
OFF_COMMAND( m_textPlayerOptions[p] );
2004-03-17 06:01:17 +00:00
OFF_COMMAND( m_ActiveAttackList[p] );
2003-04-13 21:17:14 +00:00
OFF_COMMAND( m_DifficultyIcon[p] );
OFF_COMMAND( m_DifficultyMeter[p] );
2003-04-13 21:17:14 +00:00
}
if (m_ShowScoreboard)
FOREACH_NSScoreBoardColumn( sc )
OFF_COMMAND( m_Scoreboard[sc] );
2004-08-13 08:24:11 +00:00
m_textDebug.StopTweening();
m_textDebug.BeginTweening( 1/8.f );
m_textDebug.SetDiffuse( RageColor(1,1,1,0) );
2002-06-14 22:25:22 +00:00
}
void ScreenGameplay::ShowOniGameOver( PlayerNumber pn )
2002-08-01 21:55:40 +00:00
{
m_sprOniGameOver[pn].SetDiffuse( RageColor(1,1,1,1) );
m_sprOniGameOver[pn].BeginTweening( 0.5f, Actor::TWEEN_BOUNCE_END );
2004-11-05 06:35:10 +00:00
m_sprOniGameOver[pn].SetY( SCREEN_CENTER_Y );
2003-03-02 01:43:33 +00:00
m_sprOniGameOver[pn].SetEffectBob( 4, RageVector3(0,6,0) );
2002-08-01 21:55:40 +00:00
}
2004-06-08 05:22:33 +00:00
/*
* (c) 2001-2004 Chris Danford, Glenn Maynard
* 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.
*/