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 ()
{
ScreenOptions :: Init ();
2005-08-15 02:32:36 +00:00
}
2005-07-29 02:23:02 +00:00
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 ;
pHand -> m_Def . m_vsChoices . clear ();
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 ;
pHand -> m_Def . m_vsChoices . clear ();
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 ;
pHand -> m_Def . m_sName = ssprintf ( "Entry %d" , iEntryIndex + 1 );
pHand -> m_Def . m_vsChoices . clear ();
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 ;
pHand -> m_Def . m_bExportOnChange = true ;
pHand -> m_Def . m_vsChoices . clear ();
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-03 08:01:00 +00:00
this -> MoveRowAbsolute ( PLAYER_1 , 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
{
this -> HandleScreenMessage ( SM_GoToPrevScreen );
return ; // don't call base
}
}
2005-07-30 23:40:26 +00:00
else if ( SM == SM_GoToPrevScreen )
{
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 :
{
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 . insert ( pCourse -> m_vEntries . begin () + GetCourseEntryIndexWithFocus (), ce );
2005-07-30 04:50:17 +00:00
SCREENMAN -> SetNewScreen ( this -> m_sName ); // reload
}
break ;
case CourseEntryAction_Delete :
{
2005-08-01 05:12:06 +00:00
if ( pCourse -> m_vEntries . size () == 1 )
{
2005-12-21 09:56:16 +00:00
ScreenPrompt :: Prompt ( SM_None , CANNOT_DELETE_LAST_ENTRY );
2005-08-01 05:12:06 +00:00
return ;
}
2005-07-30 04:50:17 +00:00
pCourse -> m_vEntries . erase ( pCourse -> m_vEntries . begin () + GetCourseEntryIndexWithFocus () );
2005-07-30 23:40:26 +00:00
GAMESTATE -> m_iEditCourseEntryIndex . Set ( GAMESTATE -> m_iEditCourseEntryIndex );
2005-07-30 04:50:17 +00:00
SCREENMAN -> SetNewScreen ( this -> m_sName ); // reload
}
break ;
}
}
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 );
Course * pCourse = GAMESTATE -> m_pCurCourse ;
2006-01-19 07:59:59 +00:00
// Regenerate Trails so that the new values propagate
2005-08-01 05:12:06 +00:00
GAMESTATE -> m_pCurTrail [ PLAYER_1 ]. Set ( NULL );
Trail * pTrail = pCourse -> GetTrailForceRegenCache ( GAMESTATE -> m_stEdit , GAMESTATE -> m_PreferredCourseDifficulty [ PLAYER_1 ] );
// cause overlay elements to refresh by changing the course
GAMESTATE -> m_pCurCourse . Set ( pCourse );
GAMESTATE -> m_pCurTrail [ PLAYER_1 ]. Set ( pTrail );
}
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 ];
Course * pCourse = GAMESTATE -> m_pCurCourse ;
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 () );
2005-07-29 02:23:02 +00:00
break ;
2005-08-01 05:12:06 +00:00
case EditCourseRow_Meter :
{
int iMeter = pCourse -> m_iCustomMeter [ DIFFICULTY_MEDIUM ];
if ( iMeter == - 1 )
row . SetOneSharedSelection ( 0 );
else
row . SetOneSharedSelection ( iMeter + 1 - MIN_METER );
}
2005-07-29 02:23:02 +00:00
break ;
}
}
void ScreenOptionsEditCourse :: ExportOptions ( int iRow , const vector < PlayerNumber > & vpns )
{
2005-08-01 05:12:06 +00:00
OptionRow & row = * m_pRows [ iRow ];
Course * pCourse = GAMESTATE -> m_pCurCourse ;
2005-07-29 02:23:02 +00:00
2005-08-01 05:12:06 +00:00
switch ( iRow )
{
case EditCourseRow_Type :
{
CourseType ct = ( CourseType ) row . GetOneSharedSelection ();
pCourse -> SetCourseType ( ct );
}
break ;
case EditCourseRow_Meter :
{
int iSel = row . GetOneSharedSelection ();
if ( iSel == 0 ) // "auto"
pCourse -> m_iCustomMeter [ DIFFICULTY_MEDIUM ] = - 1 ;
else
pCourse -> m_iCustomMeter [ DIFFICULTY_MEDIUM ] = iSel - 1 + MIN_METER ;
}
break ;
}
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-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 )
2005-07-29 02:23:02 +00:00
{
2005-07-30 04:50:17 +00:00
// ignore
}
2005-08-01 05:12:06 +00:00
else 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 );
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 ;
this -> GetWidthXY ( PLAYER_1 , 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
}
}
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 ;
}
/*
* (c) 2002-2004 Chris Danford
* 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.
*/