2005-07-29 02:23:02 +00:00
#include "global.h"
#include "ScreenOptionsEditCourse.h"
#include "ScreenManager.h"
#include "RageLog.h"
#include "GameState.h"
#include "SongManager.h"
#include "CommonMetrics.h"
#include "GameManager.h"
#include "song.h"
2005-07-30 04:50:17 +00:00
#include "ScreenMiniMenu.h"
2005-07-30 23:40:26 +00:00
#include "ScreenPrompt.h"
2005-08-03 03:28:13 +00:00
#include "CourseUtil.h"
2005-12-22 03:10:04 +00:00
#include "LocalizedString.h"
2006-01-17 21:23:26 +00:00
#include "OptionRowHandler.h"
2005-07-29 02:23:02 +00:00
enum EditCourseRow
{
2005-08-01 05:12:06 +00:00
EditCourseRow_Type ,
EditCourseRow_Meter ,
2005-07-29 02:23:02 +00:00
NUM_EditCourseRow
};
2005-07-30 04:50:17 +00:00
AutoScreenMessage ( SM_BackFromContextMenu )
2005-07-29 02:23:02 +00:00
enum CourseEntryAction
{
CourseEntryAction_Edit ,
CourseEntryAction_InsertEntry ,
CourseEntryAction_Delete ,
NUM_CourseEntryAction
};
2006-01-04 22:30:51 +00:00
static const char * CourseEntryActionNames [] = {
2005-07-29 02:23:02 +00:00
"Edit" ,
"Insert Entry" ,
"Delete" ,
};
XToString ( CourseEntryAction , NUM_CourseEntryAction );
#define FOREACH_CourseEntryAction( i ) FOREACH_ENUM( CourseEntryAction, NUM_CourseEntryAction, i )
2005-07-30 04:50:17 +00:00
static MenuDef g_TempMenu (
"ScreenMiniMenuContext"
);
2005-07-29 02:23:02 +00:00
2006-01-15 20:46:15 +00:00
REGISTER_SCREEN_CLASS ( ScreenOptionsEditCourse );
2005-07-29 02:23:02 +00:00
void ScreenOptionsEditCourse :: Init ()
{
2006-02-20 04:25:53 +00:00
ScreenOptionsEditCourseSubMenu :: Init ();
2006-03-05 03:52:00 +00:00
SubscribeToMessage ( Message_EditCourseDifficultyChanged );
2005-08-15 02:32:36 +00:00
}
2005-07-29 02:23:02 +00:00
2006-02-20 02:38:29 +00:00
static LocalizedString ENTRY ( "OptionTitles" , "Entry %d" );
2005-08-15 02:32:36 +00:00
void ScreenOptionsEditCourse :: BeginScreen ()
{
2005-07-29 02:23:02 +00:00
// save a backup that we'll use if we revert.
ASSERT ( GAMESTATE -> m_pCurCourse );
Course * pCourse = GAMESTATE -> m_pCurCourse ;
m_Original = * pCourse ;
2005-08-15 16:02:14 +00:00
SONGMAN -> GetSongs ( m_vpDisplayedSongs );
2005-07-29 02:23:02 +00:00
vector < OptionRowHandler *> vHands ;
2006-01-17 21:23:26 +00:00
OptionRowHandler * pHand = OptionRowHandlerUtil :: MakeNull ();
pHand -> m_Def . m_sName = "Type" ;
pHand -> m_Def . m_layoutType = LAYOUT_SHOW_ONE_IN_ROW ;
pHand -> m_Def . m_bExportOnChange = true ;
2006-02-20 02:38:29 +00:00
pHand -> m_Def . m_bAllowThemeItems = false ;
2006-02-25 09:33:23 +00:00
pHand -> m_Def . m_bOneChoiceForAllPlayers = true ;
2005-08-01 05:12:06 +00:00
FOREACH_CourseType ( i )
2006-01-17 21:23:26 +00:00
pHand -> m_Def . m_vsChoices . push_back ( CourseTypeToLocalizedString ( i ) );
vHands . push_back ( pHand );
2005-07-29 02:23:02 +00:00
2006-01-17 21:23:26 +00:00
pHand = OptionRowHandlerUtil :: MakeNull ();
pHand -> m_Def . m_sName = "Meter" ;
pHand -> m_Def . m_layoutType = LAYOUT_SHOW_ONE_IN_ROW ;
pHand -> m_Def . m_bExportOnChange = true ;
2006-02-25 09:33:23 +00:00
pHand -> m_Def . m_bOneChoiceForAllPlayers = true ;
2006-01-17 21:23:26 +00:00
pHand -> m_Def . m_vsChoices . push_back ( "Auto" );
2005-07-29 02:23:02 +00:00
for ( int i = MIN_METER ; i <= MAX_METER ; i ++ )
2006-01-17 21:23:26 +00:00
pHand -> m_Def . m_vsChoices . push_back ( ssprintf ( "%d" , i ) );
vHands . push_back ( pHand );
2005-07-29 02:23:02 +00:00
FOREACH_CONST ( CourseEntry , pCourse -> m_vEntries , ce )
{
2006-01-17 21:23:26 +00:00
pHand = OptionRowHandlerUtil :: MakeNull ();
2005-07-29 02:23:02 +00:00
int iEntryIndex = ce - pCourse -> m_vEntries . begin ();
2006-01-17 21:23:26 +00:00
pHand -> m_Def . m_layoutType = LAYOUT_SHOW_ONE_IN_ROW ;
pHand -> m_Def . m_bExportOnChange = true ;
2006-02-20 02:38:29 +00:00
pHand -> m_Def . m_sName = ssprintf ( ENTRY . GetValue (), iEntryIndex + 1 );
pHand -> m_Def . m_bAllowThemeItems = false ;
pHand -> m_Def . m_bAllowThemeTitle = false ;
2006-02-25 09:33:23 +00:00
pHand -> m_Def . m_bOneChoiceForAllPlayers = true ;
2006-02-20 06:18:57 +00:00
pHand -> m_Def . m_vsChoices . push_back ( "RANDOM" ); // XXX Localize?
2005-08-15 16:02:14 +00:00
FOREACH_CONST ( Song * , m_vpDisplayedSongs , s )
2006-01-17 21:23:26 +00:00
pHand -> m_Def . m_vsChoices . push_back ( ( * s ) -> GetTranslitFullTitle () );
vHands . push_back ( pHand );
2005-07-29 02:23:02 +00:00
}
2006-01-17 21:23:26 +00:00
pHand = OptionRowHandlerUtil :: MakeNull ();
pHand -> m_Def . m_sName = "" ;
pHand -> m_Def . m_layoutType = LAYOUT_SHOW_ONE_IN_ROW ;
2006-02-21 02:51:34 +00:00
pHand -> m_Def . m_bExportOnChange = false ;
2006-02-25 09:33:23 +00:00
pHand -> m_Def . m_bOneChoiceForAllPlayers = true ;
2006-01-17 21:23:26 +00:00
pHand -> m_Def . m_vsChoices . push_back ( "Insert Entry" );
vHands . push_back ( pHand );
2005-07-29 02:23:02 +00:00
2006-01-17 21:31:50 +00:00
ScreenOptions :: InitMenu ( vHands );
2005-07-29 02:23:02 +00:00
ScreenOptions :: BeginScreen ();
2005-07-30 23:40:26 +00:00
if ( GAMESTATE -> m_iEditCourseEntryIndex > - 1 )
2006-02-20 06:18:57 +00:00
this -> MoveRowAbsolute ( GAMESTATE -> m_MasterPlayerNumber , NUM_EditCourseRow + GAMESTATE -> m_iEditCourseEntryIndex );
2005-07-30 04:50:17 +00:00
AfterChangeRow ( GAMESTATE -> m_MasterPlayerNumber );
2005-07-29 02:23:02 +00:00
}
2005-12-21 09:56:16 +00:00
static LocalizedString MAXIMUM_COURSE_ENTRIES ( "ScreenOptionsEditCourse" , "The maximum number of entries per course is %d. This course already has %d entries." );
static bool AreEntriesFull ()
{
Course * pCourse = GAMESTATE -> m_pCurCourse ;
if ( pCourse -> m_vEntries . size () >= size_t ( MAX_ENTRIES_PER_COURSE ) )
{
2006-01-22 01:00:06 +00:00
RString sError = ssprintf ( MAXIMUM_COURSE_ENTRIES . GetValue (), MAX_ENTRIES_PER_COURSE , pCourse -> m_vEntries . size () );
2005-12-21 09:56:16 +00:00
ScreenPrompt :: Prompt ( SM_None , sError );
return true ;
}
return false ;
}
static LocalizedString CANNOT_DELETE_LAST_ENTRY ( "ScreenOptionsEditCourse" , "You cannot delete the last entry in a course." );
2005-07-29 02:23:02 +00:00
void ScreenOptionsEditCourse :: HandleScreenMessage ( const ScreenMessage SM )
{
2005-07-30 23:40:26 +00:00
Course * pCourse = GAMESTATE -> m_pCurCourse ;
2005-07-29 02:23:02 +00:00
if ( SM == SM_GoToNextScreen )
{
int iCurRow = m_iCurrentRow [ GAMESTATE -> m_MasterPlayerNumber ];
2005-08-01 05:12:06 +00:00
if ( iCurRow == ( int ) m_pRows . size () - 1 )
2005-07-29 02:23:02 +00:00
{
2006-03-04 10:27:09 +00:00
m_Original = * pCourse ;
WriteCourse ();
2005-07-29 02:23:02 +00:00
this -> HandleScreenMessage ( SM_GoToPrevScreen );
return ; // don't call base
}
}
2005-07-30 23:40:26 +00:00
else if ( SM == SM_GoToPrevScreen )
{
2006-03-04 10:27:09 +00:00
* pCourse = m_Original ;
GAMESTATE -> m_pCurCourse . Set ( pCourse );
2005-07-30 23:40:26 +00:00
GAMESTATE -> m_iEditCourseEntryIndex . Set ( - 1 );
}
2005-07-30 04:50:17 +00:00
else if ( SM == SM_BackFromContextMenu )
2005-07-29 02:23:02 +00:00
{
2005-07-30 04:50:17 +00:00
if ( ! ScreenMiniMenu :: s_bCancelled )
{
switch ( ScreenMiniMenu :: s_iLastRowCode )
{
case CourseEntryAction_Edit :
ScreenOptions :: BeginFadingOut ();
break ;
case CourseEntryAction_InsertEntry :
2006-02-20 02:46:22 +00:00
{
if ( AreEntriesFull () )
return ;
CourseEntry ce ;
CourseUtil :: MakeDefaultEditCourseEntry ( ce );
pCourse -> m_vEntries . insert ( pCourse -> m_vEntries . begin () + GetCourseEntryIndexWithFocus (), ce );
2006-03-18 13:26:01 +00:00
SCREENMAN -> SetNewScreen ( this -> m_sName ); // reload
2005-07-30 04:50:17 +00:00
break ;
2006-02-20 02:46:22 +00:00
}
2005-07-30 04:50:17 +00:00
case CourseEntryAction_Delete :
2006-02-20 02:46:22 +00:00
{
if ( pCourse -> m_vEntries . size () == 1 )
2005-07-30 04:50:17 +00:00
{
2006-02-20 02:46:22 +00:00
ScreenPrompt :: Prompt ( SM_None , CANNOT_DELETE_LAST_ENTRY );
return ;
2005-07-30 04:50:17 +00:00
}
2006-02-20 02:46:22 +00:00
pCourse -> m_vEntries . erase ( pCourse -> m_vEntries . begin () + GetCourseEntryIndexWithFocus () );
GAMESTATE -> m_iEditCourseEntryIndex . Set ( GAMESTATE -> m_iEditCourseEntryIndex );
2006-03-18 13:26:01 +00:00
SCREENMAN -> SetNewScreen ( this -> m_sName ); // reload
2005-07-30 04:50:17 +00:00
break ;
}
2006-02-20 02:46:22 +00:00
}
2005-07-30 04:50:17 +00:00
}
2005-07-29 02:23:02 +00:00
}
ScreenOptions :: HandleScreenMessage ( SM );
}
2005-07-30 04:50:17 +00:00
void ScreenOptionsEditCourse :: AfterChangeRow ( PlayerNumber pn )
2005-07-29 02:23:02 +00:00
{
2005-07-30 04:50:17 +00:00
ScreenOptions :: AfterChangeRow ( pn );
int iCourseEntry = GetCourseEntryIndexWithFocus ();
GAMESTATE -> m_iEditCourseEntryIndex . Set ( iCourseEntry );
2005-07-29 02:23:02 +00:00
}
2005-08-01 05:12:06 +00:00
void ScreenOptionsEditCourse :: AfterChangeValueInRow ( int iRow , PlayerNumber pn )
{
ScreenOptions :: AfterChangeValueInRow ( iRow , pn );
2006-02-21 02:51:34 +00:00
2005-08-01 05:12:06 +00:00
Course * pCourse = GAMESTATE -> m_pCurCourse ;
2006-01-19 07:59:59 +00:00
// Regenerate Trails so that the new values propagate
2006-03-04 02:34:01 +00:00
GAMESTATE -> m_pCurTrail [ PLAYER_1 ]. Set ( NULL );
2006-02-20 04:25:53 +00:00
Trail * pTrail = pCourse -> GetTrailForceRegenCache ( GAMESTATE -> m_stEdit , GAMESTATE -> m_cdEdit );
2005-08-01 05:12:06 +00:00
// cause overlay elements to refresh by changing the course
GAMESTATE -> m_pCurCourse . Set ( pCourse );
2006-03-04 02:34:01 +00:00
GAMESTATE -> m_pCurTrail [ PLAYER_1 ]. Set ( pTrail );
2005-08-01 05:12:06 +00:00
}
2005-07-29 02:23:02 +00:00
void ScreenOptionsEditCourse :: ImportOptions ( int iRow , const vector < PlayerNumber > & vpns )
{
2005-08-01 05:12:06 +00:00
OptionRow & row = * m_pRows [ iRow ];
2006-02-21 02:51:34 +00:00
if ( row . GetRowType () == OptionRow :: RowType_Exit )
return ;
2005-08-01 05:12:06 +00:00
Course * pCourse = GAMESTATE -> m_pCurCourse ;
2006-02-21 11:28:05 +00:00
if ( iRow == ( int ) pCourse -> m_vEntries . size () + NUM_EditCourseRow )
return ; // "Insert Entry"
2005-07-29 02:23:02 +00:00
switch ( iRow )
{
2005-08-01 05:12:06 +00:00
case EditCourseRow_Type :
row . SetOneSharedSelection ( pCourse -> GetCourseType () );
2006-02-20 06:18:57 +00:00
return ;
2005-08-01 05:12:06 +00:00
case EditCourseRow_Meter :
2006-02-20 02:46:22 +00:00
{
2006-02-20 06:18:57 +00:00
int iMeter = pCourse -> m_iCustomMeter [ GAMESTATE -> m_cdEdit ];
2006-02-20 02:46:22 +00:00
if ( iMeter == - 1 )
row . SetOneSharedSelection ( 0 );
else
row . SetOneSharedSelection ( iMeter + 1 - MIN_METER );
2006-02-20 06:18:57 +00:00
return ;
2005-07-29 02:23:02 +00:00
}
2006-02-20 02:46:22 +00:00
}
2006-02-20 06:18:57 +00:00
const CourseEntry & ce = pCourse -> m_vEntries [ iRow - NUM_EditCourseRow ];
2006-02-21 02:51:34 +00:00
if ( ! ce . IsFixedSong () )
2006-02-20 06:18:57 +00:00
{
row . SetOneSharedSelection ( 0 );
}
else
{
vector < Song *>:: const_iterator iter = find ( m_vpDisplayedSongs . begin (), m_vpDisplayedSongs . end (), ce . pSong );
2006-02-21 02:51:34 +00:00
if ( iter == m_vpDisplayedSongs . end () ) // This song isn't being displayed, set to "RANDOM"
2006-02-20 06:18:57 +00:00
row . SetOneSharedSelection ( 0 );
else
row . SetOneSharedSelection ( iter - m_vpDisplayedSongs . begin () + 1 );
}
2005-07-29 02:23:02 +00:00
}
void ScreenOptionsEditCourse :: ExportOptions ( int iRow , const vector < PlayerNumber > & vpns )
{
2005-08-01 05:12:06 +00:00
OptionRow & row = * m_pRows [ iRow ];
2006-02-20 04:25:53 +00:00
2006-02-21 02:51:34 +00:00
if ( row . GetRowType () == OptionRow :: RowType_Exit )
return ;
Course * pCourse = GAMESTATE -> m_pCurCourse ;
2006-02-21 12:37:58 +00:00
if ( iRow == ( int ) pCourse -> m_vEntries . size () + NUM_EditCourseRow )
return ; // "Insert Entry"
2006-02-21 02:51:34 +00:00
int iSel = row . GetOneSharedSelection ();
2005-08-01 05:12:06 +00:00
switch ( iRow )
{
case EditCourseRow_Type :
2006-02-20 02:46:22 +00:00
{
2006-02-21 02:51:34 +00:00
CourseType ct = ( CourseType ) iSel ;
2006-02-20 02:46:22 +00:00
pCourse -> SetCourseType ( ct );
2006-02-21 02:51:34 +00:00
return ;
2006-02-20 02:46:22 +00:00
}
2005-08-01 05:12:06 +00:00
case EditCourseRow_Meter :
2006-02-20 02:46:22 +00:00
{
if ( iSel == 0 ) // "auto"
2006-02-20 06:18:57 +00:00
pCourse -> m_iCustomMeter [ GAMESTATE -> m_cdEdit ] = - 1 ;
2006-02-20 02:46:22 +00:00
else
2006-02-20 06:18:57 +00:00
pCourse -> m_iCustomMeter [ GAMESTATE -> m_cdEdit ] = iSel - 1 + MIN_METER ;
2006-02-21 02:51:34 +00:00
return ;
2005-08-01 05:12:06 +00:00
}
2006-02-20 02:46:22 +00:00
}
2006-02-20 04:25:53 +00:00
2006-02-21 02:51:34 +00:00
CourseEntry & ce = pCourse -> m_vEntries [ iRow - NUM_EditCourseRow ];
if ( iSel == 0 )
ce . pSong = NULL ;
else
ce . pSong = m_vpDisplayedSongs [ iSel - 1 ];
2005-07-29 02:23:02 +00:00
}
2005-09-23 00:44:52 +00:00
void ScreenOptionsEditCourse :: ProcessMenuStart ( const InputEventPlus & input )
2005-07-29 02:23:02 +00:00
{
2006-02-18 03:02:21 +00:00
if ( IsTransitioning () )
return ;
2006-02-03 06:21:03 +00:00
int iCurRow = m_iCurrentRow [ GAMESTATE -> m_MasterPlayerNumber ];
2005-07-30 23:40:26 +00:00
Course * pCourse = GAMESTATE -> m_pCurCourse ;
2005-07-29 02:23:02 +00:00
2005-07-30 04:50:17 +00:00
if ( iCurRow < NUM_EditCourseRow )
2006-02-21 02:51:34 +00:00
return ;
if ( iCurRow == ( int ) m_pRows . size () - 2 ) // "create entry"
2005-07-30 04:50:17 +00:00
{
2005-12-21 09:56:16 +00:00
if ( AreEntriesFull () )
2005-07-30 23:40:26 +00:00
return ;
2005-08-03 03:28:13 +00:00
CourseEntry ce ;
CourseUtil :: MakeDefaultEditCourseEntry ( ce );
pCourse -> m_vEntries . push_back ( ce );
2005-07-30 23:40:26 +00:00
GAMESTATE -> m_iEditCourseEntryIndex . Set ( pCourse -> m_vEntries . size () - 1 );
2006-03-18 13:26:01 +00:00
SCREENMAN -> SetNewScreen ( this -> m_sName ); // reload
2005-07-30 04:50:17 +00:00
}
2005-08-01 05:12:06 +00:00
else if ( iCurRow == ( int ) m_pRows . size () - 1 ) // "done"
2005-07-30 04:50:17 +00:00
{
2006-01-30 05:41:46 +00:00
SCREENMAN -> PlayStartSound ();
2005-07-30 04:50:17 +00:00
this -> BeginFadingOut ();
}
else // a course entry
{
g_TempMenu . rows . clear ();
FOREACH_CourseEntryAction ( i )
2005-07-29 02:23:02 +00:00
{
2006-02-13 22:45:17 +00:00
MenuRowDef mrd ( i , CourseEntryActionToString ( i ), true , EditMode_Home , true , true , 0 , "" );
2005-07-30 04:50:17 +00:00
g_TempMenu . rows . push_back ( mrd );
2005-07-29 02:23:02 +00:00
}
2005-07-30 04:50:17 +00:00
int iWidth , iX , iY ;
2006-02-20 06:18:57 +00:00
this -> GetWidthXY ( GAMESTATE -> m_MasterPlayerNumber , iCurRow , 0 , iWidth , iX , iY );
2005-08-01 05:12:06 +00:00
ScreenMiniMenu :: MiniMenu ( & g_TempMenu , SM_BackFromContextMenu , SM_BackFromContextMenu , ( float ) iX , ( float ) iY );
2005-07-29 02:23:02 +00:00
}
}
2006-03-05 03:52:00 +00:00
void ScreenOptionsEditCourse :: HandleMessage ( const RString & sMessage )
{
if ( sMessage == "EditCourseDifficultyChanged" )
{
const vector < PlayerNumber > vpns ( 1 , GAMESTATE -> m_MasterPlayerNumber );
2006-03-10 22:29:05 +00:00
OptionRow & row = * m_pRows [ EditCourseRow_Meter ];
2006-03-05 03:52:00 +00:00
ImportOptions ( EditCourseRow_Meter , vpns );
2006-03-10 22:29:05 +00:00
row . AfterImportOptions ( GAMESTATE -> m_MasterPlayerNumber );
2006-03-05 03:52:00 +00:00
}
ScreenOptionsEditCourseSubMenu :: HandleMessage ( sMessage );
}
2005-07-29 02:23:02 +00:00
int ScreenOptionsEditCourse :: GetCourseEntryIndexWithFocus () const
{
int iCurRow = m_iCurrentRow [ GAMESTATE -> m_MasterPlayerNumber ];
if ( iCurRow < NUM_EditCourseRow ) // not a CourseEntry
return - 1 ;
2005-08-01 05:12:06 +00:00
else if ( iCurRow == ( int ) m_pRows . size () - 1 ) // "done"
2005-07-29 02:23:02 +00:00
return - 1 ;
else
return iCurRow - NUM_EditCourseRow ;
}
/*
2006-03-05 03:52:00 +00:00
* (c) 2002-2006 Chris Danford, Steve Checkoway
2005-07-29 02:23:02 +00:00
* 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.
*/