add per-player danger and per-player dead animations

This commit is contained in:
Chris Danford
2003-12-07 20:29:42 +00:00
parent dc3063cf8c
commit ade8308aa1
10 changed files with 254 additions and 108 deletions
+1
View File
@@ -1933,6 +1933,7 @@ LeftEdge=20
TopEdge=20
RightEdge=620
BottomEdge=460
BlinkDangerAll=1
[Judgment]
BooOddCommand=
+32 -7
View File
@@ -507,7 +507,7 @@ void BGAnimationLayer::LoadFromIni( CString sAniDir, CString sLayer )
bool Stretch = false;
{
CString type;
CString type = "sprite";
ini.GetValue( sLayer, "Type", type );
type.MakeLower();
@@ -515,13 +515,38 @@ void BGAnimationLayer::LoadFromIni( CString sAniDir, CString sLayer )
* and "stretch=1". "type=1" is for backwards-compatibility. */
ini.GetValue( sLayer, "Stretch", Stretch );
if( atoi(type) == 0 || type == "sprite" ) m_Type = TYPE_SPRITE;
else if( atoi(type) == 1 ) { m_Type = TYPE_SPRITE; Stretch = true; }
else if( atoi(type) == 2 || type == "particles" ) m_Type = TYPE_PARTICLES;
else if( atoi(type) == 3 || type == "tiles" ) m_Type = TYPE_TILES;
// Check for string match first, then do integer match.
// "if(atoi(type)==0)" was matching against all string matches.
// -Chris
if( stricmp(type,"sprite")==0 )
{
m_Type = TYPE_SPRITE;
}
else if( stricmp(type,"particles")==0 )
{
m_Type = TYPE_PARTICLES;
}
else if( stricmp(type,"tiles")==0 )
{
m_Type = TYPE_TILES;
}
else if( atoi(type) == 1 )
{
m_Type = TYPE_SPRITE;
Stretch = true;
}
else if( atoi(type) == 2 )
{
m_Type = TYPE_PARTICLES;
}
else if( atoi(type) == 3 )
{
m_Type = TYPE_TILES;
}
else
RageException::Throw("Unknown %s::type in %s: \"%s\"",
sLayer.c_str(), sAniDir.c_str(), type.c_str() );
{
m_Type = TYPE_SPRITE;
}
}
{
+77 -13
View File
@@ -35,6 +35,7 @@ const float FADE_SECONDS = 1.0f;
#define TOP_EDGE THEME->GetMetricI("Background","TopEdge")
#define RIGHT_EDGE THEME->GetMetricI("Background","RightEdge")
#define BOTTOM_EDGE THEME->GetMetricI("Background","BottomEdge")
CachedThemeMetricB BLINK_DANGER_ALL("Background","BlinkDangerAll");
#define RECT_BACKGROUND RectI(LEFT_EDGE,TOP_EDGE,RIGHT_EDGE,BOTTOM_EDGE)
@@ -45,14 +46,20 @@ CString RandomBackground(int num) { return ssprintf("__random%i", num); }
Background::Background()
{
m_bInDanger = false;
BLINK_DANGER_ALL.Refresh();
int p;
m_iCurBGChangeIndex = -1;
m_pCurrentBGA = NULL;
m_pFadingBGA = NULL;
m_fSecsLeftInFade = 0;
m_BGADanger.LoadFromAniDir( THEME->GetPathToB("ScreenGameplay danger") );
m_DangerAll.LoadFromAniDir( THEME->GetPathToB("ScreenGameplay danger all") );
for( p=0; p<NUM_PLAYERS; p++ )
m_DangerPlayer[p].LoadFromAniDir( THEME->GetPathToB(ssprintf("ScreenGameplay danger p%d",p+1)) );
for( p=0; p<NUM_PLAYERS; p++ )
m_DeadPlayer[p].LoadFromAniDir( THEME->GetPathToB(ssprintf("ScreenGameplay dead p%d",p+1)) );
m_quadBGBrightness.StretchTo( RECT_BACKGROUND );
m_quadBGBrightness.SetDiffuse( RageColor(0,0,0,1-PREFSMAN->m_fBGBrightness) );
@@ -68,7 +75,7 @@ Background::Background()
bool bOneOrMoreChars = false;
bool bShowingBeginnerHelper = false;
for( int p=0; p<NUM_PLAYERS; p++ )
for( p=0; p<NUM_PLAYERS; p++ )
{
if( !GAMESTATE->IsHumanPlayer(p) )
continue;
@@ -374,9 +381,20 @@ void Background::LoadFromSong( Song* pSong )
iter->second->SetZoomY( fYZoom );
}
m_BGADanger.SetXY( (float)LEFT_EDGE, (float)TOP_EDGE );
m_BGADanger.SetZoomX( fXZoom );
m_BGADanger.SetZoomY( fYZoom );
m_DangerAll.SetXY( (float)LEFT_EDGE, (float)TOP_EDGE );
m_DangerAll.SetZoomX( fXZoom );
m_DangerAll.SetZoomY( fYZoom );
for( int p=0; p<NUM_PLAYERS; p++ )
{
m_DangerPlayer[p].SetXY( (float)LEFT_EDGE, (float)TOP_EDGE );
m_DangerPlayer[p].SetZoomX( fXZoom );
m_DangerPlayer[p].SetZoomY( fYZoom );
m_DeadPlayer[p].SetXY( (float)LEFT_EDGE, (float)TOP_EDGE );
m_DeadPlayer[p].SetZoomX( fXZoom );
m_DeadPlayer[p].SetZoomY( fYZoom );
}
TEXTUREMAN->EnableOddDimensionWarning();
@@ -433,12 +451,21 @@ void Background::Update( float fDeltaTime )
{
ActorFrame::Update( fDeltaTime );
if( IsDangerVisible() )
if( IsDangerAllVisible() )
{
m_BGADanger.Update( fDeltaTime );
m_DangerAll.Update( fDeltaTime );
}
/* Always update the current background, even when m_BGADanger is being displayed.
for( int p=0; p<NUM_PLAYERS; p++ )
{
if( IsDangerPlayerVisible((PlayerNumber)p) )
m_DangerPlayer[p].Update( fDeltaTime );
if( IsDeadPlayerVisible((PlayerNumber)p) )
m_DeadPlayer[p].Update( fDeltaTime );
}
/* Always update the current background, even when m_DangerAll is being displayed.
* Otherwise, we'll stop updating movies during danger (which may stop them from
* playing), and we won't start clips at the right time, which will throw backgrounds
* off sync. */
@@ -469,12 +496,12 @@ void Background::DrawPrimitives()
ActorFrame::DrawPrimitives();
if( IsDangerVisible() )
if( IsDangerAllVisible() )
{
// Since this only shows when DANGER is visible, it will flash red on it's own accord :)
if( m_pDancingCharacters )
m_pDancingCharacters->m_bDrawDangerLight = true;
m_BGADanger.Draw();
m_DangerAll.Draw();
}
else
{
@@ -484,6 +511,14 @@ void Background::DrawPrimitives()
m_pCurrentBGA->Draw();
if( m_pFadingBGA )
m_pFadingBGA->Draw();
for( int p=0; p<NUM_PLAYERS; p++ )
{
if( IsDangerPlayerVisible((PlayerNumber)p) )
m_DangerPlayer[p].Draw();
if( IsDeadPlayerVisible((PlayerNumber)p) )
m_DeadPlayer[p].Draw();
}
}
if( m_pDancingCharacters )
@@ -494,9 +529,38 @@ void Background::DrawPrimitives()
m_quadBorder[i].Draw();
}
bool Background::IsDangerVisible()
bool Background::IsDangerAllVisible()
{
return m_bInDanger && PREFSMAN->m_bShowDanger && (RageTimer::GetTimeSinceStart() - (int)RageTimer::GetTimeSinceStart()) < 0.5f;
if( GAMESTATE->m_SongOptions.m_FailType == SongOptions::FAIL_OFF )
return false;
if( !PREFSMAN->m_bShowDanger )
return false;
if( GAMESTATE->AllAreInDangerOrWorse() )
{
if( BLINK_DANGER_ALL )
return (RageTimer::GetTimeSinceStart() - (int)RageTimer::GetTimeSinceStart()) < 0.5f;
else
return true;
}
else
return false;
}
bool Background::IsDangerPlayerVisible( PlayerNumber pn )
{
if( GAMESTATE->m_SongOptions.m_FailType == SongOptions::FAIL_OFF )
return false;
if( !PREFSMAN->m_bShowDanger )
return false;
return GAMESTATE->m_HealthState[pn] == GameState::DANGER;
}
bool Background::IsDeadPlayerVisible( PlayerNumber pn )
{
if( GAMESTATE->m_SongOptions.m_FailType == SongOptions::FAIL_OFF )
return false;
return GAMESTATE->m_HealthState[pn] == GameState::DEAD;
}
+7 -9
View File
@@ -36,20 +36,20 @@ public:
void FadeIn();
void FadeOut();
virtual void TurnDangerOn() { m_bInDanger = true; };
virtual void TurnDangerOff() { m_bInDanger = false; };
virtual bool IsInDanger() { return m_bInDanger; };
DancingCharacters* GetDancingCharacters() { return m_pDancingCharacters; };
protected:
bool IsDangerVisible();
bool IsDangerPlayerVisible( PlayerNumber pn );
bool IsDangerAllVisible();
bool IsDeadPlayerVisible( PlayerNumber pn );
void UpdateCurBGChange();
DancingCharacters* m_pDancingCharacters;
BGAnimation m_BGADanger;
BGAnimation m_DangerPlayer[NUM_PLAYERS];
BGAnimation m_DangerAll;
BGAnimation m_DeadPlayer[NUM_PLAYERS];
BGAnimation* CreateSongBGA(const Song *pSong, CString sBGName) const;
BGAnimation* CreateRandomBGA() const;
@@ -63,8 +63,6 @@ protected:
Quad m_quadBGBrightness;
Quad m_quadBorder[4]; // l, t, r, b - cover up the edge of animations that might hang outside of the background rectangle
bool m_bInDanger;
};
+67 -15
View File
@@ -33,6 +33,7 @@
#include "ThemeManager.h"
#include "LightsManager.h"
#include "RageFile.h"
#include "Bookkeeper.h"
#define DEFAULT_MODIFIERS THEME->GetMetric( "Common","DefaultModifiers" )
@@ -143,6 +144,10 @@ void GameState::Reset()
}
LIGHTSMAN->SetLightMode( LIGHTMODE_ATTRACT );
// HACK: save stats intermitently in case of crash
BOOKKEEPER->WriteToDisk();
PROFILEMAN->SaveMachineScoresToDisk();
}
void GameState::Update( float fDelta )
@@ -259,7 +264,10 @@ void GameState::ResetStageStatistics()
m_fOpponentHealthPercent = 1;
m_fTugLifePercentP1 = 0.5f;
for( int p=0; p<NUM_PLAYERS; p++ )
{
m_fSuperMeter[p] = 0;
m_HealthState[p] = ALIVE;
}
}
void GameState::UpdateSongPosition(float fPositionSeconds)
@@ -951,24 +959,41 @@ void GameState::GetRankingFeats( PlayerNumber pn, vector<RankingFeats> &asFeatsO
GetFinalEvalStatsAndSongs( stats, vSongs );
for( int mc=0; mc<NUM_MEMORY_CARDS; mc++ )
// Find Machine Records
for( i=0; i<NUM_RANKING_CATEGORIES; i++ )
{
for( i=0; i<NUM_RANKING_CATEGORIES; i++ )
vector<ProfileManager::CategoryData::HighScore> &vHighScores = PROFILEMAN->m_CategoryDatas[MEMORY_CARD_MACHINE][nt][i].vHighScores;
for( unsigned j=0; j<vHighScores.size(); j++ )
{
vector<ProfileManager::CategoryData::HighScore> &vHighScores = PROFILEMAN->m_CategoryDatas[mc][nt][i].vHighScores;
for( unsigned j=0; j<vHighScores.size(); j++ )
{
if( vHighScores[j].sName != RANKING_TO_FILL_IN_MARKER[pn] )
continue;
if( vHighScores[j].sName != RANKING_TO_FILL_IN_MARKER[pn] )
continue;
RankingFeats feat;
feat.Type = RankingFeats::RANKING;
feat.Feat = ssprintf("#%d in Type %c (%d)", j+1, 'A'+i, stats.iMeter[pn] );
feat.pStringToFill = &vHighScores[j].sName;
feat.g = GRADE_NO_DATA;
feat.Score = (float) vHighScores[j].iScore;
asFeatsOut.push_back( feat );
}
RankingFeats feat;
feat.Type = RankingFeats::RANKING;
feat.Feat = ssprintf("MR #%d in Type %c (%d)", j+1, 'A'+i, stats.iMeter[pn] );
feat.pStringToFill = &vHighScores[j].sName;
feat.g = GRADE_NO_DATA;
feat.Score = (float) vHighScores[j].iScore;
asFeatsOut.push_back( feat );
}
}
// Find Personal Records
for( i=0; i<NUM_RANKING_CATEGORIES; i++ )
{
vector<ProfileManager::CategoryData::HighScore> &vHighScores = PROFILEMAN->m_CategoryDatas[pn][nt][i].vHighScores;
for( unsigned j=0; j<vHighScores.size(); j++ )
{
if( vHighScores[j].sName != RANKING_TO_FILL_IN_MARKER[pn] )
continue;
RankingFeats feat;
feat.Type = RankingFeats::RANKING;
feat.Feat = ssprintf("PR #%d in Type %c (%d)", j+1, 'A'+i, stats.iMeter[pn] );
feat.pStringToFill = &vHighScores[j].sName;
feat.g = GRADE_NO_DATA;
feat.Score = (float) vHighScores[j].iScore;
asFeatsOut.push_back( feat );
}
}
}
@@ -1036,3 +1061,30 @@ void GameState::StoreRankingName( PlayerNumber pn, CString name )
*aFeats[i].pStringToFill = name;
}
}
bool GameState::AllAreInDangerOrWorse() const
{
for( int p=0; p<NUM_PLAYERS; p++ )
if( GAMESTATE->IsPlayerEnabled(p) )
if( m_HealthState[p] < DANGER )
return false;
return true;
}
bool GameState::AllAreDead() const
{
for( int p=0; p<NUM_PLAYERS; p++ )
if( GAMESTATE->IsPlayerEnabled(p) )
if( m_HealthState[p] < DEAD )
return false;
return true;
}
bool GameState::OneIsHot() const
{
for( int p=0; p<NUM_PLAYERS; p++ )
if( GAMESTATE->IsPlayerEnabled(PlayerNumber(p)) )
if( m_HealthState[p] == HOT )
return true;
return false;
}
+5
View File
@@ -161,6 +161,11 @@ public:
// Nonstop/Oni/Endless: for current course (which usually contains multiple songs)
//
StageStats m_CurStageStats; // current stage (not necessarily passed if Extra Stage)
enum HealthState { HOT, ALIVE, DANGER, DEAD };
HealthState m_HealthState[NUM_PLAYERS];
bool AllAreInDangerOrWorse() const;
bool AllAreDead() const;
bool OneIsHot() const;
// used in PLAY_MODE_BATTLE and PLAY_MODE_RAVE
AttackArray m_ActiveAttacks[NUM_PLAYERS];
+24 -4
View File
@@ -425,7 +425,10 @@ void ProfileManager::ReadSongScoresFromFile( CString fn, MemoryCard mc )
{
RageFile f;
if( !f.Open(fn, RageFile::READ) )
{
LOG->Warn( "Couldn't open file '%s'", fn.c_str() );
return;
}
int version;
if( !FileRead(f, version) )
@@ -520,7 +523,10 @@ void ProfileManager::ReadCategoryScoresFromFile( CString fn, MemoryCard mc )
{
RageFile f;
if( !f.Open(fn, RageFile::READ) )
{
LOG->Warn( "Couldn't open file '%s'", fn.c_str() );
return;
}
int version;
if( !FileRead(f, version) )
@@ -552,7 +558,10 @@ void ProfileManager::ReadCourseScoresFromFile( CString fn, MemoryCard mc )
{
RageFile f;
if( !f.Open(fn, RageFile::READ) )
{
LOG->Warn( "Couldn't open file '%s'", fn.c_str() );
return;
}
int version;
if( !FileRead(f, version) )
@@ -633,12 +642,11 @@ void ProfileManager::InitMachineScoresFromDisk()
void ProfileManager::ReadSM300NoteScores()
{
if( !DoesFileExist(SM_300_STATISTICS_FILE) )
return;
IniFile ini;
ini.SetPath( SM_300_STATISTICS_FILE );
if( !ini.ReadFile() ) {
LOG->Trace( "WARNING: Could not read SM 3.0 final statistics '%s'.", SM_300_STATISTICS_FILE );
return; // load nothing
}
// load song statistics
const IniFile::key* pKey = ini.GetKey( "Statistics" );
@@ -707,7 +715,10 @@ void ProfileManager::SaveCategoryScoresToFile( CString fn, MemoryCard mc )
RageFile f;
if( !f.Open(fn, RageFile::WRITE) )
{
LOG->Warn( "Couldn't open file '%s'", fn.c_str() );
return;
}
FileWrite( f, CATEGORY_RANKING_VERSION );
@@ -735,7 +746,10 @@ void ProfileManager::SaveCourseScoresToFile( CString fn, MemoryCard mc )
RageFile f;
if( !f.Open(fn, RageFile::WRITE) )
{
LOG->Warn( "Couldn't open file '%s'", fn.c_str() );
return;
}
FileWrite( f, COURSE_SCORES_VERSION );
@@ -791,7 +805,10 @@ void ProfileManager::SaveSongScoresToFile( CString fn, MemoryCard mc )
RageFile f;
if( !f.Open(fn, RageFile::WRITE) )
{
LOG->Warn( "Couldn't open file '%s'", fn.c_str() );
return;
}
FileWrite( f, STEPS_SCORES_VERSION );
@@ -892,7 +909,10 @@ void ProfileManager::SaveStatsWebPageToFile( CString fn, MemoryCard mc )
{
RageFile f;
if( !f.Open( fn, RageFile::WRITE ) )
{
LOG->Warn( "Couldn't open file '%s'", fn.c_str() );
return;
}
f.PutLine( "<html>" );
f.PutLine( "<head>" );
+41 -49
View File
@@ -958,37 +958,6 @@ float ScreenGameplay::StartPlayingSong(float MinTimeToNotes, float MinTimeToMusi
return fFirstSecond - fStartSecond;
}
bool ScreenGameplay::OneIsHot() const
{
for( int p=0; p<NUM_PLAYERS; p++ )
if( GAMESTATE->IsPlayerEnabled(PlayerNumber(p)) )
if( (m_pLifeMeter[p] && m_pLifeMeter[p]->IsHot()) ||
(m_pCombinedLifeMeter && m_pCombinedLifeMeter->IsHot((PlayerNumber)p)) )
return true;
return false;
}
bool ScreenGameplay::AllAreInDanger() const
{
for( int p=0; p<NUM_PLAYERS; p++ )
if( GAMESTATE->IsPlayerEnabled(PlayerNumber(p)) )
if( (m_pLifeMeter[p] && !m_pLifeMeter[p]->IsInDanger()) ||
(m_pCombinedLifeMeter && !m_pCombinedLifeMeter->IsInDanger((PlayerNumber)p)) )
return false;
return true;
}
bool ScreenGameplay::AllAreFailing() const
{
for( int p=0; p<NUM_PLAYERS; p++ )
if( GAMESTATE->IsPlayerEnabled(PlayerNumber(p)) )
if( (m_pLifeMeter[p] && !m_pLifeMeter[p]->IsFailing()) ||
(m_pCombinedLifeMeter && !m_pCombinedLifeMeter->IsFailing((PlayerNumber)p)) )
return false;
return true;
}
bool ScreenGameplay::AllFailedEarlier() const
{
for( int p=0; p<NUM_PLAYERS; p++ )
@@ -1107,6 +1076,39 @@ void ScreenGameplay::Update( float fDeltaTime )
int pn;
m_BeginnerHelper.Update(fDeltaTime);
//
// update GameState HealthState
//
for( int p=0; p<NUM_PLAYERS; p++ )
{
if( GAMESTATE->IsPlayerEnabled(p) )
{
if(
(m_pLifeMeter[p] && m_pLifeMeter[p]->IsHot()) ||
(m_pCombinedLifeMeter && m_pCombinedLifeMeter->IsHot((PlayerNumber)p)) )
{
GAMESTATE->m_HealthState[p] = GameState::HOT;
}
else if(
(m_pLifeMeter[p] && m_pLifeMeter[p]->IsFailing()) ||
(m_pCombinedLifeMeter && m_pCombinedLifeMeter->IsFailing((PlayerNumber)p)) )
{
GAMESTATE->m_HealthState[p] = GameState::DEAD;
}
else if(
(m_pLifeMeter[p] && m_pLifeMeter[p]->IsInDanger()) ||
(m_pCombinedLifeMeter && m_pCombinedLifeMeter->IsInDanger((PlayerNumber)p)) )
{
GAMESTATE->m_HealthState[p] = GameState::DANGER;
}
else
{
GAMESTATE->m_HealthState[p] = GameState::ALIVE;
}
}
}
switch( m_DancingState )
{
case STATE_DANCING:
@@ -1124,19 +1126,6 @@ void ScreenGameplay::Update( float fDeltaTime )
if( GAMESTATE->m_fMusicSeconds > fSecondsToStop && !m_NextSongOut.IsTransitioning() )
this->PostScreenMessage( SM_NotesEnded, 0 );
//
// Handle the background danger graphic. Never show it in FAIL_OFF. Don't
// show it if everyone is already failing: it's already too late and it's
// annoying for it to show for the entire duration of a song.
//
if( GAMESTATE->m_SongOptions.m_FailType != SongOptions::FAIL_OFF )
{
if( AllAreInDanger() && !AllAreFailing() )
m_Background.TurnDangerOn();
else
m_Background.TurnDangerOff();
}
//
// check for fail
//
@@ -1221,9 +1210,12 @@ void ScreenGameplay::Update( float fDeltaTime )
case PLAY_MODE_ARCADE:
case PLAY_MODE_BATTLE:
case PLAY_MODE_RAVE:
if( OneIsHot() ) m_announcerHot.PlayRandom();
else if( AllAreInDanger() ) m_announcerDanger.PlayRandom();
else m_announcerGood.PlayRandom();
if( GAMESTATE->OneIsHot() )
m_announcerHot.PlayRandom();
else if( GAMESTATE->AllAreInDangerOrWorse() )
m_announcerDanger.PlayRandom();
else
m_announcerGood.PlayRandom();
if( m_pCombinedLifeMeter )
m_pCombinedLifeMeter->OnTaunt();
break;
@@ -1301,7 +1293,7 @@ void ScreenGameplay::UpdateCheckFail()
/* 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 && !AllAreFailing() )
PREFSMAN->m_bTwoPlayerRecovery && !GAMESTATE->AllAreDead() )
continue;
LOG->Trace("Player %d failed", (int)pn);
@@ -1323,7 +1315,7 @@ void ScreenGameplay::UpdateCheckFail()
/* If FAIL_ARCADE and everyone is failing, start SM_BeginFailed. */
if( GAMESTATE->m_SongOptions.m_FailType == SongOptions::FAIL_ARCADE &&
AllAreFailing() )
GAMESTATE->AllAreDead() )
SCREENMAN->PostMessageToTopScreen( SM_BeginFailed, 0 );
}
-3
View File
@@ -76,9 +76,6 @@ protected:
float StartPlayingSong(float MinTimeToNotes, float MinTimeToMusic);
void ShowSavePrompt( ScreenMessage SM_SendWhenDone );
bool OneIsHot() const;
bool AllAreInDanger() const;
bool AllAreFailing() const;
bool AllFailedEarlier() const;
bool IsTimeToPlayTicks() const;
void UpdateLyrics( float fDeltaTime );
-8
View File
@@ -30,8 +30,6 @@
#include "UnlockSystem.h"
#include "ProductInfo.h"
#include "LightsManager.h"
#include "Bookkeeper.h"
#include "ProfileManager.h"
#define LOGO_ON_COMMAND THEME->GetMetric("ScreenTitleMenu","LogoOnCommand")
@@ -73,12 +71,6 @@ ScreenTitleMenu::ScreenTitleMenu( CString sClassName ) : ScreenSelect( sClassNam
return;
}
// HACK: save stats intermitently in case of crash
BOOKKEEPER->WriteToDisk();
PROFILEMAN->SaveMachineScoresToDisk();
/* XXX We really need two common calls: 1, something run when exiting from gameplay
* (to do this reset), and 2, something run when entering gameplay, to apply default
* options. Having special cases in attract screens and the title menu to reset