2010-01-26 21:00:30 -06:00
#include "global.h"
#include <utility>
#include <float.h>
#include "ScreenEdit.h"
#include "ActorUtil.h"
#include "AdjustSync.h"
#include "BackgroundUtil.h"
#include "CommonMetrics.h"
#include "Foreach.h"
#include "GameManager.h"
#include "GamePreferences.h"
#include "GameSoundManager.h"
#include "GameState.h"
#include "InputEventPlus.h"
#include "InputMapper.h"
#include "LocalizedString.h"
#include "NoteDataUtil.h"
#include "NoteSkinManager.h"
2011-03-13 22:24:43 -04:00
#include "NoteTypes.h"
2010-01-26 21:00:30 -06:00
#include "NotesWriterSM.h"
#include "PrefsManager.h"
#include "RageSoundManager.h"
#include "RageInput.h"
#include "RageLog.h"
#include "ScreenDimensions.h"
#include "ScreenManager.h"
#include "ScreenMiniMenu.h"
#include "ScreenPrompt.h"
#include "ScreenSaveSync.h"
#include "ScreenTextEntry.h"
#include "SongManager.h"
#include "SongUtil.h"
#include "StepsUtil.h"
#include "Style.h"
#include "ThemeManager.h"
#include "ThemeMetric.h"
2011-01-09 17:06:40 -05:00
#include "TimingData.h"
2010-01-26 21:00:30 -06:00
#include "Game.h"
#include "RageSoundReader.h"
static Preference < float > g_iDefaultRecordLength ( "DefaultRecordLength" , 4 );
static Preference < bool > g_bEditorShowBGChangesPlay ( "EditorShowBGChangesPlay" , true );
// Defines specific to ScreenEdit
const float RECORD_HOLD_SECONDS = 0.3f ;
#define PLAYER_X (SCREEN_CENTER_X)
#define PLAYER_Y (SCREEN_CENTER_Y)
#define PLAYER_HEIGHT (360)
#define PLAYER_Y_STANDARD (PLAYER_Y-PLAYER_HEIGHT/2)
#define EDIT_X (SCREEN_CENTER_X)
#define EDIT_Y (PLAYER_Y)
#define RECORD_X (SCREEN_CENTER_X)
#define RECORD_Y (SCREEN_CENTER_Y)
#define PLAY_RECORD_HELP_TEXT THEME->GetString(m_sName,"PlayRecordHelpText")
#define EDIT_HELP_TEXT THEME->GetString(m_sName,"EditHelpText")
AutoScreenMessage ( SM_UpdateTextInfo );
AutoScreenMessage ( SM_BackFromMainMenu );
AutoScreenMessage ( SM_BackFromAreaMenu );
AutoScreenMessage ( SM_BackFromStepsInformation );
AutoScreenMessage ( SM_BackFromOptions );
AutoScreenMessage ( SM_BackFromSongInformation );
AutoScreenMessage ( SM_BackFromBGChange );
AutoScreenMessage ( SM_BackFromInsertTapAttack );
AutoScreenMessage ( SM_BackFromInsertTapAttackPlayerOptions );
AutoScreenMessage ( SM_BackFromInsertCourseAttack );
AutoScreenMessage ( SM_BackFromInsertCourseAttackPlayerOptions );
AutoScreenMessage ( SM_BackFromCourseModeMenu );
AutoScreenMessage ( SM_DoRevertToLastSave );
AutoScreenMessage ( SM_DoRevertFromDisk );
2011-01-18 00:49:03 -05:00
AutoScreenMessage ( SM_BackFromTimingDataInformation );
2010-01-26 21:00:30 -06:00
AutoScreenMessage ( SM_BackFromBPMChange );
AutoScreenMessage ( SM_BackFromStopChange );
AutoScreenMessage ( SM_BackFromDelayChange );
2011-01-16 13:22:55 -05:00
AutoScreenMessage ( SM_BackFromTimeSignatureNumeratorChange );
AutoScreenMessage ( SM_BackFromTimeSignatureDenominatorChange );
2011-01-18 11:49:27 -05:00
AutoScreenMessage ( SM_BackFromTickcountChange );
2011-03-05 01:44:58 -05:00
AutoScreenMessage ( SM_BackFromComboChange );
2010-01-26 21:00:30 -06:00
AutoScreenMessage ( SM_DoSaveAndExit );
AutoScreenMessage ( SM_DoExit );
AutoScreenMessage ( SM_SaveSuccessful );
AutoScreenMessage ( SM_SaveFailed );
static const char * EditStateNames [] = {
"Edit" ,
"Record" ,
"RecordPaused" ,
"Playing"
};
XToString ( EditState );
2010-12-26 00:31:46 -06:00
LuaXType ( EditState );
2010-01-26 21:00:30 -06:00
#if defined(XBOX)
void ScreenEdit :: InitEditMappings ()
{
/* XXX: fill this in */
m_EditMappingsDeviceInput . Clear ();
switch ( EDIT_MODE . GetValue () )
{
case EditMode_Practice :
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_PREV_MEASURE ][ 0 ] = DeviceInput ( DEVICE_JOY1 , JOY_HAT_UP );
m_EditMappingsMenuButton . button [ EDIT_BUTTON_SCROLL_PREV_MEASURE ][ 0 ] = GAME_BUTTON_UP ;
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_NEXT_MEASURE ][ 0 ] = DeviceInput ( DEVICE_JOY1 , JOY_HAT_DOWN );
m_EditMappingsMenuButton . button [ EDIT_BUTTON_SCROLL_NEXT_MEASURE ][ 0 ] = GAME_BUTTON_DOWN ;
break ;
default :
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_UP_LINE ][ 0 ] = DeviceInput ( DEVICE_JOY1 , JOY_HAT_UP );
m_EditMappingsMenuButton . button [ EDIT_BUTTON_SCROLL_UP_LINE ][ 0 ] = GAME_BUTTON_UP ;
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_DOWN_LINE ][ 0 ] = DeviceInput ( DEVICE_JOY1 , JOY_HAT_DOWN );
m_EditMappingsMenuButton . button [ EDIT_BUTTON_SCROLL_DOWN_LINE ][ 0 ] = GAME_BUTTON_DOWN ;
break ;
}
// Map these to the triggers: L goes up, R goes down.
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_UP_PAGE ][ 0 ] = DeviceInput ( DEVICE_JOY1 , JOY_BUTTON_7 );
//m_EditMappingsMenuButton.button[EDIT_BUTTON_SCROLL_UP_PAGE][0] = GAME_BUTTON_UPLEFT;
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_DOWN_PAGE ][ 0 ] = DeviceInput ( DEVICE_JOY1 , JOY_BUTTON_8 );
//m_EditMappingsMenuButton.button[EDIT_BUTTON_SCROLL_DOWN_PAGE][0] = GAME_BUTTON_UPRIGHT;
}
#else
void ScreenEdit :: InitEditMappings ()
{
m_EditMappingsDeviceInput . Clear ();
// Common mappings:
switch ( EDIT_MODE . GetValue () )
{
case EditMode_Practice :
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_PREV_MEASURE ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_UP );
m_EditMappingsMenuButton . button [ EDIT_BUTTON_SCROLL_PREV_MEASURE ][ 0 ] = GAME_BUTTON_UP ;
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_NEXT_MEASURE ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_DOWN );
m_EditMappingsMenuButton . button [ EDIT_BUTTON_SCROLL_NEXT_MEASURE ][ 0 ] = GAME_BUTTON_DOWN ;
break ;
default :
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_UP_LINE ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_UP );
m_EditMappingsMenuButton . button [ EDIT_BUTTON_SCROLL_UP_LINE ][ 0 ] = GAME_BUTTON_UP ;
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_DOWN_LINE ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_DOWN );
m_EditMappingsMenuButton . button [ EDIT_BUTTON_SCROLL_DOWN_LINE ][ 0 ] = GAME_BUTTON_DOWN ;
break ;
}
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_UP_PAGE ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_PGUP );
2011-01-09 13:52:41 -05:00
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_UP_PAGE ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_SEMICOLON );
2010-01-26 21:00:30 -06:00
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_DOWN_PAGE ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_PGDN );
2011-01-09 13:52:41 -05:00
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_DOWN_PAGE ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_SQUOTE );
2010-01-26 21:00:30 -06:00
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_HOME ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_HOME );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_END ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_END );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_NEXT ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_PERIOD );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_PREV ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_COMMA );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_SELECT ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LSHIFT );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_SELECT ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RSHIFT );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_LAY_SELECT ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_SPACE );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_PLAY_FROM_START ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cp );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_PLAY_FROM_START ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LCTRL );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_PLAY_FROM_START ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RCTRL );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_PLAY_FROM_CURSOR ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cp );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_PLAY_FROM_CURSOR ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LSHIFT );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_PLAY_FROM_CURSOR ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RSHIFT );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_PLAY_SELECTION ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cp );
// EditMode-specific mappings
switch ( EDIT_MODE . GetValue () )
{
case EditMode_Practice :
// Left = Zoom out (1x, 2x, 4x)
// Right = Zoom in
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_SPEED_DOWN ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LEFT );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_SPEED_UP ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RIGHT );
// F1 = Show help popup
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_OPEN_INPUT_HELP ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_F1 );
// Esc = Show Edit Menu
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_OPEN_EDIT_MENU ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_ESC );
m_EditMappingsMenuButton . button [ EDIT_BUTTON_OPEN_EDIT_MENU ][ 0 ] = GAME_BUTTON_START ;
m_EditMappingsMenuButton . button [ EDIT_BUTTON_OPEN_EDIT_MENU ][ 1 ] = GAME_BUTTON_BACK ;
// Escape, Enter = exit play/record
m_PlayMappingsDeviceInput . button [ EDIT_BUTTON_RETURN_TO_EDIT ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_ENTER );
m_PlayMappingsDeviceInput . button [ EDIT_BUTTON_RETURN_TO_EDIT ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_ESC );
m_PlayMappingsMenuButton . button [ EDIT_BUTTON_RETURN_TO_EDIT ][ 1 ] = GAME_BUTTON_BACK ;
return ;
case EditMode_CourseMods :
// Left/Right = Snap to Next/Prev
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SNAP_NEXT ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LEFT );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SNAP_PREV ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RIGHT );
2010-03-14 19:46:05 -05:00
2010-01-26 21:00:30 -06:00
// v = course attack menu
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_OPEN_COURSE_ATTACK_MENU ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cv );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_ADD_COURSE_MODS ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cm );
2010-03-14 19:46:05 -05:00
2010-01-26 21:00:30 -06:00
// F1 = Show help popup
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_OPEN_INPUT_HELP ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_F1 );
2010-03-14 19:46:05 -05:00
2010-01-26 21:00:30 -06:00
// Esc = Show Edit Menu
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_OPEN_EDIT_MENU ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_ESC );
m_EditMappingsMenuButton . button [ EDIT_BUTTON_OPEN_EDIT_MENU ][ 0 ] = GAME_BUTTON_START ;
m_EditMappingsMenuButton . button [ EDIT_BUTTON_OPEN_EDIT_MENU ][ 1 ] = GAME_BUTTON_BACK ;
2010-03-14 19:46:05 -05:00
2010-01-26 21:00:30 -06:00
// Escape, Enter = exit play/record
m_PlayMappingsDeviceInput . button [ EDIT_BUTTON_RETURN_TO_EDIT ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_ENTER );
m_PlayMappingsDeviceInput . button [ EDIT_BUTTON_RETURN_TO_EDIT ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_ESC );
m_PlayMappingsMenuButton . button [ EDIT_BUTTON_RETURN_TO_EDIT ][ 0 ] = GAME_BUTTON_START ;
return ;
2010-03-14 19:46:05 -05:00
2010-01-26 21:00:30 -06:00
case EditMode_Full :
2010-03-14 19:46:05 -05:00
/* Don't allow F5/F6 in home mode. It breaks the "delay creation until first save" logic. */
2010-01-26 21:00:30 -06:00
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_OPEN_PREV_STEPS ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_F5 );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_OPEN_NEXT_STEPS ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_F6 );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_BPM_DOWN ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_F7 );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_BPM_UP ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_F8 );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_STOP_DOWN ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_F9 );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_STOP_UP ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_F10 );
/*
m_EditMappingsDeviceInput.button[EDIT_BUTTON_DELAY_DOWN][0] = DeviceInput(DEVICE_KEYBOARD, KEY_F9);
m_EditMappingsDeviceInput.button[EDIT_BUTTON_DELAY_UP][0] = DeviceInput(DEVICE_KEYBOARD, KEY_F10);
*/
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_OFFSET_DOWN ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_F11 );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_OFFSET_UP ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_F12 );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SAMPLE_START_UP ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RBRACKET );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SAMPLE_START_DOWN ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LBRACKET );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SAMPLE_LENGTH_UP ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RBRACKET );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_SAMPLE_LENGTH_UP ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LSHIFT );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_SAMPLE_LENGTH_UP ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RSHIFT );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SAMPLE_LENGTH_DOWN ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LBRACKET );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_SAMPLE_LENGTH_DOWN ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LSHIFT );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_SAMPLE_LENGTH_DOWN ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RSHIFT );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_PLAY_SAMPLE_MUSIC ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cm );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_OPEN_BGCHANGE_LAYER1_MENU ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cb );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_OPEN_BGCHANGE_LAYER2_MENU ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cb );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_OPEN_BGCHANGE_LAYER2_MENU ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LSHIFT );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_OPEN_BGCHANGE_LAYER2_MENU ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RSHIFT );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_OPEN_COURSE_MENU ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cc );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_OPEN_COURSE_ATTACK_MENU ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cv );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_INSERT_SHIFT_PAUSES ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_INSERT );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_INSERT_SHIFT_PAUSES ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LCTRL );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_INSERT_SHIFT_PAUSES ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RCTRL );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_DELETE_SHIFT_PAUSES ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_DEL );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_DELETE_SHIFT_PAUSES ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LCTRL );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_DELETE_SHIFT_PAUSES ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RCTRL );
break ;
}
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_COLUMN_0 ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_C1 );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_COLUMN_1 ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_C2 );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_COLUMN_2 ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_C3 );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_COLUMN_3 ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_C4 );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_COLUMN_4 ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_C5 );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_COLUMN_5 ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_C6 );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_COLUMN_6 ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_C7 );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_COLUMN_7 ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_C8 );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_COLUMN_8 ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_C9 );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_COLUMN_9 ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_C0 );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_RIGHT_SIDE ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LALT );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_RIGHT_SIDE ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RALT );
2011-03-13 22:45:19 -04:00
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_LAY_ROLL ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LSHIFT );
2010-01-26 21:00:30 -06:00
// m_EditMappingsDeviceInput.button[EDIT_BUTTON_LAY_TAP_ATTACK][0] = DeviceInput(DEVICE_KEYBOARD, KEY_RSHIFT);
2011-03-13 20:03:54 -04:00
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_CYCLE_TAP_LEFT ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cn );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_CYCLE_TAP_RIGHT ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cm );
2010-01-26 21:00:30 -06:00
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_SPEED_UP ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_UP );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_SCROLL_SPEED_UP ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LCTRL );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_SCROLL_SPEED_UP ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RCTRL );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_SPEED_DOWN ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_DOWN );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_SCROLL_SPEED_DOWN ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LCTRL );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_SCROLL_SPEED_DOWN ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RCTRL );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_SELECT ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LSHIFT );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_SELECT ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RSHIFT );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SNAP_NEXT ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LEFT );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SNAP_PREV ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RIGHT );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_OPEN_EDIT_MENU ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_ESC );
m_EditMappingsMenuButton . button [ EDIT_BUTTON_OPEN_EDIT_MENU ][ 0 ] = GAME_BUTTON_START ;
m_EditMappingsMenuButton . button [ EDIT_BUTTON_OPEN_EDIT_MENU ][ 1 ] = GAME_BUTTON_BACK ;
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_OPEN_AREA_MENU ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_ENTER );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_OPEN_INPUT_HELP ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_F1 );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_BAKE_RANDOM_FROM_SONG_GROUP ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cb );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_BAKE_RANDOM_FROM_SONG_GROUP ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LALT );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_BAKE_RANDOM_FROM_SONG_GROUP ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RALT );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_BAKE_RANDOM_FROM_SONG_GROUP_AND_GENRE ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cb );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_BAKE_RANDOM_FROM_SONG_GROUP_AND_GENRE ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LCTRL );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_BAKE_RANDOM_FROM_SONG_GROUP_AND_GENRE ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RCTRL );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_RECORD_SELECTION ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cr );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_RECORD_SELECTION ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LCTRL );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_RECORD_SELECTION ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RCTRL );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_INSERT ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_INSERT );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_INSERT ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_BACKSLASH );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_DELETE ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_DEL );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_ADJUST_FINE ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RALT );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_ADJUST_FINE ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LALT );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SAVE ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cs );
#if defined(MACOSX)
/* use cmd */
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_SAVE ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LMETA );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_SAVE ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RMETA );
#else
/* use ctrl */
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_SAVE ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LCTRL );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_SAVE ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RCTRL );
#endif
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_UNDO ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cu );
// Switch players, if it makes sense to do so.
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SWITCH_PLAYERS ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_SLASH );
m_PlayMappingsDeviceInput . button [ EDIT_BUTTON_RETURN_TO_EDIT ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_ESC );
m_PlayMappingsMenuButton . button [ EDIT_BUTTON_RETURN_TO_EDIT ][ 1 ] = GAME_BUTTON_BACK ;
2011-03-13 22:45:19 -04:00
m_RecordMappingsDeviceInput . button [ EDIT_BUTTON_LAY_ROLL ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LSHIFT );
m_RecordMappingsDeviceInput . button [ EDIT_BUTTON_LAY_ROLL ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RSHIFT );
2010-01-26 21:00:30 -06:00
m_RecordMappingsDeviceInput . button [ EDIT_BUTTON_REMOVE_NOTE ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LALT );
m_RecordMappingsDeviceInput . button [ EDIT_BUTTON_REMOVE_NOTE ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RALT );
m_RecordMappingsDeviceInput . button [ EDIT_BUTTON_RETURN_TO_EDIT ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_ESC );
m_RecordMappingsMenuButton . button [ EDIT_BUTTON_RETURN_TO_EDIT ][ 1 ] = GAME_BUTTON_BACK ;
m_RecordPausedMappingsDeviceInput . button [ EDIT_BUTTON_PLAY_SELECTION ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cp );
m_RecordPausedMappingsDeviceInput . button [ EDIT_BUTTON_RECORD_SELECTION ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cr );
m_RecordPausedMappingsDeviceInput . hold [ EDIT_BUTTON_RECORD_SELECTION ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LCTRL );
m_RecordPausedMappingsDeviceInput . hold [ EDIT_BUTTON_RECORD_SELECTION ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RCTRL );
m_RecordPausedMappingsDeviceInput . button [ EDIT_BUTTON_RECORD_FROM_CURSOR ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cr );
m_RecordPausedMappingsDeviceInput . button [ EDIT_BUTTON_RETURN_TO_EDIT ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_ESC );
m_RecordPausedMappingsMenuButton . button [ EDIT_BUTTON_RETURN_TO_EDIT ][ 1 ] = GAME_BUTTON_BACK ;
m_RecordPausedMappingsDeviceInput . button [ EDIT_BUTTON_UNDO ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cu );
}
#endif
/* Given a DeviceInput that was just depressed, return an active edit function. */
EditButton ScreenEdit :: DeviceToEdit ( const DeviceInput & DeviceI ) const
{
ASSERT ( DeviceI . IsValid () );
const MapEditToDI * pCurrentMap = GetCurrentDeviceInputMap ();
/* First, search to see if a key that requires a modifier is pressed. */
FOREACH_EditButton ( e )
{
for ( int slot = 0 ; slot < NUM_EDIT_TO_DEVICE_SLOTS ; ++ slot )
{
if ( pCurrentMap -> button [ e ][ slot ] == DeviceI && pCurrentMap -> hold [ e ][ 0 ]. IsValid () )
{
/* The button maps to this function, and has one or more shift modifiers attached. */
for ( int holdslot = 0 ; holdslot < NUM_EDIT_TO_DEVICE_SLOTS ; ++ holdslot )
{
DeviceInput hDI = pCurrentMap -> hold [ e ][ holdslot ];
if ( hDI . IsValid () && INPUTFILTER -> IsBeingPressed ( hDI ) )
return e ;
}
}
}
}
/* No shifted keys matched. See if any unshifted inputs are bound to this key. */
FOREACH_EditButton ( e )
{
for ( int slot = 0 ; slot < NUM_EDIT_TO_DEVICE_SLOTS ; ++ slot )
{
if ( pCurrentMap -> button [ e ][ slot ] == DeviceI && ! pCurrentMap -> hold [ e ][ 0 ]. IsValid () )
{
/* The button maps to this function. */
return e ;
}
}
}
return EditButton_Invalid ;
}
/* Given a DeviceInput that was just depressed, return an active edit function. */
EditButton ScreenEdit :: MenuButtonToEditButton ( GameButton MenuI ) const
{
const MapEditButtonToMenuButton * pCurrentMap = GetCurrentMenuButtonMap ();
FOREACH_EditButton ( e )
{
for ( int slot = 0 ; slot < NUM_EDIT_TO_MENU_SLOTS ; ++ slot )
{
if ( pCurrentMap -> button [ e ][ slot ] == MenuI )
{
/* The button maps to this function. */
return e ;
}
}
}
return EditButton_Invalid ;
}
/* If DeviceI was just pressed, return true if button is triggered. (More than one
* function may be mapped to a key.) */
bool ScreenEdit :: EditPressed ( EditButton button , const DeviceInput & DeviceI )
{
ASSERT ( DeviceI . IsValid () );
const MapEditToDI * pCurrentMap = GetCurrentDeviceInputMap ();
/* First, search to see if a key that requires a modifier is pressed. */
bool bPrimaryButtonPressed = false ;
for ( int slot = 0 ; slot < NUM_EDIT_TO_DEVICE_SLOTS ; ++ slot )
{
if ( pCurrentMap -> button [ button ][ slot ] == DeviceI )
bPrimaryButtonPressed = true ;
}
if ( ! bPrimaryButtonPressed )
return false ;
/* The button maps to this function. Does the function has one or more shift modifiers attached? */
if ( ! pCurrentMap -> hold [ button ][ 0 ]. IsValid () )
return true ;
for ( int holdslot = 0 ; holdslot < NUM_EDIT_TO_DEVICE_SLOTS ; ++ holdslot )
{
DeviceInput hDI = pCurrentMap -> hold [ button ][ holdslot ];
if ( INPUTFILTER -> IsBeingPressed ( hDI ) )
return true ;
}
/* No shifted keys matched. */
return false ;
}
bool ScreenEdit :: EditToDevice ( EditButton button , int iSlotNum , DeviceInput & DeviceI ) const
{
ASSERT ( iSlotNum < NUM_EDIT_TO_DEVICE_SLOTS );
const MapEditToDI * pCurrentMap = GetCurrentDeviceInputMap ();
if ( pCurrentMap -> button [ button ][ iSlotNum ]. IsValid () )
DeviceI = pCurrentMap -> button [ button ][ iSlotNum ];
else if ( pCurrentMap -> hold [ button ][ iSlotNum ]. IsValid () )
DeviceI = pCurrentMap -> hold [ button ][ iSlotNum ];
return DeviceI . IsValid ();
}
bool ScreenEdit :: EditIsBeingPressed ( EditButton button ) const
{
for ( int slot = 0 ; slot < NUM_EDIT_TO_DEVICE_SLOTS ; ++ slot )
{
DeviceInput DeviceI ;
if ( EditToDevice ( button , slot , DeviceI ) && INPUTFILTER -> IsBeingPressed ( DeviceI ) )
return true ;
}
return false ;
}
const MapEditToDI * ScreenEdit :: GetCurrentDeviceInputMap () const
{
switch ( m_EditState )
{
DEFAULT_FAIL ( m_EditState );
case STATE_EDITING : return & m_EditMappingsDeviceInput ;
case STATE_PLAYING : return & m_PlayMappingsDeviceInput ;
case STATE_RECORDING : return & m_RecordMappingsDeviceInput ;
case STATE_RECORDING_PAUSED : return & m_RecordPausedMappingsDeviceInput ;
}
}
const MapEditButtonToMenuButton * ScreenEdit :: GetCurrentMenuButtonMap () const
{
switch ( m_EditState )
{
DEFAULT_FAIL ( m_EditState );
case STATE_EDITING : return & m_EditMappingsMenuButton ;
case STATE_PLAYING : return & m_PlayMappingsMenuButton ;
case STATE_RECORDING : return & m_RecordMappingsMenuButton ;
case STATE_RECORDING_PAUSED : return & m_RecordPausedMappingsMenuButton ;
}
}
static MenuDef g_EditHelp (
"ScreenMiniMenuEditHelp"
// fill this in dynamically
);
static MenuDef g_MainMenu (
"ScreenMiniMenuMainMenu" ,
2010-06-02 22:05:39 -05:00
MenuRowDef ( ScreenEdit :: play_whole_song , "Play whole song" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: play_current_beat_to_end , "Play current beat to end" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: save , "Save" , true , EditMode_Home , true , true , 0 , NULL ),
2010-01-26 21:00:30 -06:00
MenuRowDef ( ScreenEdit :: play_selection , "Play selection" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: set_selection_start , "Set selection start" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: set_selection_end , "Set selection end" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: edit_steps_information , "Edit steps information" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: revert_to_last_save , "Revert to last save" , true , EditMode_Home , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: revert_from_disk , "Revert from disk" , true , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: options , "Editor options" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: edit_song_info , "Edit song info" , true , EditMode_Full , true , true , 0 , NULL ),
2011-01-18 00:49:03 -05:00
MenuRowDef ( ScreenEdit :: edit_timing_data , "Edit Timing Data" , true , EditMode_Full , true , true , 0 , NULL ),
2010-01-26 21:00:30 -06:00
MenuRowDef ( ScreenEdit :: play_preview_music , "Play preview music" , true , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: exit , "Exit Edit Mode" , true , EditMode_Practice , true , true , 0 , NULL )
);
static MenuDef g_AreaMenu (
"ScreenMiniMenuAreaMenu" ,
MenuRowDef ( ScreenEdit :: cut , "Cut" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: copy , "Copy" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: paste_at_current_beat , "Paste at current beat" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: paste_at_begin_marker , "Paste at begin marker" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: clear , "Clear area" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: quantize , "Quantize" , true , EditMode_Practice , true , true , 0 , "4th" , "8th" , "12th" , "16th" , "24th" , "32nd" , "48th" , "64th" , "192nd" ),
MenuRowDef ( ScreenEdit :: turn , "Turn" , true , EditMode_Practice , true , true , 0 , "Left" , "Right" , "Mirror" , "Shuffle" , "SuperShuffle" ),
MenuRowDef ( ScreenEdit :: transform , "Transform" , true , EditMode_Practice , true , true , 0 , "NoHolds" , "NoMines" , "Little" , "Wide" , "Big" , "Quick" , "Skippy" , "Mines" , "Echo" , "Stomp" , "Planted" , "Floored" , "Twister" , "NoJumps" , "NoHands" , "NoQuads" , "NoStretch" ),
MenuRowDef ( ScreenEdit :: alter , "Alter" , true , EditMode_Practice , true , true , 0 , "Autogen To Fill Width" , "Backwards" , "Swap Sides" , "Copy Left To Right" , "Copy Right To Left" , "Clear Left" , "Clear Right" , "Collapse To One" , "Collapse Left" , "Shift Left" , "Shift Right" ),
MenuRowDef ( ScreenEdit :: tempo , "Tempo" , true , EditMode_Full , true , true , 0 , "Compress 2x" , "Compress 3->2" , "Compress 4->3" , "Expand 3->4" , "Expand 2->3" , "Expand 2x" ),
MenuRowDef ( ScreenEdit :: play , "Play selection" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: record , "Record in selection" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: insert_and_shift , "Insert beat and shift down" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: delete_and_shift , "Delete beat and shift up" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: shift_pauses_forward , "Shift pauses and BPM changes down" , true , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: shift_pauses_backward , "Shift pauses and BPM changes up" , true , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: convert_to_pause , "Convert selection to pause" , true , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: convert_pause_to_beat , "Convert pause to beats" , true , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: undo , "Undo" , true , EditMode_Practice , true , true , 0 , NULL )
);
static MenuDef g_StepsInformation (
"ScreenMiniMenuStepsInformation" ,
MenuRowDef ( ScreenEdit :: difficulty , "Difficulty" , true , EditMode_Practice , true , true , 0 , NULL ),
2010-07-03 22:06:37 -05:00
// xxx: this giant list of numbers SUUUUUUUUUUCKS -aj
MenuRowDef ( ScreenEdit :: meter , "Meter" , true , EditMode_Practice , true , false , 0 , "1" , "2" , "3" , "4" , "5" , "6" , "7" , "8" , "9" , "10" , "11" , "12" , "13" , "14" , "15" , "16" , "17" , "18" , "19" , "20" , "21" , "22" , "23" , "24" , "25" ),
2010-01-26 21:00:30 -06:00
MenuRowDef ( ScreenEdit :: description , "Description" , true , EditMode_Practice , true , true , 0 , NULL ),
2011-02-14 23:05:52 -06:00
MenuRowDef ( ScreenEdit :: chartstyle , "Chart Style" , true , EditMode_Practice , true , true , 0 , NULL ),
2011-02-11 01:51:01 -05:00
MenuRowDef ( ScreenEdit :: step_credit , "Step Author" , true , EditMode_Practice , true , true , 0 , NULL ),
2010-01-26 21:00:30 -06:00
MenuRowDef ( ScreenEdit :: predict_meter , "Predicted Meter" , false , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: tap_notes , "Tap Steps" , false , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: jumps , "Jumps" , false , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: hands , "Hands" , false , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: quads , "Quads" , false , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: holds , "Holds" , false , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: mines , "Mines" , false , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: stream , "Stream" , false , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: voltage , "Voltage" , false , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: air , "Air" , false , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: freeze , "Freeze" , false , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: chaos , "Chaos" , false , EditMode_Full , true , true , 0 , NULL )
);
static MenuDef g_SongInformation (
"ScreenMiniMenuSongInformation" ,
MenuRowDef ( ScreenEdit :: main_title , "Main title" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: sub_title , "Sub title" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: artist , "Artist" , true , EditMode_Practice , true , true , 0 , NULL ),
2010-07-27 21:53:40 -05:00
MenuRowDef ( ScreenEdit :: genre , "Genre" , true , EditMode_Practice , true , true , 0 , NULL ),
2010-01-26 21:00:30 -06:00
MenuRowDef ( ScreenEdit :: credit , "Credit" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: main_title_transliteration , "Main title transliteration" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: sub_title_transliteration , "Sub title transliteration" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: artist_transliteration , "Artist transliteration" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: last_beat_hint , "Last beat hint" , true , EditMode_Full , true , true , 0 , NULL )
);
2011-01-18 00:49:03 -05:00
static MenuDef g_TimingDataInformation (
"ScreenMiniMenuTimingDataInformation" ,
MenuRowDef ( ScreenEdit :: bpm , "Edit BPM change" , true , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: stop , "Edit stop" , true , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: delay , "Edit delay" , true , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: time_signature_numerator , "Edit time signature (top)" , true , EditMode_Full , true , true , 0 , NULL ),
2011-01-18 11:49:27 -05:00
MenuRowDef ( ScreenEdit :: time_signature_denominator , "Edit time signature (bottom)" , true , EditMode_Full , true , true , 0 , NULL ),
2011-03-05 01:44:58 -05:00
MenuRowDef ( ScreenEdit :: tickcount , "Edit tickcount" , true , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: combo , "Edit combo" , true , EditMode_Full , true , true , 0 , NULL )
2011-01-18 00:49:03 -05:00
);
2010-01-26 21:00:30 -06:00
enum { song_bganimation , song_movie , song_bitmap , global_bganimation , global_movie , global_movie_song_group , global_movie_song_group_and_genre , dynamic_random , baked_random , none };
static bool EnabledIfSet1SongBGAnimation ();
static bool EnabledIfSet1SongMovie ();
static bool EnabledIfSet1SongBitmap ();
static bool EnabledIfSet1GlobalBGAnimation ();
static bool EnabledIfSet1GlobalMovie ();
static bool EnabledIfSet1GlobalMovieSongGroup ();
static bool EnabledIfSet1GlobalMovieSongGroupAndGenre ();
static bool EnabledIfSet2SongBGAnimation ();
static bool EnabledIfSet2SongMovie ();
static bool EnabledIfSet2SongBitmap ();
static bool EnabledIfSet2GlobalBGAnimation ();
static bool EnabledIfSet2GlobalMovie ();
static bool EnabledIfSet2GlobalMovieSongGroup ();
static bool EnabledIfSet2GlobalMovieSongGroupAndGenre ();
static MenuDef g_BackgroundChange (
"ScreenMiniMenuBackgroundChange" ,
MenuRowDef ( ScreenEdit :: layer , "Layer" , false , EditMode_Full , true , false , 0 , "" ),
MenuRowDef ( ScreenEdit :: rate , "Rate" , true , EditMode_Full , true , false , 10 , "0%" , "10%" , "20%" , "30%" , "40%" , "50%" , "60%" , "70%" , "80%" , "90%" , "100%" , "120%" , "140%" , "160%" , "180%" , "200%" , "220%" , "240%" , "260%" , "280%" , "300%" , "350%" , "400%" ),
MenuRowDef ( ScreenEdit :: transition , "Force Transition" , true , EditMode_Full , true , false , 0 , NULL ),
MenuRowDef ( ScreenEdit :: effect , "Force Effect" , true , EditMode_Full , true , false , 0 , NULL ),
2010-06-12 14:37:20 -05:00
MenuRowDef ( ScreenEdit :: color1 , "Force Color 1" , true , EditMode_Full , true , false , 0 , "-" , "#FFFFFF" , "#808080" , "#FFFFFF80" , "#000000" , "#FF0000" , "#00FF00" , "#0000FF" , "#FFFF00" , "#00FFFF" , "#FF00FF" ),
MenuRowDef ( ScreenEdit :: color2 , "Force Color 2" , true , EditMode_Full , true , false , 0 , "-" , "#FFFFFF" , "#808080" , "#FFFFFF80" , "#000000" , "#FF0000" , "#00FF00" , "#0000FF" , "#FFFF00" , "#00FFFF" , "#FF00FF" ),
2010-01-26 21:00:30 -06:00
MenuRowDef ( ScreenEdit :: file1_type , "File1 Type" , true , EditMode_Full , true , true , 0 , "Song BGAnimation" , "Song Movie" , "Song Bitmap" , "Global BGAnimation" , "Global Movie" , "Global Movie from Song Group" , "Global Movie from Song Group and Genre" , "Dynamic Random" , "Baked Random" , "None" ),
MenuRowDef ( ScreenEdit :: file1_song_bganimation , "File1 Song BGAnimation" , EnabledIfSet1SongBGAnimation , EditMode_Full , true , false , 0 , NULL ),
MenuRowDef ( ScreenEdit :: file1_song_movie , "File1 Song Movie" , EnabledIfSet1SongMovie , EditMode_Full , true , false , 0 , NULL ),
MenuRowDef ( ScreenEdit :: file1_song_still , "File1 Song Still" , EnabledIfSet1SongBitmap , EditMode_Full , true , false , 0 , NULL ),
MenuRowDef ( ScreenEdit :: file1_global_bganimation , "File1 Global BGAnimation" , EnabledIfSet1GlobalBGAnimation , EditMode_Full , true , false , 0 , NULL ),
MenuRowDef ( ScreenEdit :: file1_global_movie , "File1 Global Movie" , EnabledIfSet1GlobalMovie , EditMode_Full , true , false , 0 , NULL ),
MenuRowDef ( ScreenEdit :: file1_global_movie_song_group , "File1 Global Movie (Group)" , EnabledIfSet1GlobalMovieSongGroup , EditMode_Full , true , false , 0 , NULL ),
MenuRowDef ( ScreenEdit :: file1_global_movie_song_group_and_genre , "File1 Global Movie (Group + Genre)" , EnabledIfSet1GlobalMovieSongGroupAndGenre , EditMode_Full , true , false , 0 , NULL ),
MenuRowDef ( ScreenEdit :: file2_type , "File2 Type" , true , EditMode_Full , true , true , 0 , "Song BGAnimation" , "Song Movie" , "Song Bitmap" , "Global BGAnimation" , "Global Movie" , "Global Movie from Song Group" , "Global Movie from Song Group and Genre" , "Dynamic Random" , "Baked Random" , "None" ),
MenuRowDef ( ScreenEdit :: file2_song_bganimation , "File2 Song BGAnimation" , EnabledIfSet2SongBGAnimation , EditMode_Full , true , false , 0 , NULL ),
MenuRowDef ( ScreenEdit :: file2_song_movie , "File2 Song Movie" , EnabledIfSet2SongMovie , EditMode_Full , true , false , 0 , NULL ),
MenuRowDef ( ScreenEdit :: file2_song_still , "File2 Song Still" , EnabledIfSet2SongBitmap , EditMode_Full , true , false , 0 , NULL ),
MenuRowDef ( ScreenEdit :: file2_global_bganimation , "File2 Global BGAnimation" , EnabledIfSet2GlobalBGAnimation , EditMode_Full , true , false , 0 , NULL ),
MenuRowDef ( ScreenEdit :: file2_global_movie , "File2 Global Movie" , EnabledIfSet2GlobalMovie , EditMode_Full , true , false , 0 , NULL ),
MenuRowDef ( ScreenEdit :: file2_global_movie_song_group , "File2 Global Movie (Group)" , EnabledIfSet2GlobalMovieSongGroup , EditMode_Full , true , false , 0 , NULL ),
MenuRowDef ( ScreenEdit :: file2_global_movie_song_group_and_genre , "File2 Global Movie (Group + Genre)" , EnabledIfSet2GlobalMovieSongGroupAndGenre , EditMode_Full , true , false , 0 , NULL ),
MenuRowDef ( ScreenEdit :: delete_change , "Remove Change" , true , EditMode_Full , true , true , 0 , NULL )
);
static bool EnabledIfSet1SongBGAnimation () { return ScreenMiniMenu :: s_viLastAnswers [ ScreenEdit :: file1_type ] == song_bganimation && ! g_BackgroundChange . rows [ ScreenEdit :: file1_song_bganimation ]. choices . empty (); }
static bool EnabledIfSet1SongMovie () { return ScreenMiniMenu :: s_viLastAnswers [ ScreenEdit :: file1_type ] == song_movie && ! g_BackgroundChange . rows [ ScreenEdit :: file1_song_movie ]. choices . empty (); }
static bool EnabledIfSet1SongBitmap () { return ScreenMiniMenu :: s_viLastAnswers [ ScreenEdit :: file1_type ] == song_bitmap && ! g_BackgroundChange . rows [ ScreenEdit :: file1_song_still ]. choices . empty (); }
static bool EnabledIfSet1GlobalBGAnimation () { return ScreenMiniMenu :: s_viLastAnswers [ ScreenEdit :: file1_type ] == global_bganimation && ! g_BackgroundChange . rows [ ScreenEdit :: file1_global_bganimation ]. choices . empty (); }
static bool EnabledIfSet1GlobalMovie () { return ScreenMiniMenu :: s_viLastAnswers [ ScreenEdit :: file1_type ] == global_movie && ! g_BackgroundChange . rows [ ScreenEdit :: file1_global_movie ]. choices . empty (); }
static bool EnabledIfSet1GlobalMovieSongGroup () { return ScreenMiniMenu :: s_viLastAnswers [ ScreenEdit :: file1_type ] == global_movie_song_group && ! g_BackgroundChange . rows [ ScreenEdit :: file1_global_movie_song_group ]. choices . empty (); }
static bool EnabledIfSet1GlobalMovieSongGroupAndGenre () { return ScreenMiniMenu :: s_viLastAnswers [ ScreenEdit :: file1_type ] == global_movie_song_group_and_genre && ! g_BackgroundChange . rows [ ScreenEdit :: file1_global_movie_song_group_and_genre ]. choices . empty (); }
static bool EnabledIfSet2SongBGAnimation () { return ScreenMiniMenu :: s_viLastAnswers [ ScreenEdit :: file2_type ] == song_bganimation && ! g_BackgroundChange . rows [ ScreenEdit :: file2_song_bganimation ]. choices . empty (); }
static bool EnabledIfSet2SongMovie () { return ScreenMiniMenu :: s_viLastAnswers [ ScreenEdit :: file2_type ] == song_movie && ! g_BackgroundChange . rows [ ScreenEdit :: file2_song_movie ]. choices . empty (); }
static bool EnabledIfSet2SongBitmap () { return ScreenMiniMenu :: s_viLastAnswers [ ScreenEdit :: file2_type ] == song_bitmap && ! g_BackgroundChange . rows [ ScreenEdit :: file2_song_still ]. choices . empty (); }
static bool EnabledIfSet2GlobalBGAnimation () { return ScreenMiniMenu :: s_viLastAnswers [ ScreenEdit :: file2_type ] == global_bganimation && ! g_BackgroundChange . rows [ ScreenEdit :: file2_global_bganimation ]. choices . empty (); }
static bool EnabledIfSet2GlobalMovie () { return ScreenMiniMenu :: s_viLastAnswers [ ScreenEdit :: file2_type ] == global_movie && ! g_BackgroundChange . rows [ ScreenEdit :: file2_global_movie ]. choices . empty (); }
static bool EnabledIfSet2GlobalMovieSongGroup () { return ScreenMiniMenu :: s_viLastAnswers [ ScreenEdit :: file2_type ] == global_movie_song_group && ! g_BackgroundChange . rows [ ScreenEdit :: file2_global_movie_song_group ]. choices . empty (); }
static bool EnabledIfSet2GlobalMovieSongGroupAndGenre () { return ScreenMiniMenu :: s_viLastAnswers [ ScreenEdit :: file2_type ] == global_movie_song_group_and_genre && ! g_BackgroundChange . rows [ ScreenEdit :: file2_global_movie_song_group_and_genre ]. choices . empty (); }
static RString GetOneBakedRandomFile ( Song * pSong , bool bTryGenre = true )
{
vector < RString > vsPathsOut ;
vector < RString > vsNamesOut ;
BackgroundUtil :: GetGlobalRandomMovies (
pSong ,
"" ,
vsPathsOut ,
vsNamesOut ,
bTryGenre );
if ( ! vsNamesOut . empty () )
return vsNamesOut [ RandomInt ( vsNamesOut . size ())];
else
return RString ();
}
static MenuDef g_InsertTapAttack (
"ScreenMiniMenuInsertTapAttack" ,
MenuRowDef ( - 1 , "Duration seconds" , true , EditMode_Practice , true , false , 3 , "5" , "10" , "15" , "20" , "25" , "30" , "35" , "40" , "45" ),
MenuRowDef ( - 1 , "Set modifiers" , true , EditMode_Practice , true , true , 0 , "Press Start" )
);
static MenuDef g_InsertCourseAttack (
"ScreenMiniMenuInsertCourseAttack" ,
MenuRowDef ( ScreenEdit :: duration , "Duration seconds" , true , EditMode_Practice , true , false , 3 , "5" , "10" , "15" , "20" , "25" , "30" , "35" , "40" , "45" ),
MenuRowDef ( ScreenEdit :: set_mods , "Set modifiers" , true , EditMode_Practice , true , true , 0 , "Press Start" ),
MenuRowDef ( ScreenEdit :: remove , "Remove" , true , EditMode_Practice , true , true , 0 , "Press Start" )
);
static MenuDef g_CourseMode (
"ScreenMiniMenuCourseDisplay" ,
MenuRowDef ( - 1 , "Play mods from course" , true , EditMode_Practice , true , false , 0 , NULL )
);
2010-08-22 12:35:19 -05:00
// HACK: need to remember the track we're inserting on so that we can lay the
// attack note after coming back from menus.
2010-01-26 21:00:30 -06:00
static int g_iLastInsertTapAttackTrack = - 1 ;
static float g_fLastInsertAttackDurationSeconds = - 1 ;
static float g_fLastInsertAttackPositionSeconds = - 1 ;
static BackgroundLayer g_CurrentBGChangeLayer = BACKGROUND_LAYER_Invalid ;
static void SetDefaultEditorNoteSkin ( size_t num , RString & sNameOut , RString & defaultValueOut )
{
sNameOut = ssprintf ( "EditorNoteSkinP%d" , int ( num + 1 ) );
2010-08-22 12:35:19 -05:00
// XXX: We need more supported noteskins.
2010-01-26 21:00:30 -06:00
switch ( num )
{
case 0 : defaultValueOut = "default" ; return ;
case 1 : defaultValueOut = "default" ; return ;
}
defaultValueOut = "default" ;
}
static Preference1D < RString > EDITOR_NOTE_SKINS ( SetDefaultEditorNoteSkin , NUM_PLAYERS );
static ThemeMetric < RString > EDIT_MODIFIERS ( "ScreenEdit" , "EditModifiers" );
REGISTER_SCREEN_CLASS ( ScreenEdit );
void ScreenEdit :: Init ()
{
m_pSoundMusic = NULL ;
SubscribeToMessage ( "Judgment" );
ASSERT ( GAMESTATE -> m_pCurSong );
ASSERT ( GAMESTATE -> m_pCurSteps [ PLAYER_1 ] );
EDIT_MODE . Load ( m_sName , "EditMode" );
ScreenWithMenuElements :: Init ();
InitEditMappings ();
// save the originals for reverting later
CopyToLastSave ();
m_CurrentAction = MAIN_MENU_CHOICE_INVALID ;
2010-02-14 23:02:34 -06:00
if ( GAMESTATE -> GetCurrentStyle () -> m_StyleType == StyleType_TwoPlayersSharedSides )
2010-01-26 21:00:30 -06:00
m_InputPlayerNumber = PLAYER_1 ;
else
m_InputPlayerNumber = PLAYER_INVALID ;
FOREACH_PlayerNumber ( p )
GAMESTATE -> m_bSideIsJoined [ p ] = false ;
GAMESTATE -> m_bSideIsJoined [ PLAYER_1 ] = true ;
m_pSong = GAMESTATE -> m_pCurSong ;
m_pSteps = GAMESTATE -> m_pCurSteps [ PLAYER_1 ];
m_bReturnToRecordMenuAfterPlay = false ;
m_fBeatToReturnTo = 0 ;
2011-03-13 22:24:43 -04:00
m_selectedTap = TAP_ORIGINAL_TAP ;
2010-01-26 21:00:30 -06:00
GAMESTATE -> m_bGameplayLeadIn . Set ( true );
GAMESTATE -> m_EditMode = EDIT_MODE . GetValue ();
GAMESTATE -> m_fSongBeat = 0 ;
m_fTrailingBeat = GAMESTATE -> m_fSongBeat ;
m_iShiftAnchor = - 1 ;
m_iStartPlayingAt = - 1 ;
m_iStopPlayingAt = - 1 ;
this -> AddChild ( & m_Background );
m_SnapDisplay . SetXY ( EDIT_X , PLAYER_Y_STANDARD );
2011-03-04 22:48:40 -06:00
m_SnapDisplay . Load ();
2011-03-02 14:41:59 -06:00
// xxx: hardcoded command -aj
2010-01-26 21:00:30 -06:00
m_SnapDisplay . SetZoom ( 0.5f );
this -> AddChild ( & m_SnapDisplay );
// We keep track of this bit of state so that when the user is in Edit/Sync Songs and makes a change to the NoteSkins,
// that change is "sticky" across multiple ScreenEdits. That is the way the rest of the options work.
// TODO: It would be cleaner to do this by making it possible to set an option in metrics.ini.
if ( ! GAMESTATE -> m_bDidModeChangeNoteSkin )
{
GAMESTATE -> m_bDidModeChangeNoteSkin = true ;
FOREACH_PlayerNumber ( pn )
{
const RString & sNoteSkin = EDITOR_NOTE_SKINS [ pn ]. Get ();
if ( NOTESKIN -> DoesNoteSkinExist ( sNoteSkin ) )
PO_GROUP_ASSIGN ( GAMESTATE -> m_pPlayerState [ pn ] -> m_PlayerOptions ,
ModsLevel_Preferred , m_sNoteSkin , sNoteSkin );
}
}
m_PlayerStateEdit . m_PlayerNumber = PLAYER_1 ;
// If we always go with the GAMESTATE NoteSkin, we will have fun effects like Vivid or Flat in the editor notefield.
// This is not conducive to productive editing.
if ( NOTESKIN -> DoesNoteSkinExist ( EDITOR_NOTE_SKINS [ PLAYER_1 ]. Get () ) )
{
PO_GROUP_ASSIGN ( m_PlayerStateEdit . m_PlayerOptions , ModsLevel_Stage , m_sNoteSkin , EDITOR_NOTE_SKINS [ PLAYER_1 ]. Get () );
}
else
{
PO_GROUP_ASSIGN ( m_PlayerStateEdit . m_PlayerOptions , ModsLevel_Stage , m_sNoteSkin , GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_PlayerOptions . GetStage (). m_sNoteSkin );
}
m_PlayerStateEdit . m_PlayerOptions . FromString ( ModsLevel_Stage , EDIT_MODIFIERS );
m_pSteps -> GetNoteData ( m_NoteDataEdit );
m_NoteFieldEdit . SetXY ( EDIT_X , EDIT_Y );
m_NoteFieldEdit . SetZoom ( 0.5f );
m_NoteFieldEdit . Init ( & m_PlayerStateEdit , PLAYER_HEIGHT * 2 );
m_NoteFieldEdit . Load ( & m_NoteDataEdit , - 240 , 850 );
this -> AddChild ( & m_NoteFieldEdit );
m_NoteDataRecord . SetNumTracks ( m_NoteDataEdit . GetNumTracks () );
m_NoteFieldRecord . SetXY ( RECORD_X , RECORD_Y );
m_NoteFieldRecord . Init ( GAMESTATE -> m_pPlayerState [ PLAYER_1 ], PLAYER_HEIGHT );
m_NoteFieldRecord . Load ( & m_NoteDataRecord , - ( int ) SCREEN_HEIGHT / 2 , ( int ) SCREEN_HEIGHT / 2 );
this -> AddChild ( & m_NoteFieldRecord );
m_EditState = EditState_Invalid ;
TransitionEditState ( STATE_EDITING );
2010-08-04 11:17:46 -05:00
2010-01-26 21:00:30 -06:00
m_bRemoveNoteButtonDown = false ;
m_Clipboard . SetNumTracks ( m_NoteDataEdit . GetNumTracks () );
m_bHasUndo = false ;
m_Undo . SetNumTracks ( m_NoteDataEdit . GetNumTracks () );
2011-03-16 23:31:06 -04:00
m_bDirty = m_NoteDataEdit . IsEmpty (); // require the usage of saving if empty.
2010-01-26 21:00:30 -06:00
m_Player -> Init ( "Player" , GAMESTATE -> m_pPlayerState [ PLAYER_1 ], NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL );
m_Player -> CacheAllUsedNoteSkins ();
GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_PlayerController = PC_HUMAN ;
m_Player -> SetXY ( PLAYER_X , PLAYER_Y );
this -> AddChild ( m_Player );
this -> AddChild ( & m_Foreground );
m_textInputTips . SetName ( "EditHelp" );
m_textInputTips . LoadFromFont ( THEME -> GetPathF ( "ScreenEdit" , "EditHelp" ) );
m_textInputTips . SetText ( EDIT_HELP_TEXT );
LOAD_ALL_COMMANDS_AND_SET_XY_AND_ON_COMMAND ( m_textInputTips );
this -> AddChild ( & m_textInputTips );
m_textInfo . SetName ( "Info" );
m_textInfo . LoadFromFont ( THEME -> GetPathF ( "ScreenEdit" , "Info" ) );
LOAD_ALL_COMMANDS_AND_SET_XY_AND_ON_COMMAND ( m_textInfo );
this -> AddChild ( & m_textInfo );
m_textPlayRecordHelp . SetName ( "PlayRecordHelp" );
m_textPlayRecordHelp . LoadFromFont ( THEME -> GetPathF ( "ScreenEdit" , "PlayRecordHelp" ) );
m_textPlayRecordHelp . SetText ( PLAY_RECORD_HELP_TEXT );
LOAD_ALL_COMMANDS_AND_SET_XY_AND_ON_COMMAND ( m_textPlayRecordHelp );
this -> AddChild ( & m_textPlayRecordHelp );
m_soundAddNote . Load ( THEME -> GetPathS ( "ScreenEdit" , "AddNote" ), true );
m_soundRemoveNote . Load ( THEME -> GetPathS ( "ScreenEdit" , "RemoveNote" ), true );
m_soundChangeLine . Load ( THEME -> GetPathS ( "ScreenEdit" , "line" ), true );
m_soundChangeSnap . Load ( THEME -> GetPathS ( "ScreenEdit" , "snap" ), true );
m_soundMarker . Load ( THEME -> GetPathS ( "ScreenEdit" , "marker" ), true );
m_soundValueIncrease . Load ( THEME -> GetPathS ( "ScreenEdit" , "value increase" ), true );
m_soundValueDecrease . Load ( THEME -> GetPathS ( "ScreenEdit" , "value decrease" ), true );
m_soundSwitchSteps . Load ( THEME -> GetPathS ( "ScreenEdit" , "switch steps" ) );
m_soundSave . Load ( THEME -> GetPathS ( "ScreenEdit" , "save" ) );
m_GameplayAssist . Init ();
m_AutoKeysounds . FinishLoading ();
m_pSoundMusic = m_AutoKeysounds . GetSound ();
this -> HandleScreenMessage ( SM_UpdateTextInfo );
m_bTextInfoNeedsUpdate = true ;
SubscribeToMessage ( Message_SongModified );
}
ScreenEdit ::~ ScreenEdit ()
{
// UGLY: Don't delete the Song's steps.
m_SongLastSave . DetachSteps ();
LOG -> Trace ( "ScreenEdit::~ScreenEdit()" );
m_pSoundMusic -> StopPlaying ();
}
void ScreenEdit :: BeginScreen ()
{
ScreenWithMenuElements :: BeginScreen ();
/* We do this ourself. */
SOUND -> HandleSongTimer ( false );
}
void ScreenEdit :: EndScreen ()
{
ScreenWithMenuElements :: EndScreen ();
SOUND -> HandleSongTimer ( true );
}
// play assist ticks
void ScreenEdit :: PlayTicks ()
{
if ( m_EditState != STATE_PLAYING )
return ;
m_GameplayAssist . PlayTicks ( m_Player -> GetNoteData () );
}
void ScreenEdit :: PlayPreviewMusic ()
{
SOUND -> StopMusic ();
SOUND -> PlayMusic (
m_pSong -> GetMusicPath (),
NULL ,
false ,
m_pSong -> m_fMusicSampleStartSeconds ,
m_pSong -> m_fMusicSampleLengthSeconds ,
0.0f ,
1.5f );
}
void ScreenEdit :: MakeFilteredMenuDef ( const MenuDef * pDef , MenuDef & menu )
{
menu = * pDef ;
menu . rows . clear ();
vector < MenuRowDef > aRows ;
FOREACH_CONST ( MenuRowDef , pDef -> rows , r )
{
// Don't add rows that aren't applicable to this edit mode.
if ( EDIT_MODE >= r -> emShowIn )
menu . rows . push_back ( * r );
}
}
void ScreenEdit :: EditMiniMenu ( const MenuDef * pDef , ScreenMessage SM_SendOnOK , ScreenMessage SM_SendOnCancel )
{
2010-03-01 00:44:39 -06:00
// Reload options.
2010-01-26 21:00:30 -06:00
MenuDef menu ( "" );
MakeFilteredMenuDef ( pDef , menu );
ScreenMiniMenu :: MiniMenu ( & menu , SM_SendOnOK , SM_SendOnCancel );
}
void ScreenEdit :: Update ( float fDeltaTime )
{
m_PlayerStateEdit . Update ( fDeltaTime );
if ( m_pSoundMusic -> IsPlaying () )
{
RageTimer tm ;
const float fSeconds = m_pSoundMusic -> GetPositionSeconds ( NULL , & tm );
GAMESTATE -> UpdateSongPosition ( fSeconds , GAMESTATE -> m_pCurSong -> m_Timing , tm );
}
if ( m_EditState == STATE_RECORDING )
{
for ( int t = 0 ; t < GAMESTATE -> GetCurrentStyle () -> m_iColsPerPlayer ; t ++ ) // for each track
{
GameInput GameI = GAMESTATE -> GetCurrentStyle () -> StyleInputToGameInput ( t , PLAYER_1 );
float fSecsHeld = INPUTMAPPER -> GetSecsHeld ( GameI );
fSecsHeld = min ( fSecsHeld , m_RemoveNoteButtonLastChanged . Ago () );
if ( fSecsHeld == 0 )
continue ;
float fStartPlayingAtBeat = NoteRowToBeat ( m_iStartPlayingAt );
if ( GAMESTATE -> m_fSongBeat <= fStartPlayingAtBeat )
continue ;
float fStartedHoldingSeconds = m_pSoundMusic -> GetPositionSeconds () - fSecsHeld ;
float fStartBeat = max ( fStartPlayingAtBeat , m_pSong -> GetBeatFromElapsedTime ( fStartedHoldingSeconds ) );
float fEndBeat = max ( fStartBeat , GAMESTATE -> m_fSongBeat );
fEndBeat = min ( fEndBeat , NoteRowToBeat ( m_iStopPlayingAt ) );
// Round start and end to the nearest snap interval
fStartBeat = Quantize ( fStartBeat , NoteTypeToBeat ( m_SnapDisplay . GetNoteType ()) );
fEndBeat = Quantize ( fEndBeat , NoteTypeToBeat ( m_SnapDisplay . GetNoteType ()) );
if ( m_bRemoveNoteButtonDown )
{
m_NoteDataRecord . ClearRangeForTrack ( BeatToNoteRow ( fStartBeat ), BeatToNoteRow ( fEndBeat ), t );
}
else if ( fSecsHeld > RECORD_HOLD_SECONDS )
{
// create or extend a hold or roll note
2011-03-13 22:45:19 -04:00
TapNote tn = EditIsBeingPressed ( EDIT_BUTTON_LAY_ROLL ) ? TAP_ORIGINAL_ROLL_HEAD : TAP_ORIGINAL_HOLD_HEAD ;
2010-01-26 21:00:30 -06:00
tn . pn = m_InputPlayerNumber ;
m_NoteDataRecord . AddHoldNote ( t , BeatToNoteRow ( fStartBeat ), BeatToNoteRow ( fEndBeat ), tn );
}
}
}
//
// check for end of playback/record
//
if ( m_EditState == STATE_RECORDING || m_EditState == STATE_PLAYING )
{
/*
* If any arrow is being held, continue for up to half a second after
* the end marker. This makes it possible to start a hold note near
* the end of the range. We won't allow placing anything outside of the
* range.
*/
bool bButtonIsBeingPressed = false ;
for ( int t = 0 ; t < GAMESTATE -> GetCurrentStyle () -> m_iColsPerPlayer ; t ++ ) // for each track
{
GameInput GameI = GAMESTATE -> GetCurrentStyle () -> StyleInputToGameInput ( t , PLAYER_1 );
if ( INPUTMAPPER -> IsBeingPressed ( GameI ) )
bButtonIsBeingPressed = true ;
}
float fLastBeat = NoteRowToBeat ( m_iStopPlayingAt );
if ( bButtonIsBeingPressed && m_EditState == STATE_RECORDING )
{
float fSeconds = m_pSong -> m_Timing . GetElapsedTimeFromBeat ( fLastBeat );
fLastBeat = m_pSong -> m_Timing . GetBeatFromElapsedTime ( fSeconds + 0.5f );
}
float fStopAtSeconds = m_pSong -> m_Timing . GetElapsedTimeFromBeat ( NoteRowToBeat ( m_iStopPlayingAt ) ) + 1 ;
if ( GAMESTATE -> m_fMusicSeconds > fStopAtSeconds )
{
// loop
TransitionEditState ( STATE_PLAYING );
}
}
//LOG->Trace( "ScreenEdit::Update(%f)", fDeltaTime );
ScreenWithMenuElements :: Update ( fDeltaTime );
// Update trailing beat
float fDelta = GAMESTATE -> m_fSongBeat - m_fTrailingBeat ;
if ( fabsf ( fDelta ) < 10 )
fapproach ( m_fTrailingBeat , GAMESTATE -> m_fSongBeat ,
fDeltaTime * 40 / m_NoteFieldEdit . GetPlayerState () -> m_PlayerOptions . GetCurrent (). m_fScrollSpeed );
else
fapproach ( m_fTrailingBeat , GAMESTATE -> m_fSongBeat ,
fabsf ( fDelta ) * fDeltaTime * 5 );
PlayTicks ();
}
static LocalizedString CURRENT_BEAT ( "ScreenEdit" , "Current beat" );
static LocalizedString CURRENT_SECOND ( "ScreenEdit" , "Current second" );
static LocalizedString SNAP_TO ( "ScreenEdit" , "Snap to" );
static LocalizedString NOTES ( "ScreenEdit" , "%s notes" );
static LocalizedString SELECTION_BEAT ( "ScreenEdit" , "Selection beat" );
static LocalizedString DIFFICULTY ( "ScreenEdit" , "Difficulty" );
2011-02-22 00:08:28 -05:00
static LocalizedString ROUTINE_PLAYER ( "ScreenEdit" , "Routine Player" );
2010-01-26 21:00:30 -06:00
static LocalizedString DESCRIPTION ( "ScreenEdit" , "Description" );
2011-02-14 23:05:52 -06:00
static LocalizedString CHART_STYLE ( "ScreenEdit" , "Chart Style" );
2010-01-26 21:00:30 -06:00
static LocalizedString MAIN_TITLE ( "ScreenEdit" , "Main title" );
static LocalizedString SUBTITLE ( "ScreenEdit" , "Subtitle" );
2011-03-13 22:24:43 -04:00
static LocalizedString TAP_NOTE_TYPE ( "ScreenEdit" , "Tap Note" );
2010-01-26 21:00:30 -06:00
static LocalizedString TAP_STEPS ( "ScreenEdit" , "Tap Steps" );
static LocalizedString JUMPS ( "ScreenEdit" , "Jumps" );
static LocalizedString HANDS ( "ScreenEdit" , "Hands" );
static LocalizedString HOLDS ( "ScreenEdit" , "Holds" );
static LocalizedString MINES ( "ScreenEdit" , "Mines" );
static LocalizedString ROLLS ( "ScreenEdit" , "Rolls" );
2011-02-27 22:50:26 -05:00
static LocalizedString LIFTS ( "ScreenEdit" , "Lifts" );
static LocalizedString FAKES ( "ScreenEdit" , "Fakes" );
2010-01-26 21:00:30 -06:00
static LocalizedString BEAT_0_OFFSET ( "ScreenEdit" , "Beat 0 offset" );
static LocalizedString PREVIEW_START ( "ScreenEdit" , "Preview Start" );
static LocalizedString PREVIEW_LENGTH ( "ScreenEdit" , "Preview Length" );
2011-02-22 00:32:21 -05:00
static ThemeMetric < RString > CURRENT_BEAT_FORMAT ( "ScreenEdit" , "CurrentBeatFormat" );
static ThemeMetric < RString > CURRENT_SECOND_FORMAT ( "ScreenEdit" , "CurrentSecondFormat" );
static ThemeMetric < RString > SNAP_TO_FORMAT ( "ScreenEdit" , "SnapToFormat" );
static ThemeMetric < RString > SELECTION_BEAT_BEGIN_FORMAT ( "ScreenEdit" , "SelectionBeatBeginFormat" );
static ThemeMetric < RString > SELECTION_BEAT_UNFINISHED_FORMAT ( "ScreenEdit" , "SelectionBeatUnfinishedFormat" );
static ThemeMetric < RString > SELECTION_BEAT_END_FORMAT ( "ScreenEdit" , "SelectionBeatEndFormat" );
static ThemeMetric < RString > DIFFICULTY_FORMAT ( "ScreenEdit" , "DifficultyFormat" );
static ThemeMetric < RString > ROUTINE_PLAYER_FORMAT ( "ScreenEdit" , "RoutinePlayerFormat" );
static ThemeMetric < RString > DESCRIPTION_FORMAT ( "ScreenEdit" , "DescriptionFormat" );
static ThemeMetric < RString > CHART_STYLE_FORMAT ( "ScreenEdit" , "ChartStyleFormat" );
static ThemeMetric < RString > MAIN_TITLE_FORMAT ( "ScreenEdit" , "MainTitleFormat" );
static ThemeMetric < RString > SUBTITLE_FORMAT ( "ScreenEdit" , "SubtitleFormat" );
2011-03-13 22:24:43 -04:00
static ThemeMetric < RString > TAP_NOTE_TYPE_FORMAT ( "ScreenEdit" , "TapNoteTypeFormat" );
2011-02-22 00:32:21 -05:00
static ThemeMetric < RString > NUM_STEPS_FORMAT ( "ScreenEdit" , "NumStepsFormat" );
static ThemeMetric < RString > NUM_JUMPS_FORMAT ( "ScreenEdit" , "NumJumpsFormat" );
static ThemeMetric < RString > NUM_HOLDS_FORMAT ( "ScreenEdit" , "NumHoldsFormat" );
static ThemeMetric < RString > NUM_MINES_FORMAT ( "ScreenEdit" , "NumMinesFormat" );
static ThemeMetric < RString > NUM_HANDS_FORMAT ( "ScreenEdit" , "NumHandsFormat" );
static ThemeMetric < RString > NUM_ROLLS_FORMAT ( "ScreenEdit" , "NumRollsFormat" );
2011-02-27 22:50:26 -05:00
static ThemeMetric < RString > NUM_LIFTS_FORMAT ( "ScreenEdit" , "NumLiftsFormat" );
static ThemeMetric < RString > NUM_FAKES_FORMAT ( "ScreenEdit" , "NumFakesFormat" );
2011-02-22 00:32:21 -05:00
static ThemeMetric < RString > BEAT_0_OFFSET_FORMAT ( "ScreenEdit" , "Beat0OffsetFormat" );
static ThemeMetric < RString > PREVIEW_START_FORMAT ( "ScreenEdit" , "PreviewStartFormat" );
static ThemeMetric < RString > PREVIEW_LENGTH_FORMAT ( "ScreenEdit" , "PreviewLengthFormat" );
2010-01-26 21:00:30 -06:00
void ScreenEdit :: UpdateTextInfo ()
{
if ( m_pSteps == NULL )
return ;
// Don't update the text during playback or record. It causes skips.
if ( m_EditState != STATE_EDITING )
return ;
if ( ! m_bTextInfoNeedsUpdate )
return ;
m_bTextInfoNeedsUpdate = false ;
RString sNoteType = ssprintf ( NOTES . GetValue (), NoteTypeToLocalizedString ( m_SnapDisplay . GetNoteType ()). c_str () );
RString sText ;
2011-02-22 00:32:21 -05:00
sText += ssprintf ( CURRENT_BEAT_FORMAT . GetValue (), CURRENT_BEAT . GetValue (). c_str (), GAMESTATE -> m_fSongBeat );
sText += ssprintf ( CURRENT_SECOND_FORMAT . GetValue (), CURRENT_SECOND . GetValue (). c_str (), m_pSong -> GetElapsedTimeFromBeat ( GAMESTATE -> m_fSongBeat ) );
2010-01-26 21:00:30 -06:00
switch ( EDIT_MODE . GetValue () )
{
DEFAULT_FAIL ( EDIT_MODE . GetValue () );
case EditMode_Practice :
break ;
case EditMode_CourseMods :
case EditMode_Home :
case EditMode_Full :
2011-02-22 00:32:21 -05:00
sText += ssprintf ( SNAP_TO_FORMAT . GetValue (), SNAP_TO . GetValue (). c_str (), sNoteType . c_str () );
2010-01-26 21:00:30 -06:00
break ;
}
if ( m_NoteFieldEdit . m_iBeginMarker != - 1 )
{
2011-02-22 00:32:21 -05:00
sText += ssprintf ( SELECTION_BEAT_BEGIN_FORMAT . GetValue (), SELECTION_BEAT . GetValue (). c_str (), NoteRowToBeat ( m_NoteFieldEdit . m_iBeginMarker ) );
2010-01-26 21:00:30 -06:00
if ( m_NoteFieldEdit . m_iEndMarker != - 1 )
2011-02-22 00:32:21 -05:00
sText += ssprintf ( SELECTION_BEAT_END_FORMAT . GetValue (), NoteRowToBeat ( m_NoteFieldEdit . m_iEndMarker ) );
2010-01-26 21:00:30 -06:00
else
2011-02-22 00:32:21 -05:00
sText += SELECTION_BEAT_UNFINISHED_FORMAT ;
2010-01-26 21:00:30 -06:00
}
switch ( EDIT_MODE . GetValue () )
{
DEFAULT_FAIL ( EDIT_MODE . GetValue () );
case EditMode_Practice :
case EditMode_CourseMods :
case EditMode_Home :
break ;
case EditMode_Full :
2011-02-22 00:32:21 -05:00
sText += ssprintf ( DIFFICULTY_FORMAT . GetValue (), DIFFICULTY . GetValue (). c_str (), DifficultyToString ( m_pSteps -> GetDifficulty () ). c_str () );
2011-02-22 00:08:28 -05:00
if ( m_InputPlayerNumber != PLAYER_INVALID )
2011-02-22 00:32:21 -05:00
sText += ssprintf ( ROUTINE_PLAYER_FORMAT . GetValue (), ROUTINE_PLAYER . GetValue (). c_str (), m_InputPlayerNumber + 1 );
sText += ssprintf ( DESCRIPTION_FORMAT . GetValue (), DESCRIPTION . GetValue (). c_str (), m_pSteps -> GetDescription (). c_str () );
sText += ssprintf ( CHART_STYLE_FORMAT . GetValue (), CHART_STYLE . GetValue (). c_str (), m_pSteps -> GetChartStyle (). c_str () );
sText += ssprintf ( MAIN_TITLE_FORMAT . GetValue (), MAIN_TITLE . GetValue (). c_str (), m_pSong -> m_sMainTitle . c_str () );
2010-01-26 21:00:30 -06:00
if ( m_pSong -> m_sSubTitle . size () )
2011-02-22 00:32:21 -05:00
sText += ssprintf ( SUBTITLE_FORMAT . GetValue (), SUBTITLE . GetValue (). c_str (), m_pSong -> m_sSubTitle . c_str () );
2011-03-13 22:24:43 -04:00
sText += ssprintf ( TAP_NOTE_TYPE_FORMAT . GetValue (), TAP_NOTE_TYPE . GetValue (). c_str (), TapNoteTypeToString ( m_selectedTap . type ). c_str () );
2010-01-26 21:00:30 -06:00
break ;
}
2011-02-22 00:32:21 -05:00
sText += ssprintf ( NUM_STEPS_FORMAT . GetValue (), TAP_STEPS . GetValue (). c_str (), m_NoteDataEdit . GetNumTapNotes () );
sText += ssprintf ( NUM_JUMPS_FORMAT . GetValue (), JUMPS . GetValue (). c_str (), m_NoteDataEdit . GetNumJumps () );
sText += ssprintf ( NUM_HANDS_FORMAT . GetValue (), HANDS . GetValue (). c_str (), m_NoteDataEdit . GetNumHands () );
sText += ssprintf ( NUM_HOLDS_FORMAT . GetValue (), HOLDS . GetValue (). c_str (), m_NoteDataEdit . GetNumHoldNotes () );
sText += ssprintf ( NUM_MINES_FORMAT . GetValue (), MINES . GetValue (). c_str (), m_NoteDataEdit . GetNumMines () );
sText += ssprintf ( NUM_ROLLS_FORMAT . GetValue (), ROLLS . GetValue (). c_str (), m_NoteDataEdit . GetNumRolls () );
2011-02-27 22:50:26 -05:00
sText += ssprintf ( NUM_LIFTS_FORMAT . GetValue (), LIFTS . GetValue (). c_str (), m_NoteDataEdit . GetNumLifts () );
sText += ssprintf ( NUM_FAKES_FORMAT . GetValue (), FAKES . GetValue (). c_str (), m_NoteDataEdit . GetNumFakes () );
2010-01-26 21:00:30 -06:00
switch ( EDIT_MODE . GetValue () )
{
DEFAULT_FAIL ( EDIT_MODE . GetValue () );
case EditMode_Practice :
case EditMode_CourseMods :
case EditMode_Home :
break ;
case EditMode_Full :
2011-02-22 00:32:21 -05:00
sText += ssprintf ( BEAT_0_OFFSET_FORMAT . GetValue (), BEAT_0_OFFSET . GetValue (). c_str (), m_pSong -> m_Timing . m_fBeat0OffsetInSeconds );
sText += ssprintf ( PREVIEW_START_FORMAT . GetValue (), PREVIEW_START . GetValue (). c_str (), m_pSong -> m_fMusicSampleStartSeconds );
sText += ssprintf ( PREVIEW_LENGTH_FORMAT . GetValue (), PREVIEW_LENGTH . GetValue (). c_str (), m_pSong -> m_fMusicSampleLengthSeconds );
2010-01-26 21:00:30 -06:00
break ;
}
m_textInfo . SetText ( sText );
}
void ScreenEdit :: DrawPrimitives ()
{
// HACK: Draw using the trailing beat
float fSongBeat = GAMESTATE -> m_fSongBeat ; // save song beat
float fSongBeatNoOffset = GAMESTATE -> m_fSongBeatNoOffset ;
float fSongBeatVisible = GAMESTATE -> m_fSongBeatVisible ;
if ( ! m_pSoundMusic -> IsPlaying () )
{
GAMESTATE -> m_fSongBeat = m_fTrailingBeat ; // put trailing beat in effect
GAMESTATE -> m_fSongBeatNoOffset = m_fTrailingBeat ; // put trailing beat in effect
GAMESTATE -> m_fSongBeatVisible = m_fTrailingBeat ; // put trailing beat in effect
}
ScreenWithMenuElements :: DrawPrimitives ();
if ( ! m_pSoundMusic -> IsPlaying () )
{
GAMESTATE -> m_fSongBeat = fSongBeat ; // restore real song beat
GAMESTATE -> m_fSongBeatNoOffset = fSongBeatNoOffset ;
GAMESTATE -> m_fSongBeatVisible = fSongBeatVisible ;
}
}
void ScreenEdit :: Input ( const InputEventPlus & input )
{
// LOG->Trace( "ScreenEdit::Input()" );
// invalidate input if cmd/meta is being held.
if ( INPUTFILTER -> IsBeingPressed ( DeviceInput ( DEVICE_KEYBOARD , KEY_LMETA )) ||
INPUTFILTER -> IsBeingPressed ( DeviceInput ( DEVICE_KEYBOARD , KEY_RMETA )) )
return ;
if ( m_In . IsTransitioning () || m_Out . IsTransitioning () )
return ;
EditButton EditB = DeviceToEdit ( input . DeviceI );
if ( EditB == EditButton_Invalid )
EditB = MenuButtonToEditButton ( input . MenuI );
if ( EditB == EDIT_BUTTON_REMOVE_NOTE )
{
/* Ugly: we need to know when the button was pressed or released, so we
* can clamp operations to that time. Should InputFilter keep track of
* last release, too? */
m_bRemoveNoteButtonDown = ( input . type != IET_RELEASE );
m_RemoveNoteButtonLastChanged . Touch ();
}
switch ( m_EditState )
{
DEFAULT_FAIL ( m_EditState );
case STATE_EDITING :
InputEdit ( input , EditB );
m_bTextInfoNeedsUpdate = true ;
break ;
case STATE_RECORDING :
InputRecord ( input , EditB );
break ;
case STATE_RECORDING_PAUSED :
InputRecordPaused ( input , EditB );
break ;
case STATE_PLAYING :
InputPlay ( input , EditB );
break ;
}
}
static void ShiftToRightSide ( int & iCol , int iNumTracks )
{
switch ( GAMESTATE -> GetCurrentStyle () -> m_StyleType )
{
DEFAULT_FAIL ( GAMESTATE -> GetCurrentStyle () -> m_StyleType );
case StyleType_OnePlayerOneSide :
break ;
case StyleType_TwoPlayersTwoSides :
case StyleType_OnePlayerTwoSides :
case StyleType_TwoPlayersSharedSides :
iCol += iNumTracks / 2 ;
break ;
}
}
static int FindAttackAtTime ( const AttackArray & attacks , float fStartTime )
{
for ( unsigned i = 0 ; i < attacks . size (); ++ i )
{
if ( fabs ( attacks [ i ]. fStartSecond - fStartTime ) < 0.001f )
return i ;
}
return - 1 ;
}
static LocalizedString SWITCHED_TO ( "ScreenEdit" , "Switched to" );
static LocalizedString NO_BACKGROUNDS_AVAILABLE ( "ScreenEdit" , "No backgrounds available" );
void ScreenEdit :: InputEdit ( const InputEventPlus & input , EditButton EditB )
{
if ( input . type == IET_RELEASE )
{
if ( EditPressed ( EDIT_BUTTON_SCROLL_SELECT , input . DeviceI ) )
m_iShiftAnchor = - 1 ;
return ;
}
2011-01-09 17:06:40 -05:00
int beatsPerMeasure = GAMESTATE -> m_pCurSong -> m_Timing . GetTimeSignatureSegmentAtBeat ( GAMESTATE -> m_fSongBeat ). m_iNumerator ;
2010-01-26 21:00:30 -06:00
switch ( EditB )
{
case EDIT_BUTTON_COLUMN_0 :
case EDIT_BUTTON_COLUMN_1 :
case EDIT_BUTTON_COLUMN_2 :
case EDIT_BUTTON_COLUMN_3 :
case EDIT_BUTTON_COLUMN_4 :
case EDIT_BUTTON_COLUMN_5 :
case EDIT_BUTTON_COLUMN_6 :
case EDIT_BUTTON_COLUMN_7 :
case EDIT_BUTTON_COLUMN_8 :
case EDIT_BUTTON_COLUMN_9 :
{
if ( input . type != IET_FIRST_PRESS )
break ; // We only care about first presses
int iCol = EditB - EDIT_BUTTON_COLUMN_0 ;
// Alt + number = input to right half
if ( EditIsBeingPressed ( EDIT_BUTTON_RIGHT_SIDE ) )
ShiftToRightSide ( iCol , m_NoteDataEdit . GetNumTracks () );
const float fSongBeat = GAMESTATE -> m_fSongBeat ;
const int iSongIndex = BeatToNoteRow ( fSongBeat );
if ( iCol >= m_NoteDataEdit . GetNumTracks () ) // this button is not in the range of columns for this Style
break ;
// check for to see if the user intended to remove a HoldNote
int iHeadRow ;
if ( m_NoteDataEdit . IsHoldNoteAtRow ( iCol , iSongIndex , & iHeadRow ) )
{
m_soundRemoveNote . Play ();
SetDirty ( true );
SaveUndo ();
m_NoteDataEdit . SetTapNote ( iCol , iHeadRow , TAP_EMPTY );
// Don't CheckNumberOfNotesAndUndo. We don't want to revert any change that removes notes.
}
else if ( m_NoteDataEdit . GetTapNote ( iCol , iSongIndex ). type != TapNote :: empty )
{
m_soundRemoveNote . Play ();
SetDirty ( true );
SaveUndo ();
m_NoteDataEdit . SetTapNote ( iCol , iSongIndex , TAP_EMPTY );
// Don't CheckNumberOfNotesAndUndo. We don't want to revert any change that removes notes.
}
else if ( EditIsBeingPressed ( EDIT_BUTTON_LAY_TAP_ATTACK ) )
{
g_iLastInsertTapAttackTrack = iCol ;
EditMiniMenu ( & g_InsertTapAttack , SM_BackFromInsertTapAttack );
}
else
{
m_soundAddNote . Play ();
SetDirty ( true );
SaveUndo ();
2011-03-13 22:24:43 -04:00
TapNote tn = m_selectedTap ;
2010-01-26 21:00:30 -06:00
tn . pn = m_InputPlayerNumber ;
m_NoteDataEdit . SetTapNote ( iCol , iSongIndex , tn );
CheckNumberOfNotesAndUndo ();
}
}
break ;
2011-03-13 22:24:43 -04:00
case EDIT_BUTTON_CYCLE_TAP_LEFT :
{
switch ( m_selectedTap . type )
{
case TapNote :: tap : m_selectedTap = TAP_ORIGINAL_FAKE ; break ;
case TapNote :: mine : m_selectedTap = TAP_ORIGINAL_TAP ; break ;
case TapNote :: lift : m_selectedTap = TAP_ORIGINAL_MINE ; break ;
case TapNote :: fake : m_selectedTap = TAP_ORIGINAL_LIFT ; break ;
DEFAULT_FAIL ( m_selectedTap . type );
}
break ;
}
case EDIT_BUTTON_CYCLE_TAP_RIGHT :
{
switch ( m_selectedTap . type )
{
case TapNote :: tap : m_selectedTap = TAP_ORIGINAL_MINE ; break ;
case TapNote :: mine : m_selectedTap = TAP_ORIGINAL_LIFT ; break ;
case TapNote :: lift : m_selectedTap = TAP_ORIGINAL_FAKE ; break ;
case TapNote :: fake : m_selectedTap = TAP_ORIGINAL_TAP ; break ;
DEFAULT_FAIL ( m_selectedTap . type );
}
break ;
}
2010-01-26 21:00:30 -06:00
case EDIT_BUTTON_SCROLL_SPEED_UP :
case EDIT_BUTTON_SCROLL_SPEED_DOWN :
{
PlayerState * pPlayerState = const_cast < PlayerState *> ( m_NoteFieldEdit . GetPlayerState ());
float fScrollSpeed = pPlayerState -> m_PlayerOptions . GetSong (). m_fScrollSpeed ;
const float fSpeeds [] = { 1.0f , 1.5f , 2.0f , 3.0f , 4.0f , 6.0f , 8.0f };
int iSpeed = 0 ;
for ( unsigned i = 0 ; i < ARRAYLEN ( fSpeeds ); ++ i )
{
if ( fSpeeds [ i ] == fScrollSpeed )
{
iSpeed = i ;
break ;
}
}
switch ( EditB )
{
DEFAULT_FAIL ( EditB );
case EDIT_BUTTON_SCROLL_SPEED_DOWN :
-- iSpeed ;
break ;
case EDIT_BUTTON_SCROLL_SPEED_UP :
++ iSpeed ;
break ;
}
iSpeed = clamp ( iSpeed , 0 , ( int ) ARRAYLEN ( fSpeeds ) - 1 );
2011-03-13 00:17:36 -06:00
2010-01-26 21:00:30 -06:00
if ( fSpeeds [ iSpeed ] != fScrollSpeed )
{
m_soundMarker . Play ();
fScrollSpeed = fSpeeds [ iSpeed ];
}
PO_GROUP_ASSIGN ( pPlayerState -> m_PlayerOptions , ModsLevel_Song , m_fScrollSpeed , fScrollSpeed );
break ;
}
break ;
case EDIT_BUTTON_SCROLL_HOME :
ScrollTo ( 0 );
break ;
case EDIT_BUTTON_SCROLL_END :
ScrollTo ( m_NoteDataEdit . GetLastBeat () );
break ;
case EDIT_BUTTON_SCROLL_UP_LINE :
case EDIT_BUTTON_SCROLL_UP_PAGE :
case EDIT_BUTTON_SCROLL_DOWN_LINE :
case EDIT_BUTTON_SCROLL_DOWN_PAGE :
{
float fBeatsToMove = 0.f ;
switch ( EditB )
{
DEFAULT_FAIL ( EditB );
case EDIT_BUTTON_SCROLL_UP_LINE :
case EDIT_BUTTON_SCROLL_DOWN_LINE :
fBeatsToMove = NoteTypeToBeat ( m_SnapDisplay . GetNoteType () );
2011-03-02 14:41:59 -06:00
if ( EditB == EDIT_BUTTON_SCROLL_UP_LINE )
2010-01-26 21:00:30 -06:00
fBeatsToMove *= - 1 ;
break ;
case EDIT_BUTTON_SCROLL_UP_PAGE :
case EDIT_BUTTON_SCROLL_DOWN_PAGE :
2011-01-09 17:06:40 -05:00
fBeatsToMove = beatsPerMeasure ;
2011-03-02 14:41:59 -06:00
if ( EditB == EDIT_BUTTON_SCROLL_UP_PAGE )
2010-01-26 21:00:30 -06:00
fBeatsToMove *= - 1 ;
break ;
}
if ( m_PlayerStateEdit . m_PlayerOptions . GetSong (). m_fScrolls [ PlayerOptions :: SCROLL_REVERSE ] > 0.5 )
fBeatsToMove *= - 1 ;
float fDestinationBeat = GAMESTATE -> m_fSongBeat + fBeatsToMove ;
fDestinationBeat = Quantize ( fDestinationBeat , NoteTypeToBeat ( m_SnapDisplay . GetNoteType ()) );
ScrollTo ( fDestinationBeat );
}
break ;
case EDIT_BUTTON_SCROLL_NEXT_MEASURE :
{
2011-01-09 17:06:40 -05:00
float fDestinationBeat = GAMESTATE -> m_fSongBeat + beatsPerMeasure ;
fDestinationBeat = ftruncf ( fDestinationBeat , ( float ) beatsPerMeasure );
2010-01-26 21:00:30 -06:00
ScrollTo ( fDestinationBeat );
break ;
}
case EDIT_BUTTON_SCROLL_PREV_MEASURE :
{
2011-01-09 17:06:40 -05:00
float fDestinationBeat = QuantizeUp ( GAMESTATE -> m_fSongBeat , ( float ) beatsPerMeasure );
fDestinationBeat -= ( float ) beatsPerMeasure ;
2010-01-26 21:00:30 -06:00
ScrollTo ( fDestinationBeat );
break ;
}
case EDIT_BUTTON_SCROLL_NEXT :
{
int iRow = BeatToNoteRow ( GAMESTATE -> m_fSongBeat );
NoteDataUtil :: GetNextEditorPosition ( m_NoteDataEdit , iRow );
ScrollTo ( NoteRowToBeat ( iRow ) );
}
break ;
case EDIT_BUTTON_SCROLL_PREV :
{
int iRow = BeatToNoteRow ( GAMESTATE -> m_fSongBeat );
NoteDataUtil :: GetPrevEditorPosition ( m_NoteDataEdit , iRow );
ScrollTo ( NoteRowToBeat ( iRow ) );
}
break ;
case EDIT_BUTTON_SNAP_NEXT :
if ( m_SnapDisplay . PrevSnapMode () )
OnSnapModeChange ();
break ;
case EDIT_BUTTON_SNAP_PREV :
if ( m_SnapDisplay . NextSnapMode () )
OnSnapModeChange ();
break ;
case EDIT_BUTTON_LAY_SELECT :
{
const int iCurrentRow = BeatToNoteRow ( GAMESTATE -> m_fSongBeat );
if ( m_NoteFieldEdit . m_iBeginMarker ==- 1 && m_NoteFieldEdit . m_iEndMarker ==- 1 )
{
// lay begin marker
m_NoteFieldEdit . m_iBeginMarker = BeatToNoteRow ( GAMESTATE -> m_fSongBeat );
}
else if ( m_NoteFieldEdit . m_iEndMarker ==- 1 ) // only begin marker is laid
{
if ( iCurrentRow == m_NoteFieldEdit . m_iBeginMarker )
{
m_NoteFieldEdit . m_iBeginMarker = - 1 ;
}
else
{
m_NoteFieldEdit . m_iEndMarker = max ( m_NoteFieldEdit . m_iBeginMarker , iCurrentRow );
m_NoteFieldEdit . m_iBeginMarker = min ( m_NoteFieldEdit . m_iBeginMarker , iCurrentRow );
}
}
else // both markers are laid
{
m_NoteFieldEdit . m_iBeginMarker = iCurrentRow ;
m_NoteFieldEdit . m_iEndMarker = - 1 ;
}
m_soundMarker . Play ();
}
break ;
case EDIT_BUTTON_OPEN_AREA_MENU :
{
// update enabled/disabled in g_AreaMenu
bool bAreaSelected = m_NoteFieldEdit . m_iBeginMarker !=- 1 && m_NoteFieldEdit . m_iEndMarker !=- 1 ;
g_AreaMenu . rows [ cut ]. bEnabled = bAreaSelected ;
g_AreaMenu . rows [ copy ]. bEnabled = bAreaSelected ;
g_AreaMenu . rows [ paste_at_current_beat ]. bEnabled = ! m_Clipboard . IsEmpty ();
g_AreaMenu . rows [ paste_at_begin_marker ]. bEnabled = ! m_Clipboard . IsEmpty () != 0 && m_NoteFieldEdit . m_iBeginMarker !=- 1 ;
g_AreaMenu . rows [ clear ]. bEnabled = bAreaSelected ;
g_AreaMenu . rows [ quantize ]. bEnabled = bAreaSelected ;
g_AreaMenu . rows [ turn ]. bEnabled = bAreaSelected ;
g_AreaMenu . rows [ transform ]. bEnabled = bAreaSelected ;
g_AreaMenu . rows [ alter ]. bEnabled = bAreaSelected ;
g_AreaMenu . rows [ tempo ]. bEnabled = bAreaSelected ;
g_AreaMenu . rows [ play ]. bEnabled = bAreaSelected ;
g_AreaMenu . rows [ record ]. bEnabled = bAreaSelected ;
g_AreaMenu . rows [ convert_to_pause ]. bEnabled = bAreaSelected ;
g_AreaMenu . rows [ undo ]. bEnabled = m_bHasUndo ;
EditMiniMenu ( & g_AreaMenu , SM_BackFromAreaMenu );
}
break ;
case EDIT_BUTTON_OPEN_EDIT_MENU :
EditMiniMenu ( & g_MainMenu , SM_BackFromMainMenu );
break ;
case EDIT_BUTTON_OPEN_INPUT_HELP :
DoHelp ();
break ;
case EDIT_BUTTON_OPEN_NEXT_STEPS :
case EDIT_BUTTON_OPEN_PREV_STEPS :
{
// don't keep undo when changing Steps
ClearUndo ();
// save current steps
Steps * pSteps = GAMESTATE -> m_pCurSteps [ PLAYER_1 ];
ASSERT ( pSteps );
pSteps -> SetNoteData ( m_NoteDataEdit );
// Get all Steps of this StepsType
StepsType st = pSteps -> m_StepsType ;
vector < Steps *> vSteps ;
SongUtil :: GetSteps ( GAMESTATE -> m_pCurSong , vSteps , st );
// Sort them by difficulty.
StepsUtil :: SortStepsByTypeAndDifficulty ( vSteps );
// Find out what index the current Steps are
vector < Steps *>:: iterator it = find ( vSteps . begin (), vSteps . end (), pSteps );
ASSERT ( it != vSteps . end () );
switch ( EditB )
{
DEFAULT_FAIL ( EditB );
case EDIT_BUTTON_OPEN_PREV_STEPS :
if ( it == vSteps . begin () )
{
SCREENMAN -> PlayInvalidSound ();
return ;
}
it -- ;
break ;
case EDIT_BUTTON_OPEN_NEXT_STEPS :
it ++ ;
if ( it == vSteps . end () )
{
SCREENMAN -> PlayInvalidSound ();
return ;
}
break ;
}
pSteps = * it ;
GAMESTATE -> m_pCurSteps [ PLAYER_1 ]. Set ( pSteps );
m_pSteps = pSteps ;
pSteps -> GetNoteData ( m_NoteDataEdit );
RString s = ssprintf (
SWITCHED_TO . GetValue () + " %s %s '%s' (%d of %d)" ,
GAMEMAN -> GetStepsTypeInfo ( pSteps -> m_StepsType ). szName ,
DifficultyToString ( pSteps -> GetDifficulty () ). c_str (),
pSteps -> GetDescription (). c_str (),
it - vSteps . begin () + 1 ,
int ( vSteps . size ()) );
SCREENMAN -> SystemMessage ( s );
m_soundSwitchSteps . Play ();
}
break ;
case EDIT_BUTTON_BPM_UP :
case EDIT_BUTTON_BPM_DOWN :
{
float fBPM = m_pSong -> GetBPMAtBeat ( GAMESTATE -> m_fSongBeat );
float fDelta ;
switch ( EditB )
{
DEFAULT_FAIL ( EditB );
case EDIT_BUTTON_BPM_UP : fDelta = + 0.020f ; break ;
case EDIT_BUTTON_BPM_DOWN : fDelta = - 0.020f ; break ;
}
if ( EditIsBeingPressed ( EDIT_BUTTON_ADJUST_FINE ) )
{
fDelta /= 20 ; // .001 bpm
}
else if ( input . type == IET_REPEAT )
{
if ( INPUTFILTER -> GetSecsHeld ( input . DeviceI ) < 1.0f )
fDelta *= 10 ;
else
fDelta *= 40 ;
}
float fNewBPM = fBPM + fDelta ;
m_pSong -> SetBPMAtBeat ( GAMESTATE -> m_fSongBeat , fNewBPM );
( fDelta > 0 ? m_soundValueIncrease : m_soundValueDecrease ). Play ();
SetDirty ( true );
}
break ;
case EDIT_BUTTON_STOP_UP :
case EDIT_BUTTON_STOP_DOWN :
{
float fDelta ;
switch ( EditB )
{
DEFAULT_FAIL ( EditB );
case EDIT_BUTTON_STOP_UP : fDelta = + 0.020f ; break ;
case EDIT_BUTTON_STOP_DOWN : fDelta = - 0.020f ; break ;
}
if ( EditIsBeingPressed ( EDIT_BUTTON_ADJUST_FINE ) )
{
fDelta /= 20 ; // 1ms
}
else if ( input . type == IET_REPEAT )
{
if ( INPUTFILTER -> GetSecsHeld ( input . DeviceI ) < 1.0f )
fDelta *= 10 ;
else
fDelta *= 40 ;
}
unsigned i ;
for ( i = 0 ; i < m_pSong -> m_Timing . m_StopSegments . size (); i ++ )
{
if ( m_pSong -> m_Timing . m_StopSegments [ i ]. m_iStartRow == BeatToNoteRow ( GAMESTATE -> m_fSongBeat ) )
break ;
}
if ( i == m_pSong -> m_Timing . m_StopSegments . size () ) // there is no StopSegment at the current beat
{
// create a new StopSegment
if ( fDelta > 0 )
m_pSong -> AddStopSegment ( StopSegment ( BeatToNoteRow ( GAMESTATE -> m_fSongBeat ), fDelta ) );
}
else // StopSegment being modified is m_Timing.m_StopSegments[i]
{
m_pSong -> m_Timing . m_StopSegments [ i ]. m_fStopSeconds += fDelta ;
if ( m_pSong -> m_Timing . m_StopSegments [ i ]. m_fStopSeconds <= 0 )
m_pSong -> m_Timing . m_StopSegments . erase ( m_pSong -> m_Timing . m_StopSegments . begin () + i ,
m_pSong -> m_Timing . m_StopSegments . begin () + i + 1 );
}
( fDelta > 0 ? m_soundValueIncrease : m_soundValueDecrease ). Play ();
SetDirty ( true );
}
break ;
/*
case EDIT_BUTTON_DELAY_UP:
case EDIT_BUTTON_DELAY_DOWN:
{
float fDelta;
switch( EditB )
{
DEFAULT_FAIL( EditB );
case EDIT_BUTTON_STOP_UP: fDelta = +0.020f; break;
case EDIT_BUTTON_STOP_DOWN: fDelta = -0.020f; break;
}
if( EditIsBeingPressed( EDIT_BUTTON_ADJUST_FINE ) )
{
fDelta /= 20; // 1ms
}
else if( input.type == IET_REPEAT )
{
if( INPUTFILTER->GetSecsHeld(input.DeviceI) < 1.0f )
fDelta *= 10;
else
fDelta *= 40;
}
unsigned i;
for( i=0; i<m_pSong->m_Timing.m_StopSegments.size(); i++ )
{
if( m_pSong->m_Timing.m_StopSegments[i].m_iStartRow == BeatToNoteRow(GAMESTATE->m_fSongBeat) )
break;
}
if( i == m_pSong->m_Timing.m_StopSegments.size() ) // there is no delay segment at the current beat
{
// create a new delay segment
if( fDelta > 0 )
m_pSong->AddStopSegment( StopSegment(BeatToNoteRow(GAMESTATE->m_fSongBeat), fDelta, true) );
}
else // delay segment being modified is m_Timing.m_StopSegments[i]
{
m_pSong->m_Timing.m_StopSegments[i].m_fStopSeconds += fDelta;
if( m_pSong->m_Timing.m_StopSegments[i].m_fStopSeconds <= 0 )
m_pSong->m_Timing.m_StopSegments.erase( m_pSong->m_Timing.m_StopSegments.begin()+i,
m_pSong->m_Timing.m_StopSegments.begin()+i+1);
}
(fDelta>0 ? m_soundValueIncrease : m_soundValueDecrease).Play();
SetDirty( true );
}
break;
*/
case EDIT_BUTTON_OFFSET_UP :
case EDIT_BUTTON_OFFSET_DOWN :
{
float fDelta ;
switch ( EditB )
{
DEFAULT_FAIL ( EditB );
case EDIT_BUTTON_OFFSET_DOWN : fDelta = - 0.02f ; break ;
case EDIT_BUTTON_OFFSET_UP : fDelta = + 0.02f ; break ;
}
if ( EditIsBeingPressed ( EDIT_BUTTON_ADJUST_FINE ) )
{
fDelta /= 20 ; /* 1ms */
}
else if ( input . type == IET_REPEAT )
{
if ( INPUTFILTER -> GetSecsHeld ( input . DeviceI ) < 1.0f )
fDelta *= 10 ;
else
fDelta *= 40 ;
}
m_pSong -> m_Timing . m_fBeat0OffsetInSeconds += fDelta ;
( fDelta > 0 ? m_soundValueIncrease : m_soundValueDecrease ). Play ();
SetDirty ( true );
}
break ;
case EDIT_BUTTON_SAMPLE_START_UP :
case EDIT_BUTTON_SAMPLE_START_DOWN :
case EDIT_BUTTON_SAMPLE_LENGTH_DOWN :
case EDIT_BUTTON_SAMPLE_LENGTH_UP :
{
float fDelta ;
switch ( EditB )
{
DEFAULT_FAIL ( EditB );
case EDIT_BUTTON_SAMPLE_START_DOWN : fDelta = - 0.02f ; break ;
case EDIT_BUTTON_SAMPLE_START_UP : fDelta = + 0.02f ; break ;
case EDIT_BUTTON_SAMPLE_LENGTH_DOWN : fDelta = - 0.02f ; break ;
case EDIT_BUTTON_SAMPLE_LENGTH_UP : fDelta = + 0.02f ; break ;
}
if ( input . type == IET_REPEAT )
{
if ( INPUTFILTER -> GetSecsHeld ( input . DeviceI ) < 1.0f )
fDelta *= 10 ;
else
fDelta *= 40 ;
}
if ( EditB == EDIT_BUTTON_SAMPLE_LENGTH_DOWN || EditB == EDIT_BUTTON_SAMPLE_LENGTH_UP )
{
m_pSong -> m_fMusicSampleLengthSeconds += fDelta ;
m_pSong -> m_fMusicSampleLengthSeconds = max ( m_pSong -> m_fMusicSampleLengthSeconds , 0 );
}
else
{
m_pSong -> m_fMusicSampleStartSeconds += fDelta ;
m_pSong -> m_fMusicSampleStartSeconds = max ( m_pSong -> m_fMusicSampleStartSeconds , 0 );
}
( fDelta > 0 ? m_soundValueIncrease : m_soundValueDecrease ). Play ();
SetDirty ( true );
}
break ;
case EDIT_BUTTON_PLAY_SAMPLE_MUSIC :
PlayPreviewMusic ();
break ;
case EDIT_BUTTON_OPEN_BGCHANGE_LAYER1_MENU :
case EDIT_BUTTON_OPEN_BGCHANGE_LAYER2_MENU :
switch ( EditB )
{
DEFAULT_FAIL ( EditB );
case EDIT_BUTTON_OPEN_BGCHANGE_LAYER1_MENU : g_CurrentBGChangeLayer = BACKGROUND_LAYER_1 ; break ;
case EDIT_BUTTON_OPEN_BGCHANGE_LAYER2_MENU : g_CurrentBGChangeLayer = BACKGROUND_LAYER_2 ; break ;
}
{
// Fill in option names
vector < RString > vThrowAway ;
MenuDef & menu = g_BackgroundChange ;
menu . rows [ layer ]. choices [ 0 ] = ssprintf ( "%d" , g_CurrentBGChangeLayer );
BackgroundUtil :: GetBackgroundTransitions ( "" , vThrowAway , menu . rows [ transition ]. choices );
g_BackgroundChange . rows [ transition ]. choices . insert ( g_BackgroundChange . rows [ transition ]. choices . begin (), "None" ); // add "no transition"
BackgroundUtil :: GetBackgroundEffects ( "" , vThrowAway , menu . rows [ effect ]. choices );
menu . rows [ effect ]. choices . insert ( menu . rows [ effect ]. choices . begin (), "Default" ); // add "default effect"
BackgroundUtil :: GetSongBGAnimations ( m_pSong , "" , vThrowAway , menu . rows [ file1_song_bganimation ]. choices );
BackgroundUtil :: GetSongMovies ( m_pSong , "" , vThrowAway , menu . rows [ file1_song_movie ]. choices );
BackgroundUtil :: GetSongBitmaps ( m_pSong , "" , vThrowAway , menu . rows [ file1_song_still ]. choices );
BackgroundUtil :: GetGlobalBGAnimations ( m_pSong , "" , vThrowAway , menu . rows [ file1_global_bganimation ]. choices ); // NULL to get all background files
BackgroundUtil :: GetGlobalRandomMovies ( m_pSong , "" , vThrowAway , menu . rows [ file1_global_movie ]. choices , false , false ); // all backgrounds
BackgroundUtil :: GetGlobalRandomMovies ( m_pSong , "" , vThrowAway , menu . rows [ file1_global_movie_song_group ]. choices , false , true ); // song group's backgrounds
BackgroundUtil :: GetGlobalRandomMovies ( m_pSong , "" , vThrowAway , menu . rows [ file1_global_movie_song_group_and_genre ]. choices , true , true ); // song group and genre's backgrounds
menu . rows [ file2_type ]. choices = menu . rows [ file1_type ]. choices ;
menu . rows [ file2_song_bganimation ]. choices = menu . rows [ file1_song_bganimation ]. choices ;
menu . rows [ file2_song_movie ]. choices = menu . rows [ file1_song_movie ]. choices ;
menu . rows [ file2_song_still ]. choices = menu . rows [ file1_song_still ]. choices ;
menu . rows [ file2_global_bganimation ]. choices = menu . rows [ file1_global_bganimation ]. choices ;
menu . rows [ file2_global_movie ]. choices = menu . rows [ file1_global_movie ]. choices ;
menu . rows [ file2_global_movie_song_group ]. choices = menu . rows [ file1_global_movie_song_group ]. choices ;
menu . rows [ file2_global_movie_song_group_and_genre ]. choices = menu . rows [ file1_global_movie_song_group_and_genre ]. choices ;
// Fill in lines enabled/disabled
bool bAlreadyBGChangeHere = false ;
BackgroundChange bgChange ;
FOREACH ( BackgroundChange , m_pSong -> GetBackgroundChanges ( g_CurrentBGChangeLayer ), bgc )
{
if ( bgc -> m_fStartBeat == GAMESTATE -> m_fSongBeat )
{
bAlreadyBGChangeHere = true ;
bgChange = * bgc ;
}
}
#define FILL_ENABLED( x ) menu.rows[x].bEnabled = menu.rows[x].choices.size() > 0;
FILL_ENABLED ( transition );
FILL_ENABLED ( effect );
FILL_ENABLED ( file1_song_bganimation );
FILL_ENABLED ( file1_song_movie );
FILL_ENABLED ( file1_song_still );
FILL_ENABLED ( file1_global_bganimation );
FILL_ENABLED ( file1_global_movie );
FILL_ENABLED ( file1_global_movie_song_group );
FILL_ENABLED ( file1_global_movie_song_group_and_genre );
FILL_ENABLED ( file2_song_bganimation );
FILL_ENABLED ( file2_song_movie );
FILL_ENABLED ( file2_song_still );
FILL_ENABLED ( file2_global_bganimation );
FILL_ENABLED ( file2_global_movie );
FILL_ENABLED ( file2_global_movie_song_group );
FILL_ENABLED ( file2_global_movie_song_group_and_genre );
#undef FILL_ENABLED
menu . rows [ delete_change ]. bEnabled = bAlreadyBGChangeHere ;
// set default choices
menu . rows [ rate ]. SetDefaultChoiceIfPresent ( ssprintf ( "%2.0f%%" , bgChange . m_fRate * 100 ) );
menu . rows [ transition ]. SetDefaultChoiceIfPresent ( bgChange . m_sTransition );
menu . rows [ effect ]. SetDefaultChoiceIfPresent ( bgChange . m_def . m_sEffect );
menu . rows [ file1_type ]. iDefaultChoice = none ;
if ( bgChange . m_def . m_sFile1 == RANDOM_BACKGROUND_FILE ) menu . rows [ file1_type ]. iDefaultChoice = dynamic_random ;
if ( menu . rows [ file1_song_bganimation ]. SetDefaultChoiceIfPresent ( bgChange . m_def . m_sFile1 ) ) menu . rows [ file1_type ]. iDefaultChoice = song_bganimation ;
if ( menu . rows [ file1_song_movie ]. SetDefaultChoiceIfPresent ( bgChange . m_def . m_sFile1 ) ) menu . rows [ file1_type ]. iDefaultChoice = song_movie ;
if ( menu . rows [ file1_song_still ]. SetDefaultChoiceIfPresent ( bgChange . m_def . m_sFile1 ) ) menu . rows [ file1_type ]. iDefaultChoice = song_bitmap ;
if ( menu . rows [ file1_global_bganimation ]. SetDefaultChoiceIfPresent ( bgChange . m_def . m_sFile1 ) ) menu . rows [ file1_type ]. iDefaultChoice = global_bganimation ;
if ( menu . rows [ file1_global_movie ]. SetDefaultChoiceIfPresent ( bgChange . m_def . m_sFile1 ) ) menu . rows [ file1_type ]. iDefaultChoice = global_movie ;
if ( menu . rows [ file1_global_movie_song_group ]. SetDefaultChoiceIfPresent ( bgChange . m_def . m_sFile1 ) ) menu . rows [ file1_type ]. iDefaultChoice = global_movie_song_group ;
if ( menu . rows [ file1_global_movie_song_group_and_genre ]. SetDefaultChoiceIfPresent ( bgChange . m_def . m_sFile1 ) ) menu . rows [ file1_type ]. iDefaultChoice = global_movie_song_group_and_genre ;
menu . rows [ file2_type ]. iDefaultChoice = none ;
if ( bgChange . m_def . m_sFile2 == RANDOM_BACKGROUND_FILE ) menu . rows [ file2_type ]. iDefaultChoice = dynamic_random ;
if ( menu . rows [ file2_song_bganimation ]. SetDefaultChoiceIfPresent ( bgChange . m_def . m_sFile2 ) ) menu . rows [ file2_type ]. iDefaultChoice = song_bganimation ;
if ( menu . rows [ file2_song_movie ]. SetDefaultChoiceIfPresent ( bgChange . m_def . m_sFile2 ) ) menu . rows [ file2_type ]. iDefaultChoice = song_movie ;
if ( menu . rows [ file2_song_still ]. SetDefaultChoiceIfPresent ( bgChange . m_def . m_sFile2 ) ) menu . rows [ file2_type ]. iDefaultChoice = song_bitmap ;
if ( menu . rows [ file2_global_bganimation ]. SetDefaultChoiceIfPresent ( bgChange . m_def . m_sFile2 ) ) menu . rows [ file2_type ]. iDefaultChoice = global_bganimation ;
if ( menu . rows [ file2_global_movie ]. SetDefaultChoiceIfPresent ( bgChange . m_def . m_sFile2 ) ) menu . rows [ file2_type ]. iDefaultChoice = global_movie ;
if ( menu . rows [ file2_global_movie_song_group ]. SetDefaultChoiceIfPresent ( bgChange . m_def . m_sFile2 ) ) menu . rows [ file2_type ]. iDefaultChoice = global_movie_song_group ;
if ( menu . rows [ file2_global_movie_song_group_and_genre ]. SetDefaultChoiceIfPresent ( bgChange . m_def . m_sFile2 ) ) menu . rows [ file2_type ]. iDefaultChoice = global_movie_song_group_and_genre ;
menu . rows [ color1 ]. SetDefaultChoiceIfPresent ( bgChange . m_def . m_sColor1 );
menu . rows [ color2 ]. SetDefaultChoiceIfPresent ( bgChange . m_def . m_sColor2 );
EditMiniMenu ( & g_BackgroundChange , SM_BackFromBGChange );
}
break ;
case EDIT_BUTTON_OPEN_COURSE_MENU :
{
g_CourseMode . rows [ 0 ]. choices . clear ();
g_CourseMode . rows [ 0 ]. choices . push_back ( CommonMetrics :: LocalizeOptionItem ( "Off" , false ) );
g_CourseMode . rows [ 0 ]. iDefaultChoice = 0 ;
vector < Course *> courses ;
SONGMAN -> GetAllCourses ( courses , false );
for ( unsigned i = 0 ; i < courses . size (); ++ i )
{
const Course * crs = courses [ i ];
bool bUsesThisSong = false ;
for ( unsigned e = 0 ; e < crs -> m_vEntries . size (); ++ e )
{
if ( crs -> m_vEntries [ e ]. songID . ToSong () != m_pSong )
continue ;
bUsesThisSong = true ;
}
if ( bUsesThisSong )
{
g_CourseMode . rows [ 0 ]. choices . push_back ( crs -> GetDisplayFullTitle () );
if ( crs == GAMESTATE -> m_pCurCourse )
g_CourseMode . rows [ 0 ]. iDefaultChoice = g_CourseMode . rows [ 0 ]. choices . size () - 1 ;
}
}
EditMiniMenu ( & g_CourseMode , SM_BackFromCourseModeMenu );
}
break ;
case EDIT_BUTTON_OPEN_COURSE_ATTACK_MENU :
{
Course * pCourse = GAMESTATE -> m_pCurCourse ;
if ( pCourse == NULL )
break ;
CourseEntry & ce = pCourse -> m_vEntries [ GAMESTATE -> m_iEditCourseEntryIndex ];
float fStartTime = m_pSong -> GetElapsedTimeFromBeat ( GAMESTATE -> m_fSongBeat );
int iAttack = FindAttackAtTime ( ce . attacks , fStartTime );
if ( iAttack >= 0 )
{
const RString sDuration = ssprintf ( "%.5f" , ce . attacks [ iAttack ]. fSecsRemaining );
g_InsertCourseAttack . rows [ remove ]. bEnabled = true ;
if ( g_InsertCourseAttack . rows [ duration ]. choices . size () == 9 )
g_InsertCourseAttack . rows [ duration ]. choices . push_back ( sDuration );
else
g_InsertCourseAttack . rows [ duration ]. choices . back () = sDuration ;
g_InsertCourseAttack . rows [ duration ]. iDefaultChoice = 9 ;
}
else
{
if ( g_InsertCourseAttack . rows [ duration ]. choices . size () == 10 )
g_InsertCourseAttack . rows [ duration ]. choices . pop_back ();
g_InsertCourseAttack . rows [ duration ]. iDefaultChoice = 3 ;
}
EditMiniMenu ( & g_InsertCourseAttack , SM_BackFromInsertCourseAttack );
}
break ;
case EDIT_BUTTON_ADD_COURSE_MODS :
{
float fStart , fEnd ;
PlayerOptions po ;
const Course * pCourse = GAMESTATE -> m_pCurCourse ;
if ( pCourse == NULL )
break ;
const CourseEntry & ce = pCourse -> m_vEntries [ GAMESTATE -> m_iEditCourseEntryIndex ];
if ( m_NoteFieldEdit . m_iBeginMarker == - 1 )
{
fStart = - 1 ;
fEnd = - 1 ;
po . FromString ( ce . sModifiers );
}
else
{
fStart = m_pSong -> GetElapsedTimeFromBeat ( NoteRowToBeat ( m_NoteFieldEdit . m_iBeginMarker ) );
int iAttack = FindAttackAtTime ( ce . attacks , fStart );
if ( iAttack >= 0 )
po . FromString ( ce . attacks [ iAttack ]. sModifiers );
if ( m_NoteFieldEdit . m_iEndMarker == - 1 )
fEnd = m_pSong -> m_fMusicLengthSeconds ;
else
fEnd = m_pSong -> GetElapsedTimeFromBeat ( NoteRowToBeat ( m_NoteFieldEdit . m_iEndMarker ) );
}
g_fLastInsertAttackPositionSeconds = fStart ;
g_fLastInsertAttackDurationSeconds = fEnd - fStart ;
GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_PlayerOptions . Assign ( ModsLevel_Stage , po );
SCREENMAN -> AddNewScreenToTop ( "ScreenPlayerOptions" , SM_BackFromInsertCourseAttackPlayerOptions );
}
break ;
case EDIT_BUTTON_BAKE_RANDOM_FROM_SONG_GROUP :
case EDIT_BUTTON_BAKE_RANDOM_FROM_SONG_GROUP_AND_GENRE :
{
bool bTryGenre = EditB == EDIT_BUTTON_BAKE_RANDOM_FROM_SONG_GROUP_AND_GENRE ;
RString sName = GetOneBakedRandomFile ( m_pSong , bTryGenre );
if ( sName . empty () )
{
SCREENMAN -> PlayInvalidSound ();
SCREENMAN -> SystemMessage ( NO_BACKGROUNDS_AVAILABLE );
}
else
{
bool bAlreadyBGChangeHere = false ;
BackgroundLayer iLayer = BACKGROUND_LAYER_1 ;
BackgroundChange bgChange ;
bgChange . m_fStartBeat = GAMESTATE -> m_fSongBeat ;
FOREACH ( BackgroundChange , m_pSong -> GetBackgroundChanges ( iLayer ), bgc )
{
if ( bgc -> m_fStartBeat == GAMESTATE -> m_fSongBeat )
{
bAlreadyBGChangeHere = true ;
bgChange = * bgc ;
m_pSong -> GetBackgroundChanges ( iLayer ). erase ( bgc );
break ;
}
}
bgChange . m_def . m_sFile1 = sName ;
m_pSong -> AddBackgroundChange ( iLayer , bgChange );
m_soundMarker . Play ();
}
}
break ;
case EDIT_BUTTON_PLAY_FROM_START :
HandleMainMenuChoice ( play_whole_song );
break ;
case EDIT_BUTTON_PLAY_FROM_CURSOR :
HandleMainMenuChoice ( play_current_beat_to_end );
break ;
case EDIT_BUTTON_PLAY_SELECTION :
HandleMainMenuChoice ( play_selection );
break ;
case EDIT_BUTTON_RECORD_SELECTION :
if ( m_NoteFieldEdit . m_iBeginMarker !=- 1 && m_NoteFieldEdit . m_iEndMarker !=- 1 )
{
HandleAreaMenuChoice ( record );
}
else
{
if ( g_iDefaultRecordLength . Get () == - 1 )
{
m_iStartPlayingAt = BeatToNoteRow ( GAMESTATE -> m_fSongBeat );
m_iStopPlayingAt = max ( m_iStartPlayingAt , m_NoteDataEdit . GetLastRow () + 1 );
}
else
{
m_iStartPlayingAt = BeatToNoteRow ( ftruncf ( GAMESTATE -> m_fSongBeat , g_iDefaultRecordLength . Get ()) );
m_iStopPlayingAt = m_iStartPlayingAt + BeatToNoteRow ( g_iDefaultRecordLength . Get () );
}
if ( GAMESTATE -> m_pCurSteps [ 0 ] -> IsAnEdit () )
m_iStopPlayingAt = min ( m_iStopPlayingAt , BeatToNoteRow ( GetMaximumBeatForNewNote ()) );
if ( m_iStartPlayingAt >= m_iStopPlayingAt )
{
SCREENMAN -> PlayInvalidSound ();
return ;
}
TransitionEditState ( STATE_RECORDING );
}
break ;
case EDIT_BUTTON_RECORD_FROM_CURSOR :
m_iStartPlayingAt = BeatToNoteRow ( GAMESTATE -> m_fSongBeat );
m_iStopPlayingAt = max ( m_iStartPlayingAt , m_NoteDataEdit . GetLastRow () );
TransitionEditState ( STATE_RECORDING );
break ;
case EDIT_BUTTON_INSERT :
HandleAreaMenuChoice ( insert_and_shift );
SCREENMAN -> PlayInvalidSound ();
break ;
case EDIT_BUTTON_INSERT_SHIFT_PAUSES :
HandleAreaMenuChoice ( shift_pauses_forward );
SCREENMAN -> PlayInvalidSound ();
break ;
case EDIT_BUTTON_DELETE :
HandleAreaMenuChoice ( delete_and_shift );
SCREENMAN -> PlayInvalidSound ();
break ;
case EDIT_BUTTON_DELETE_SHIFT_PAUSES :
HandleAreaMenuChoice ( shift_pauses_backward );
SCREENMAN -> PlayInvalidSound ();
break ;
case EDIT_BUTTON_SAVE :
HandleMainMenuChoice ( ScreenEdit :: save );
break ;
case EDIT_BUTTON_UNDO :
Undo ();
break ;
case EDIT_BUTTON_SWITCH_PLAYERS :
if ( m_InputPlayerNumber != PLAYER_INVALID )
{
enum_add ( m_InputPlayerNumber , 1 );
if ( m_InputPlayerNumber == NUM_PLAYERS )
m_InputPlayerNumber = PLAYER_1 ;
}
break ;
}
}
void ScreenEdit :: InputRecord ( const InputEventPlus & input , EditButton EditB )
{
if ( input . type == IET_FIRST_PRESS && EditB == EDIT_BUTTON_RETURN_TO_EDIT )
{
TransitionEditState ( STATE_EDITING );
return ;
}
if ( input . pn != PLAYER_1 )
return ; // ignore
const int iCol = GAMESTATE -> GetCurrentStyle () -> GameInputToColumn ( input . GameI );
switch ( input . type )
{
DEFAULT_FAIL ( input . type );
case IET_FIRST_PRESS :
{
if ( EditIsBeingPressed ( EDIT_BUTTON_REMOVE_NOTE ) )
{
// Remove notes in Update.
break ;
}
// Add a tap
float fBeat = GAMESTATE -> m_fSongBeat ;
fBeat = Quantize ( fBeat , NoteTypeToBeat ( m_SnapDisplay . GetNoteType ()) );
const int iRow = BeatToNoteRow ( fBeat );
if ( iRow < 0 )
break ;
// Don't add outside of the range.
if ( iRow < m_iStartPlayingAt || iRow >= m_iStopPlayingAt )
return ;
// Remove hold if any so that we don't have taps inside of a hold.
int iHeadRow ;
if ( m_NoteDataRecord . IsHoldNoteAtRow ( iCol , iRow , & iHeadRow ) )
m_NoteDataRecord . SetTapNote ( iCol , iHeadRow , TAP_EMPTY );
TapNote tn = TAP_ORIGINAL_TAP ;
tn . pn = m_InputPlayerNumber ;
m_NoteDataRecord . SetTapNote ( iCol , iRow , tn );
m_NoteFieldRecord . Step ( iCol , TNS_W1 );
}
break ;
case IET_REPEAT :
case IET_RELEASE :
// don't add or extend holds here; we do it in Update()
break ;
}
}
void ScreenEdit :: InputRecordPaused ( const InputEventPlus & input , EditButton EditB )
{
if ( input . type != IET_FIRST_PRESS )
return ; // don't care
switch ( EditB )
{
case EDIT_BUTTON_UNDO :
/* We've already actually committed changes to m_NoteDataEdit, so all we have
* to do to undo is Undo() as usual, and copy the note data back in. */
Undo ();
m_NoteDataRecord . CopyAll ( m_NoteDataEdit );
break ;
case EDIT_BUTTON_PLAY_SELECTION :
TransitionEditState ( STATE_PLAYING );
break ;
case EDIT_BUTTON_RECORD_SELECTION :
TransitionEditState ( STATE_RECORDING );
break ;
case EDIT_BUTTON_RECORD_FROM_CURSOR :
if ( GAMESTATE -> m_pCurSteps [ 0 ] -> IsAnEdit () )
{
float fMaximumBeat = GetMaximumBeatForNewNote ();
if ( NoteRowToBeat ( m_iStopPlayingAt ) >= fMaximumBeat )
{
// We're already at the end.
SCREENMAN -> PlayInvalidSound ();
return ;
}
}
// Pick up where we left off.
{
int iSize = m_iStopPlayingAt - m_iStartPlayingAt ;
m_iStartPlayingAt = m_iStopPlayingAt ;
m_iStopPlayingAt += iSize ;
if ( GAMESTATE -> m_pCurSteps [ 0 ] -> IsAnEdit () )
m_iStopPlayingAt = min ( m_iStopPlayingAt , BeatToNoteRow ( GetMaximumBeatForNewNote ()) );
}
TransitionEditState ( STATE_RECORDING );
break ;
case EDIT_BUTTON_RETURN_TO_EDIT :
TransitionEditState ( STATE_EDITING );
break ;
}
}
void ScreenEdit :: InputPlay ( const InputEventPlus & input , EditButton EditB )
{
switch ( input . type )
{
case IET_RELEASE :
case IET_FIRST_PRESS :
break ;
default :
return ;
}
GameButtonType gbt = GAMESTATE -> m_pCurGame -> GetPerButtonInfo ( input . GameI . button ) -> m_gbt ;
if ( GamePreferences :: m_AutoPlay == PC_HUMAN && GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_PlayerOptions . GetCurrent (). m_fPlayerAutoPlay == 0 )
{
const int iCol = GAMESTATE -> GetCurrentStyle () -> GameInputToColumn ( input . GameI );
bool bRelease = input . type == IET_RELEASE ;
switch ( input . pn )
{
2010-02-14 23:02:34 -06:00
case PLAYER_2 :
// ignore player 2 input unless this mode requires it
if ( GAMESTATE -> GetCurrentStyle () -> m_StyleType != StyleType_TwoPlayersSharedSides )
break ;
// fall through to input handling logic:
2010-01-26 21:00:30 -06:00
case PLAYER_1 :
{
switch ( gbt )
{
case GameButtonType_INVALID :
break ;
case GameButtonType_Step :
if ( iCol != - 1 )
m_Player -> Step ( iCol , - 1 , input . DeviceI . ts , false , bRelease );
break ;
case GameButtonType_Fret :
if ( iCol != - 1 )
m_Player -> Fret ( iCol , - 1 , input . DeviceI . ts , false , bRelease );
break ;
case GameButtonType_Strum :
m_Player -> Strum ( iCol , - 1 , input . DeviceI . ts , false , bRelease );
break ;
}
}
break ;
}
}
if ( gbt == GameButtonType_INVALID && input . type == IET_FIRST_PRESS )
{
switch ( EditB )
{
case EDIT_BUTTON_RETURN_TO_EDIT :
/* When exiting play mode manually, leave the cursor where it is. */
m_fBeatToReturnTo = GAMESTATE -> m_fSongBeat ;
TransitionEditState ( STATE_EDITING );
break ;
case EDIT_BUTTON_OFFSET_UP :
case EDIT_BUTTON_OFFSET_DOWN :
{
float fOffsetDelta ;
switch ( EditB )
{
DEFAULT_FAIL ( EditB );
case EDIT_BUTTON_OFFSET_DOWN : fOffsetDelta = - 0.020f ; break ;
case EDIT_BUTTON_OFFSET_UP : fOffsetDelta = + 0.020f ; break ;
}
if ( EditIsBeingPressed ( EDIT_BUTTON_ADJUST_FINE ) )
{
fOffsetDelta /= 20 ; /* 1ms */
}
else if ( input . type == IET_REPEAT )
{
if ( INPUTFILTER -> GetSecsHeld ( input . DeviceI ) < 1.0f )
fOffsetDelta *= 10 ;
else
fOffsetDelta *= 40 ;
}
m_pSong -> m_Timing . m_fBeat0OffsetInSeconds += fOffsetDelta ;
}
break ;
}
}
}
void ScreenEdit :: TransitionEditState ( EditState em )
{
EditState old = m_EditState ;
// If we're going from recording to paused, come back when we're done.
if ( old == STATE_RECORDING_PAUSED && em == STATE_PLAYING )
m_bReturnToRecordMenuAfterPlay = true ;
const bool bStateChanging = em != old ;
#if 0
// If switching out of record, open the menu.
{
bool bGoToRecordMenu = (old == STATE_RECORDING);
if( m_bReturnToRecordMenuAfterPlay && old == STATE_PLAYING )
{
bGoToRecordMenu = true;
m_bReturnToRecordMenuAfterPlay = false;
}
if( bGoToRecordMenu )
em = STATE_RECORDING_PAUSED;
}
#endif
// If we're playing music or assist ticks when changing modes, stop.
SOUND -> StopMusic ();
if ( m_pSoundMusic )
m_pSoundMusic -> StopPlaying ();
m_GameplayAssist . StopPlaying ();
GAMESTATE -> m_bGameplayLeadIn . Set ( true );
if ( bStateChanging )
{
switch ( old )
{
case STATE_EDITING :
// If exiting EDIT mode, save the cursor position.
m_fBeatToReturnTo = GAMESTATE -> m_fSongBeat ;
break ;
case STATE_PLAYING :
AdjustSync :: HandleSongEnd ();
if ( AdjustSync :: IsSyncDataChanged () )
ScreenSaveSync :: PromptSaveSync ();
break ;
case STATE_RECORDING :
SetDirty ( true );
SaveUndo ();
// delete old TapNotes in the range
m_NoteDataEdit . ClearRange ( m_iStartPlayingAt , m_iStopPlayingAt );
m_NoteDataEdit . CopyRange ( m_NoteDataRecord , m_iStartPlayingAt , m_iStopPlayingAt , m_iStartPlayingAt );
m_NoteDataRecord . ClearAll ();
CheckNumberOfNotesAndUndo ();
break ;
}
}
// Set up player options for this mode. (EDITING uses m_PlayerStateEdit,
// which we don't need to change.)
if ( em != STATE_EDITING )
{
// Stop displaying course attacks, if any.
GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> RemoveActiveAttacks ();
// Load the player's default PlayerOptions.
GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> RebuildPlayerOptionsFromActiveAttacks ();
switch ( em )
{
case STATE_RECORDING :
case STATE_RECORDING_PAUSED :
PO_GROUP_ASSIGN_N ( GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_PlayerOptions , ModsLevel_Stage , m_fScrolls , PlayerOptions :: SCROLL_CENTERED , 1.0f );
break ;
}
// Snap to current options.
GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_PlayerOptions . SetCurrentToLevel ( ModsLevel_Stage );
}
switch ( em )
{
DEFAULT_FAIL ( em );
case STATE_EDITING :
// Important: people will stop playing, change the BG and start again; make sure we reload
m_Background . Unload ();
m_Foreground . Unload ();
2011-03-02 14:41:59 -06:00
// Restore the cursor position.
2010-01-26 21:00:30 -06:00
GAMESTATE -> m_fSongBeat = m_fBeatToReturnTo ;
2011-03-02 14:41:59 -06:00
// Make sure we're snapped.
2010-01-26 21:00:30 -06:00
GAMESTATE -> m_fSongBeat = Quantize ( GAMESTATE -> m_fSongBeat , NoteTypeToBeat ( m_SnapDisplay . GetNoteType ()) );
/* Playing and recording have lead-ins, which may start before beat 0;
* make sure we don't stay there if we escaped out early. */
GAMESTATE -> m_fSongBeat = max ( GAMESTATE -> m_fSongBeat , 0 );
break ;
case STATE_PLAYING :
case STATE_RECORDING :
{
if ( bStateChanging )
AdjustSync :: ResetOriginalSyncData ();
/* Give a 1 second lead-in. If we're loading Player, this must be done first. */
float fSeconds = m_pSong -> m_Timing . GetElapsedTimeFromBeat ( NoteRowToBeat ( m_iStartPlayingAt ) ) - 1 ;
GAMESTATE -> UpdateSongPosition ( fSeconds , m_pSong -> m_Timing );
GAMESTATE -> m_bGameplayLeadIn . Set ( false );
/* Reset the note skin, in case preferences have changed. */
// XXX
// GAMESTATE->ResetNoteSkins();
//GAMESTATE->res
break ;
}
case STATE_RECORDING_PAUSED :
break ;
}
switch ( em )
{
case STATE_PLAYING :
// If we're in course display mode, set that up.
SetupCourseAttacks ();
m_Player . Load ( m_NoteDataEdit );
if ( GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_PlayerOptions . GetCurrent (). m_fPlayerAutoPlay != 0 )
GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_PlayerController = PC_AUTOPLAY ;
else
GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_PlayerController = GamePreferences :: m_AutoPlay ;
if ( g_bEditorShowBGChangesPlay )
{
/* FirstBeat affects backgrounds, so commit changes to memory (not to disk)
* and recalc it. */
Steps * pSteps = GAMESTATE -> m_pCurSteps [ PLAYER_1 ];
ASSERT ( pSteps );
pSteps -> SetNoteData ( m_NoteDataEdit );
m_pSong -> ReCalculateRadarValuesAndLastBeat ();
m_Background . Unload ();
m_Background . LoadFromSong ( m_pSong );
m_Foreground . Unload ();
m_Foreground . LoadFromSong ( m_pSong );
}
break ;
case STATE_RECORDING :
case STATE_RECORDING_PAUSED :
// initialize m_NoteFieldRecord
m_NoteDataRecord . CopyAll ( m_NoteDataEdit );
// highlight the section being recorded
m_NoteFieldRecord . m_iBeginMarker = m_iStartPlayingAt ;
m_NoteFieldRecord . m_iEndMarker = m_iStopPlayingAt ;
break ;
}
// Show/hide depending on edit state (em)
m_sprOverlay -> PlayCommand ( EditStateToString ( em ) );
m_sprUnderlay -> PlayCommand ( EditStateToString ( em ) );
m_Background . SetVisible ( g_bEditorShowBGChangesPlay && em != STATE_EDITING );
m_textInputTips . SetVisible ( em == STATE_EDITING );
m_textInfo . SetVisible ( em == STATE_EDITING );
// Play the OnCommands again so that these will be re-hidden if the OnCommand hides them.
if ( em == STATE_EDITING )
{
m_textInputTips . PlayCommand ( "On" );
m_textInfo . PlayCommand ( "On" );
}
m_textPlayRecordHelp . SetVisible ( em != STATE_EDITING );
m_SnapDisplay . SetVisible ( em == STATE_EDITING );
m_NoteFieldEdit . SetVisible ( em == STATE_EDITING );
m_NoteFieldRecord . SetVisible ( em == STATE_RECORDING || em == STATE_RECORDING_PAUSED );
m_Player -> SetVisible ( em == STATE_PLAYING );
m_Foreground . SetVisible ( g_bEditorShowBGChangesPlay && em != STATE_EDITING );
switch ( em )
{
case STATE_PLAYING :
case STATE_RECORDING :
const float fStartSeconds = m_pSong -> GetElapsedTimeFromBeat ( GAMESTATE -> m_fSongBeat );
LOG -> Trace ( "Starting playback at %f" , fStartSeconds );
RageSoundParams p ;
p . m_fSpeed = GAMESTATE -> m_SongOptions . GetCurrent (). m_fMusicRate ;
p . m_StartSecond = fStartSeconds ;
p . StopMode = RageSoundParams :: M_CONTINUE ;
m_pSoundMusic -> SetProperty ( "AccurateSync" , true );
m_pSoundMusic -> Play ( & p );
break ;
}
m_EditState = em ;
}
void ScreenEdit :: ScrollTo ( float fDestinationBeat )
{
CLAMP ( fDestinationBeat , 0 , GetMaximumBeatForMoving () );
// Don't play the sound and do the hold note logic below if our position didn't change.
const float fOriginalBeat = GAMESTATE -> m_fSongBeat ;
if ( fOriginalBeat == fDestinationBeat )
return ;
GAMESTATE -> m_fSongBeat = fDestinationBeat ;
// check to see if they're holding a button
for ( int n = 0 ; n < NUM_EDIT_BUTTON_COLUMNS ; n ++ )
{
int iCol = n ;
// Ctrl + number = input to right half
if ( EditIsBeingPressed ( EDIT_BUTTON_RIGHT_SIDE ) )
ShiftToRightSide ( iCol , m_NoteDataEdit . GetNumTracks () );
if ( iCol >= m_NoteDataEdit . GetNumTracks () )
continue ; // skip
EditButton b = EditButton ( EDIT_BUTTON_COLUMN_0 + n );
if ( ! EditIsBeingPressed ( b ) )
continue ;
// create a new hold note
int iStartRow = BeatToNoteRow ( min ( fOriginalBeat , fDestinationBeat ) );
int iEndRow = BeatToNoteRow ( max ( fOriginalBeat , fDestinationBeat ) );
// Don't SaveUndo. We want to undo the whole hold, not just the last segment
// that the user made. Dragging the hold bigger can only absorb and remove
// other taps, so dragging won't cause us to exceed the note limit.
2011-03-13 22:45:19 -04:00
TapNote tn = EditIsBeingPressed ( EDIT_BUTTON_LAY_ROLL ) ? TAP_ORIGINAL_ROLL_HEAD : TAP_ORIGINAL_HOLD_HEAD ;
2010-01-26 21:00:30 -06:00
tn . pn = m_InputPlayerNumber ;
m_NoteDataEdit . AddHoldNote ( iCol , iStartRow , iEndRow , tn );
}
if ( EditIsBeingPressed ( EDIT_BUTTON_SCROLL_SELECT ) )
{
/* Shift is being held.
* If this is the first time we've moved since shift was depressed,
* the old position (before this move) becomes the start pos: */
int iDestinationRow = BeatToNoteRow ( fDestinationBeat );
if ( m_iShiftAnchor == - 1 )
m_iShiftAnchor = BeatToNoteRow ( fOriginalBeat );
if ( iDestinationRow == m_iShiftAnchor )
{
// We're back at the anchor, so we have nothing selected.
m_NoteFieldEdit . m_iBeginMarker = m_NoteFieldEdit . m_iEndMarker = - 1 ;
}
else
{
m_NoteFieldEdit . m_iBeginMarker = m_iShiftAnchor ;
m_NoteFieldEdit . m_iEndMarker = iDestinationRow ;
if ( m_NoteFieldEdit . m_iBeginMarker > m_NoteFieldEdit . m_iEndMarker )
swap ( m_NoteFieldEdit . m_iBeginMarker , m_NoteFieldEdit . m_iEndMarker );
}
}
m_soundChangeLine . Play ();
}
void ScreenEdit :: HandleMessage ( const Message & msg )
{
if ( msg == "Judgment" )
{
PlayerNumber pn ;
msg . GetParam ( "Player" , pn );
if ( GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_PlayerOptions . GetCurrent (). m_bMuteOnError )
{
RageSoundReader * pSoundReader = m_AutoKeysounds . GetPlayerSound ( pn );
if ( pSoundReader == NULL )
pSoundReader = m_AutoKeysounds . GetSharedSound ();
HoldNoteScore hns ;
msg . GetParam ( "HoldNoteScore" , hns );
TapNoteScore tns ;
msg . GetParam ( "TapNoteScore" , tns );
bool bOn = false ;
if ( hns != HoldNoteScore_Invalid )
bOn = hns != HNS_LetGo ;
else
bOn = tns != TNS_Miss ;
if ( pSoundReader )
pSoundReader -> SetProperty ( "Volume" , bOn ? 1.0f : 0.0f );
}
}
if ( msg == Message_SongModified )
{
SetDirty ( true );
}
Screen :: HandleMessage ( msg );
}
static LocalizedString SAVE_SUCCESSFUL ( "ScreenEdit" , "Save successful." );
void ScreenEdit :: HandleScreenMessage ( const ScreenMessage SM )
{
if ( SM != SM_UpdateTextInfo )
m_bTextInfoNeedsUpdate = true ;
if ( SM == SM_UpdateTextInfo )
{
UpdateTextInfo ();
this -> PostScreenMessage ( SM_UpdateTextInfo , 0.1f );
}
else if ( SM == SM_GoToNextScreen )
{
GAMESTATE -> m_EditMode = EditMode_Invalid ;
}
else if ( SM == SM_BackFromMainMenu )
{
HandleMainMenuChoice ( ( MainMenuChoice ) ScreenMiniMenu :: s_iLastRowCode , ScreenMiniMenu :: s_viLastAnswers );
}
else if ( SM == SM_BackFromAreaMenu )
{
HandleAreaMenuChoice ( ( AreaMenuChoice ) ScreenMiniMenu :: s_iLastRowCode , ScreenMiniMenu :: s_viLastAnswers );
}
else if ( SM == SM_BackFromStepsInformation )
{
HandleStepsInformationChoice ( ( StepsInformationChoice ) ScreenMiniMenu :: s_iLastRowCode , ScreenMiniMenu :: s_viLastAnswers );
}
else if ( SM == SM_BackFromSongInformation )
{
HandleSongInformationChoice ( ( SongInformationChoice ) ScreenMiniMenu :: s_iLastRowCode , ScreenMiniMenu :: s_viLastAnswers );
}
2011-01-18 00:49:03 -05:00
else if ( SM == SM_BackFromTimingDataInformation )
{
HandleTimingDataInformationChoice ( ( TimingDataInformationChoice ) ScreenMiniMenu :: s_iLastRowCode , ScreenMiniMenu :: s_viLastAnswers );
}
2010-01-26 21:00:30 -06:00
else if ( SM == SM_BackFromBPMChange )
{
float fBPM = StringToFloat ( ScreenTextEntry :: s_sLastAnswer );
if ( fBPM > 0 )
m_pSong -> SetBPMAtBeat ( GAMESTATE -> m_fSongBeat , fBPM );
SetDirty ( true );
}
else if ( SM == SM_BackFromStopChange )
{
float fStop = StringToFloat ( ScreenTextEntry :: s_sLastAnswer );
if ( fStop >= 0 )
m_pSong -> m_Timing . SetStopAtBeat ( GAMESTATE -> m_fSongBeat , fStop );
SetDirty ( true );
}
else if ( SM == SM_BackFromDelayChange )
{
float fDelay = StringToFloat ( ScreenTextEntry :: s_sLastAnswer );
if ( fDelay >= 0 )
m_pSong -> m_Timing . SetStopAtBeat ( GAMESTATE -> m_fSongBeat , fDelay , true );
SetDirty ( true );
}
2011-01-16 13:22:55 -05:00
else if ( SM == SM_BackFromTimeSignatureNumeratorChange )
{
int iNum = atoi ( ScreenTextEntry :: s_sLastAnswer );
if ( iNum > 0 )
{
2011-01-16 14:19:59 -05:00
m_pSong -> m_Timing . SetTimeSignatureNumeratorAtBeat ( GAMESTATE -> m_fSongBeat , iNum );
2011-01-16 13:22:55 -05:00
}
SetDirty ( true );
}
else if ( SM == SM_BackFromTimeSignatureDenominatorChange )
{
int iDen = atoi ( ScreenTextEntry :: s_sLastAnswer );
if ( iDen > 0 )
{
2011-01-16 13:52:25 -05:00
m_pSong -> m_Timing . SetTimeSignatureDenominatorAtBeat ( GAMESTATE -> m_fSongBeat , iDen );
2011-01-16 13:22:55 -05:00
}
SetDirty ( true );
}
2011-01-18 11:49:27 -05:00
else if ( SM == SM_BackFromTickcountChange )
{
int iTick = atoi ( ScreenTextEntry :: s_sLastAnswer );
2011-03-01 09:30:47 -05:00
if ( iTick >= 0 && iTick <= ROWS_PER_BEAT )
2011-01-18 11:49:27 -05:00
{
m_pSong -> m_Timing . SetTickcountAtBeat ( GAMESTATE -> m_fSongBeat , iTick );
}
SetDirty ( true );
}
2011-03-05 01:44:58 -05:00
else if ( SM == SM_BackFromComboChange )
{
int iCombo = atoi ( ScreenTextEntry :: s_sLastAnswer );
if ( iCombo >= 0 )
{
m_pSong -> m_Timing . SetComboAtBeat ( GAMESTATE -> m_fSongBeat , iCombo );
}
SetDirty ( true );
}
2010-01-26 21:00:30 -06:00
else if ( SM == SM_BackFromBGChange )
{
HandleBGChangeChoice ( ( BGChangeChoice ) ScreenMiniMenu :: s_iLastRowCode , ScreenMiniMenu :: s_viLastAnswers );
SetDirty ( true );
}
else if ( SM == SM_BackFromCourseModeMenu )
{
const int num = ScreenMiniMenu :: s_viLastAnswers [ 0 ];
GAMESTATE -> m_pCurCourse . Set ( NULL );
if ( num != 0 )
{
const RString name = g_CourseMode . rows [ 0 ]. choices [ num ];
Course * pCourse = SONGMAN -> FindCourse ( name );
int iCourseEntryIndex = - 1 ;
FOREACH_CONST ( CourseEntry , pCourse -> m_vEntries , i )
{
if ( i -> songID . ToSong () == GAMESTATE -> m_pCurSong . Get () )
iCourseEntryIndex = i - pCourse -> m_vEntries . begin ();
}
ASSERT ( iCourseEntryIndex != - 1 );
GAMESTATE -> m_pCurCourse . Set ( pCourse );
GAMESTATE -> m_iEditCourseEntryIndex . Set ( iCourseEntryIndex );
ASSERT ( GAMESTATE -> m_pCurCourse );
}
}
else if ( SM == SM_BackFromOptions )
{
// The options may have changed the note skin.
m_NoteFieldRecord . CacheAllUsedNoteSkins ();
m_Player -> CacheAllUsedNoteSkins ();
// stop any music that screen may have been playing
SOUND -> StopMusic ();
}
else if ( SM == SM_BackFromInsertTapAttack )
{
int iDurationChoice = ScreenMiniMenu :: s_viLastAnswers [ 0 ];
g_fLastInsertAttackDurationSeconds = StringToFloat ( g_InsertTapAttack . rows [ 0 ]. choices [ iDurationChoice ] );
SCREENMAN -> AddNewScreenToTop ( "ScreenPlayerOptions" , SM_BackFromInsertTapAttackPlayerOptions );
}
else if ( SM == SM_BackFromInsertTapAttackPlayerOptions )
{
PlayerOptions poChosen = GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_PlayerOptions . GetPreferred ();
RString sMods = poChosen . GetString ();
const int row = BeatToNoteRow ( GAMESTATE -> m_fSongBeat );
TapNote tn (
TapNote :: attack ,
TapNote :: SubType_Invalid ,
TapNote :: original ,
sMods ,
g_fLastInsertAttackDurationSeconds ,
- 1 );
tn . pn = m_InputPlayerNumber ;
SetDirty ( true );
SaveUndo ();
m_NoteDataEdit . SetTapNote ( g_iLastInsertTapAttackTrack , row , tn );
CheckNumberOfNotesAndUndo ();
}
else if ( SM == SM_BackFromInsertCourseAttack )
{
int iDurationChoice = ScreenMiniMenu :: s_viLastAnswers [ 0 ];
Course * pCourse = GAMESTATE -> m_pCurCourse ;
CourseEntry & ce = pCourse -> m_vEntries [ GAMESTATE -> m_iEditCourseEntryIndex ];
int iAttack ;
g_fLastInsertAttackPositionSeconds = m_pSong -> GetElapsedTimeFromBeat ( GAMESTATE -> m_fSongBeat );
g_fLastInsertAttackDurationSeconds = StringToFloat ( g_InsertCourseAttack . rows [ 0 ]. choices [ iDurationChoice ] );
iAttack = FindAttackAtTime ( ce . attacks , g_fLastInsertAttackPositionSeconds );
if ( ScreenMiniMenu :: s_iLastRowCode == ScreenEdit :: remove )
{
ASSERT ( iAttack >= 0 );
ce . attacks . erase ( ce . attacks . begin () + iAttack );
}
else
{
PlayerOptions po ;
if ( iAttack >= 0 )
po . FromString ( ce . attacks [ iAttack ]. sModifiers );
GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_PlayerOptions . Assign ( ModsLevel_Preferred , po );
SCREENMAN -> AddNewScreenToTop ( "ScreenPlayerOptions" , SM_BackFromInsertCourseAttackPlayerOptions );
}
}
else if ( SM == SM_BackFromInsertCourseAttackPlayerOptions )
{
PlayerOptions poChosen = GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_PlayerOptions . GetPreferred ();
RString sMods = poChosen . GetString ();
Course * pCourse = GAMESTATE -> m_pCurCourse ;
CourseEntry & ce = pCourse -> m_vEntries [ GAMESTATE -> m_iEditCourseEntryIndex ];
if ( g_fLastInsertAttackPositionSeconds < 0 )
{
ce . sModifiers = sMods ;
}
else
{
Attack a (
ATTACK_LEVEL_1 ,
g_fLastInsertAttackPositionSeconds ,
g_fLastInsertAttackDurationSeconds ,
sMods ,
false ,
false );
int iAttack = FindAttackAtTime ( ce . attacks , g_fLastInsertAttackPositionSeconds );
if ( iAttack >= 0 )
ce . attacks [ iAttack ] = a ;
else
ce . attacks . push_back ( a );
}
}
else if ( SM == SM_DoRevertToLastSave )
{
if ( ScreenPrompt :: s_LastAnswer == ANSWER_YES )
{
SaveUndo ();
CopyFromLastSave ();
m_pSteps -> GetNoteData ( m_NoteDataEdit );
SetDirty ( false );
}
}
else if ( SM == SM_DoRevertFromDisk )
{
if ( ScreenPrompt :: s_LastAnswer == ANSWER_YES )
{
SaveUndo ();
RevertFromDisk ();
m_pSteps -> GetNoteData ( m_NoteDataEdit );
SetDirty ( false );
}
}
else if ( SM == SM_DoSaveAndExit ) // just asked "save before exiting? yes, no, cancel"
{
switch ( ScreenPrompt :: s_LastAnswer )
{
DEFAULT_FAIL ( ScreenPrompt :: s_LastAnswer );
case ANSWER_YES :
// This will send SM_SaveSuccessful or SM_SaveFailed.
HandleMainMenuChoice ( ScreenEdit :: save_on_exit );
return ;
case ANSWER_NO :
2011-03-16 21:59:46 -05:00
// Don't save; just exit.
2010-01-26 21:00:30 -06:00
SCREENMAN -> SendMessageToTopScreen ( SM_DoExit );
return ;
case ANSWER_CANCEL :
break ; // do nothing
}
}
else if ( SM == SM_SaveSuccessful )
{
LOG -> Trace ( "Save successful." );
CopyToLastSave ();
SetDirty ( false );
SONGMAN -> Invalidate ( GAMESTATE -> m_pCurSong );
if ( m_CurrentAction == save_on_exit )
ScreenPrompt :: Prompt ( SM_DoExit , SAVE_SUCCESSFUL );
else
SCREENMAN -> SystemMessage ( SAVE_SUCCESSFUL );
}
else if ( SM == SM_SaveFailed ) // save failed ; stay in the editor
{
2011-03-16 21:59:46 -05:00
/* We committed the steps to SongManager. Revert to the last save, and
2010-01-26 21:00:30 -06:00
* recommit the reversion to SongManager. */
2011-03-16 21:33:31 -05:00
LOG -> Trace ( "Save failed. Changes uncommitted from memory." );
2010-01-26 21:00:30 -06:00
CopyFromLastSave ();
m_pSteps -> SetNoteData ( m_NoteDataEdit );
}
else if ( SM == SM_DoExit )
{
// IMPORTANT: CopyFromLastSave before deleting the Steps below
CopyFromLastSave ();
2011-03-16 21:33:31 -05:00
/* The user has been given a choice to save.
* Delete all unsaved steps before exiting the editor. */
/* FIXME: This code causes all the steps to be deleted if you quit
* without saving. However, without this code, any new steps will get
* saved on quit. -aj */
2011-03-16 23:31:06 -04:00
2010-01-26 21:00:30 -06:00
Song * pSong = GAMESTATE -> m_pCurSong ;
const vector < Steps *> & apSteps = pSong -> GetAllSteps ();
vector < Steps *> apToDelete ;
FOREACH_CONST ( Steps * , apSteps , s )
{
if ( ( * s ) -> IsAutogen () || ( * s ) -> GetSavedToDisk () )
continue ;
apToDelete . push_back ( * s );
}
FOREACH_CONST ( Steps * , apToDelete , s )
{
Steps * pSteps = * s ;
pSong -> DeleteSteps ( pSteps );
if ( m_pSteps == pSteps )
m_pSteps = NULL ;
if ( GAMESTATE -> m_pCurSteps [ PLAYER_1 ]. Get () == pSteps )
GAMESTATE -> m_pCurSteps [ PLAYER_1 ]. Set ( NULL );
}
2011-03-16 23:31:06 -04:00
2010-01-26 21:00:30 -06:00
m_Out . StartTransitioning ( SM_GoToNextScreen );
}
else if ( SM == SM_GainFocus )
{
/* When another screen comes up, RageSounds takes over the sound timer. When we come
* back, put the timer back to where it was. */
GAMESTATE -> m_fSongBeat = m_fTrailingBeat ;
}
else if ( SM == SM_LoseFocus )
{
// Snap the trailing beat, in case we lose focus while tweening.
m_fTrailingBeat = GAMESTATE -> m_fSongBeat ;
}
ScreenWithMenuElements :: HandleScreenMessage ( SM );
}
void ScreenEdit :: OnSnapModeChange ()
{
m_soundChangeSnap . Play ();
NoteType nt = m_SnapDisplay . GetNoteType ();
int iStepIndex = BeatToNoteRow ( GAMESTATE -> m_fSongBeat );
int iElementsPerNoteType = BeatToNoteRow ( NoteTypeToBeat ( nt ) );
int iStepIndexHangover = iStepIndex % iElementsPerNoteType ;
GAMESTATE -> m_fSongBeat -= NoteRowToBeat ( iStepIndexHangover );
}
// Helper function for below
// Begin helper functions for InputEdit
static void ChangeDescription ( const RString & sNew )
{
Steps * pSteps = GAMESTATE -> m_pCurSteps [ PLAYER_1 ];
2011-02-14 23:05:52 -06:00
// Don't erase edit descriptions.
2010-01-26 21:00:30 -06:00
if ( sNew . empty () && pSteps -> GetDifficulty () == Difficulty_Edit )
return ;
pSteps -> SetDescription ( sNew );
}
2011-02-14 23:05:52 -06:00
static void ChangeChartStyle ( const RString & sNew )
{
Steps * pSteps = GAMESTATE -> m_pCurSteps [ PLAYER_1 ];
pSteps -> SetChartStyle ( sNew );
}
2011-02-11 01:51:01 -05:00
static void ChangeStepCredit ( const RString & sNew )
{
Steps * pSteps = GAMESTATE -> m_pCurSteps [ PLAYER_1 ];
pSteps -> SetCredit ( sNew );
}
2010-01-26 21:00:30 -06:00
static void ChangeMainTitle ( const RString & sNew )
{
Song * pSong = GAMESTATE -> m_pCurSong ;
pSong -> m_sMainTitle = sNew ;
}
static void ChangeSubTitle ( const RString & sNew )
{
Song * pSong = GAMESTATE -> m_pCurSong ;
pSong -> m_sSubTitle = sNew ;
}
static void ChangeArtist ( const RString & sNew )
{
Song * pSong = GAMESTATE -> m_pCurSong ;
pSong -> m_sArtist = sNew ;
}
2010-07-27 21:53:40 -05:00
static void ChangeGenre ( const RString & sNew )
{
Song * pSong = GAMESTATE -> m_pCurSong ;
pSong -> m_sGenre = sNew ;
}
2010-01-26 21:00:30 -06:00
static void ChangeCredit ( const RString & sNew )
{
Song * pSong = GAMESTATE -> m_pCurSong ;
pSong -> m_sCredit = sNew ;
}
static void ChangeMainTitleTranslit ( const RString & sNew )
{
Song * pSong = GAMESTATE -> m_pCurSong ;
pSong -> m_sMainTitleTranslit = sNew ;
}
static void ChangeSubTitleTranslit ( const RString & sNew )
{
Song * pSong = GAMESTATE -> m_pCurSong ;
pSong -> m_sSubTitleTranslit = sNew ;
}
static void ChangeArtistTranslit ( const RString & sNew )
{
Song * pSong = GAMESTATE -> m_pCurSong ;
pSong -> m_sArtistTranslit = sNew ;
}
static void ChangeLastBeatHint ( const RString & sNew )
{
GAMESTATE -> m_pCurSong -> m_fSpecifiedLastBeat = StringToFloat ( sNew );
}
// End helper functions
static LocalizedString REVERT_LAST_SAVE ( "ScreenEdit" , "Do you want to revert to your last save?" );
static LocalizedString DESTROY_ALL_UNSAVED_CHANGES ( "ScreenEdit" , "This will destroy all unsaved changes." );
static LocalizedString REVERT_FROM_DISK ( "ScreenEdit" , "Do you want to revert from disk?" );
static LocalizedString SAVE_CHANGES_BEFORE_EXITING ( "ScreenEdit" , "Do you want to save changes before exiting?" );
2011-01-16 13:22:55 -05:00
2010-01-26 21:00:30 -06:00
void ScreenEdit :: HandleMainMenuChoice ( MainMenuChoice c , const vector < int > & iAnswers )
{
switch ( c )
{
DEFAULT_FAIL ( c );
case play_selection :
if ( m_NoteFieldEdit . m_iBeginMarker !=- 1 && m_NoteFieldEdit . m_iEndMarker !=- 1 )
HandleAreaMenuChoice ( play );
else if ( m_NoteFieldEdit . m_iBeginMarker !=- 1 )
HandleMainMenuChoice ( play_selection_start_to_end );
else
HandleMainMenuChoice ( play_current_beat_to_end );
break ;
case play_whole_song :
{
m_iStartPlayingAt = 0 ;
m_iStopPlayingAt = m_NoteDataEdit . GetLastRow ();
TransitionEditState ( STATE_PLAYING );
}
break ;
case play_selection_start_to_end :
{
m_iStartPlayingAt = m_NoteFieldEdit . m_iBeginMarker ;
m_iStopPlayingAt = max ( m_iStartPlayingAt , m_NoteDataEdit . GetLastRow () );
TransitionEditState ( STATE_PLAYING );
}
break ;
case play_current_beat_to_end :
{
m_iStartPlayingAt = BeatToNoteRow ( GAMESTATE -> m_fSongBeat );
m_iStopPlayingAt = max ( m_iStartPlayingAt , m_NoteDataEdit . GetLastRow () );
TransitionEditState ( STATE_PLAYING );
}
break ;
case set_selection_start :
{
const int iCurrentRow = BeatToNoteRow ( GAMESTATE -> m_fSongBeat );
if ( m_NoteFieldEdit . m_iEndMarker !=- 1 && iCurrentRow >= m_NoteFieldEdit . m_iEndMarker )
{
SCREENMAN -> PlayInvalidSound ();
}
else
{
m_NoteFieldEdit . m_iBeginMarker = iCurrentRow ;
m_soundMarker . Play ();
}
}
break ;
case set_selection_end :
{
const int iCurrentRow = BeatToNoteRow ( GAMESTATE -> m_fSongBeat );
if ( m_NoteFieldEdit . m_iBeginMarker !=- 1 && iCurrentRow <= m_NoteFieldEdit . m_iBeginMarker )
{
SCREENMAN -> PlayInvalidSound ();
}
else
{
m_NoteFieldEdit . m_iEndMarker = iCurrentRow ;
m_soundMarker . Play ();
}
}
break ;
case edit_steps_information :
{
/* XXX: If the difficulty is changed from EDIT, and pSteps->WasLoadedFromProfile()
* is true, we should warn that the steps will no longer be saved to the profile. */
Steps * pSteps = GAMESTATE -> m_pCurSteps [ PLAYER_1 ];
float fMusicSeconds = m_pSoundMusic -> GetLengthSeconds ();
g_StepsInformation . rows [ difficulty ]. choices . clear ();
FOREACH_ENUM ( Difficulty , dc )
{
g_StepsInformation . rows [ difficulty ]. choices . push_back ( "|" + CustomDifficultyToLocalizedString ( GetCustomDifficulty ( pSteps -> m_StepsType , dc , CourseType_Invalid ) ) );
}
g_StepsInformation . rows [ difficulty ]. iDefaultChoice = pSteps -> GetDifficulty ();
g_StepsInformation . rows [ difficulty ]. bEnabled = ( EDIT_MODE . GetValue () >= EditMode_Full );
g_StepsInformation . rows [ meter ]. iDefaultChoice = clamp ( pSteps -> GetMeter () - 1 , 0 , MAX_METER + 1 );
g_StepsInformation . rows [ meter ]. bEnabled = ( EDIT_MODE . GetValue () >= EditMode_Home );
g_StepsInformation . rows [ predict_meter ]. SetOneUnthemedChoice ( ssprintf ( "%.2f" , pSteps -> PredictMeter ()) );
g_StepsInformation . rows [ description ]. bEnabled = ( EDIT_MODE . GetValue () >= EditMode_Full );
g_StepsInformation . rows [ description ]. SetOneUnthemedChoice ( pSteps -> GetDescription () );
2011-02-14 23:05:52 -06:00
g_StepsInformation . rows [ chartstyle ]. bEnabled = ( EDIT_MODE . GetValue () >= EditMode_Full );
g_StepsInformation . rows [ chartstyle ]. SetOneUnthemedChoice ( pSteps -> GetChartStyle () );
2011-02-11 01:51:01 -05:00
g_StepsInformation . rows [ step_credit ]. bEnabled = ( EDIT_MODE . GetValue () >= EditMode_Full );
g_StepsInformation . rows [ step_credit ]. SetOneUnthemedChoice ( pSteps -> GetCredit () );
2010-01-26 21:00:30 -06:00
g_StepsInformation . rows [ tap_notes ]. SetOneUnthemedChoice ( ssprintf ( "%d" , m_NoteDataEdit . GetNumTapNotes ()) );
g_StepsInformation . rows [ jumps ]. SetOneUnthemedChoice ( ssprintf ( "%d" , m_NoteDataEdit . GetNumJumps ()) );
g_StepsInformation . rows [ hands ]. SetOneUnthemedChoice ( ssprintf ( "%d" , m_NoteDataEdit . GetNumHands ()) );
g_StepsInformation . rows [ quads ]. SetOneUnthemedChoice ( ssprintf ( "%d" , m_NoteDataEdit . GetNumQuads ()) );
g_StepsInformation . rows [ holds ]. SetOneUnthemedChoice ( ssprintf ( "%d" , m_NoteDataEdit . GetNumHoldNotes ()) );
g_StepsInformation . rows [ mines ]. SetOneUnthemedChoice ( ssprintf ( "%d" , m_NoteDataEdit . GetNumMines ()) );
g_StepsInformation . rows [ stream ]. SetOneUnthemedChoice ( ssprintf ( "%.2f" , NoteDataUtil :: GetStreamRadarValue ( m_NoteDataEdit , fMusicSeconds )) );
g_StepsInformation . rows [ voltage ]. SetOneUnthemedChoice ( ssprintf ( "%.2f" , NoteDataUtil :: GetVoltageRadarValue ( m_NoteDataEdit , fMusicSeconds )) );
g_StepsInformation . rows [ air ]. SetOneUnthemedChoice ( ssprintf ( "%.2f" , NoteDataUtil :: GetAirRadarValue ( m_NoteDataEdit , fMusicSeconds )) );
g_StepsInformation . rows [ freeze ]. SetOneUnthemedChoice ( ssprintf ( "%.2f" , NoteDataUtil :: GetFreezeRadarValue ( m_NoteDataEdit , fMusicSeconds )) );
g_StepsInformation . rows [ chaos ]. SetOneUnthemedChoice ( ssprintf ( "%.2f" , NoteDataUtil :: GetChaosRadarValue ( m_NoteDataEdit , fMusicSeconds )) );
EditMiniMenu ( & g_StepsInformation , SM_BackFromStepsInformation , SM_None );
}
break ;
case save :
case save_on_exit :
{
m_CurrentAction = c ;
// copy edit into current Steps
m_pSteps -> SetNoteData ( m_NoteDataEdit );
switch ( EDIT_MODE . GetValue () )
{
DEFAULT_FAIL ( EDIT_MODE . GetValue () );
case EditMode_Home :
{
ASSERT ( m_pSteps -> IsAnEdit () );
RString sError ;
m_pSteps -> CalculateRadarValues ( m_pSong -> m_fMusicLengthSeconds );
if ( ! NotesWriterSM :: WriteEditFileToMachine ( m_pSong , m_pSteps , sError ) )
{
ScreenPrompt :: Prompt ( SM_None , sError );
break ;
}
m_pSteps -> SetSavedToDisk ( true );
// HACK: clear undo, so "exit" below knows we don't need to save.
// This only works because important non-steps data can't be changed in
// home mode (BPMs, stops).
ClearUndo ();
SCREENMAN -> ZeroNextUpdate ();
HandleScreenMessage ( SM_SaveSuccessful );
/* FIXME
RString s;
switch( c )
{
case save: s = "ScreenMemcardSaveEditsAfterSave"; break;
case save_on_exit: s = "ScreenMemcardSaveEditsAfterExit"; break;
default: ASSERT(0);
}
SCREENMAN->AddNewScreenToTop( s );
*/
}
break ;
case EditMode_Full :
{
// This will recalculate radar values.
m_pSong -> Save ();
SCREENMAN -> ZeroNextUpdate ();
HandleScreenMessage ( SM_SaveSuccessful );
}
break ;
case EditMode_CourseMods :
case EditMode_Practice :
break ;
}
m_soundSave . Play ();
}
break ;
case revert_to_last_save :
ScreenPrompt :: Prompt ( SM_DoRevertToLastSave , REVERT_LAST_SAVE . GetValue () + " \n\n " + DESTROY_ALL_UNSAVED_CHANGES . GetValue (), PROMPT_YES_NO , ANSWER_NO );
break ;
case revert_from_disk :
ScreenPrompt :: Prompt ( SM_DoRevertFromDisk , REVERT_FROM_DISK . GetValue () + " \n\n " + DESTROY_ALL_UNSAVED_CHANGES . GetValue (), PROMPT_YES_NO , ANSWER_NO );
break ;
case options :
SCREENMAN -> AddNewScreenToTop ( "ScreenEditOptions" , SM_BackFromOptions );
break ;
case edit_song_info :
{
const Song * pSong = GAMESTATE -> m_pCurSong ;
g_SongInformation . rows [ main_title ]. SetOneUnthemedChoice ( pSong -> m_sMainTitle );
g_SongInformation . rows [ sub_title ]. SetOneUnthemedChoice ( pSong -> m_sSubTitle );
g_SongInformation . rows [ artist ]. SetOneUnthemedChoice ( pSong -> m_sArtist );
2010-07-27 21:53:40 -05:00
g_SongInformation . rows [ genre ]. SetOneUnthemedChoice ( pSong -> m_sGenre );
2010-01-26 21:00:30 -06:00
g_SongInformation . rows [ credit ]. SetOneUnthemedChoice ( pSong -> m_sCredit );
g_SongInformation . rows [ main_title_transliteration ]. SetOneUnthemedChoice ( pSong -> m_sMainTitleTranslit );
g_SongInformation . rows [ sub_title_transliteration ]. SetOneUnthemedChoice ( pSong -> m_sSubTitleTranslit );
g_SongInformation . rows [ artist_transliteration ]. SetOneUnthemedChoice ( pSong -> m_sArtistTranslit );
g_SongInformation . rows [ last_beat_hint ]. SetOneUnthemedChoice ( ssprintf ( "%.5f" , pSong -> m_fSpecifiedLastBeat ) );
EditMiniMenu ( & g_SongInformation , SM_BackFromSongInformation );
}
break ;
2011-01-18 00:49:03 -05:00
case edit_timing_data :
{
const Song * pSong = GAMESTATE -> m_pCurSong ;
TimingData pTime = pSong -> m_Timing ;
const float fBeat = GAMESTATE -> m_fSongBeat ;
g_TimingDataInformation . rows [ bpm ]. SetOneUnthemedChoice ( ssprintf ( "%.5f" , pSong -> GetBPMAtBeat ( fBeat ) ) );
g_TimingDataInformation . rows [ stop ]. SetOneUnthemedChoice ( ssprintf ( "%.5f" , pTime . GetStopAtBeat ( fBeat ) ) ) ;
g_TimingDataInformation . rows [ delay ]. SetOneUnthemedChoice ( ssprintf ( "%.5f" , pTime . GetDelayAtBeat ( fBeat ) ) );
g_TimingDataInformation . rows [ time_signature_numerator ]. SetOneUnthemedChoice ( ssprintf ( "%d" , pTime . GetTimeSignatureNumeratorAtBeat ( fBeat ) ) );
g_TimingDataInformation . rows [ time_signature_denominator ]. SetOneUnthemedChoice ( ssprintf ( "%d" , pTime . GetTimeSignatureDenominatorAtBeat ( fBeat ) ) );
2011-01-18 11:49:27 -05:00
g_TimingDataInformation . rows [ tickcount ]. SetOneUnthemedChoice ( ssprintf ( "%d" , pTime . GetTickcountAtBeat ( fBeat ) ) );
2011-03-05 01:44:58 -05:00
g_TimingDataInformation . rows [ combo ]. SetOneUnthemedChoice ( ssprintf ( "%d" , pTime . GetComboAtBeat ( fBeat ) ) );
2011-01-18 00:49:03 -05:00
EditMiniMenu ( & g_TimingDataInformation , SM_BackFromTimingDataInformation );
}
2011-01-16 14:19:59 -05:00
break ;
2011-01-18 00:49:03 -05:00
2010-01-26 21:00:30 -06:00
case play_preview_music :
PlayPreviewMusic ();
break ;
case exit :
switch ( EDIT_MODE . GetValue () )
{
DEFAULT_FAIL ( EDIT_MODE . GetValue () );
case EditMode_Full :
case EditMode_Home :
if ( IsDirty () )
ScreenPrompt :: Prompt ( SM_DoSaveAndExit , SAVE_CHANGES_BEFORE_EXITING , PROMPT_YES_NO_CANCEL , ANSWER_CANCEL );
else
SCREENMAN -> SendMessageToTopScreen ( SM_DoExit );
break ;
case EditMode_Practice :
case EditMode_CourseMods :
SCREENMAN -> SendMessageToTopScreen ( SM_DoExit );
break ;
}
break ;
};
}
void ScreenEdit :: HandleAreaMenuChoice ( AreaMenuChoice c , const vector < int > & iAnswers , bool bAllowUndo )
{
bool bSaveUndo = false ;
switch ( c )
{
DEFAULT_FAIL ( c );
case cut :
case copy :
case play :
case record :
case undo :
bSaveUndo = false ;
break ;
case paste_at_current_beat :
case paste_at_begin_marker :
case clear :
case quantize :
case turn :
case transform :
case alter :
case tempo :
case insert_and_shift :
case delete_and_shift :
case shift_pauses_forward :
case shift_pauses_backward :
case convert_to_pause :
case convert_pause_to_beat :
bSaveUndo = true ;
break ;
}
if ( bSaveUndo )
SetDirty ( true );
/* We call HandleAreaMenuChoice recursively. Only the outermost
* HandleAreaMenuChoice should allow Undo so that the inner calls don't
* also save Undo and mess up the outermost */
if ( ! bAllowUndo )
bSaveUndo = false ;
if ( bSaveUndo )
SaveUndo ();
switch ( c )
{
DEFAULT_FAIL ( c );
case cut :
{
HandleAreaMenuChoice ( copy );
HandleAreaMenuChoice ( clear );
}
break ;
case copy :
{
ASSERT ( m_NoteFieldEdit . m_iBeginMarker !=- 1 && m_NoteFieldEdit . m_iEndMarker !=- 1 );
m_Clipboard . ClearAll ();
m_Clipboard . CopyRange ( m_NoteDataEdit , m_NoteFieldEdit . m_iBeginMarker , m_NoteFieldEdit . m_iEndMarker );
}
break ;
case paste_at_current_beat :
case paste_at_begin_marker :
{
int iDestFirstRow = - 1 ;
switch ( c )
{
DEFAULT_FAIL ( c );
case paste_at_current_beat :
iDestFirstRow = BeatToNoteRow ( GAMESTATE -> m_fSongBeat );
break ;
case paste_at_begin_marker :
ASSERT ( m_NoteFieldEdit . m_iBeginMarker !=- 1 );
iDestFirstRow = m_NoteFieldEdit . m_iBeginMarker ;
break ;
}
int iRowsToCopy = m_Clipboard . GetLastRow () + 1 ;
m_NoteDataEdit . CopyRange ( m_Clipboard , 0 , iRowsToCopy , iDestFirstRow );
}
break ;
case clear :
{
ASSERT ( m_NoteFieldEdit . m_iBeginMarker !=- 1 && m_NoteFieldEdit . m_iEndMarker !=- 1 );
m_NoteDataEdit . ClearRange ( m_NoteFieldEdit . m_iBeginMarker , m_NoteFieldEdit . m_iEndMarker );
}
break ;
case quantize :
{
NoteType nt = ( NoteType ) iAnswers [ c ];
NoteDataUtil :: SnapToNearestNoteType ( m_NoteDataEdit , nt , nt , m_NoteFieldEdit . m_iBeginMarker , m_NoteFieldEdit . m_iEndMarker );
}
break ;
case turn :
{
const NoteData OldClipboard ( m_Clipboard );
HandleAreaMenuChoice ( cut );
StepsType st = GAMESTATE -> GetCurrentStyle () -> m_StepsType ;
TurnType tt = ( TurnType ) iAnswers [ c ];
switch ( tt )
{
DEFAULT_FAIL ( tt );
case left : NoteDataUtil :: Turn ( m_Clipboard , st , NoteDataUtil :: left ); break ;
case right : NoteDataUtil :: Turn ( m_Clipboard , st , NoteDataUtil :: right ); break ;
case mirror : NoteDataUtil :: Turn ( m_Clipboard , st , NoteDataUtil :: mirror ); break ;
case shuffle : NoteDataUtil :: Turn ( m_Clipboard , st , NoteDataUtil :: shuffle ); break ;
case super_shuffle : NoteDataUtil :: Turn ( m_Clipboard , st , NoteDataUtil :: super_shuffle ); break ;
}
HandleAreaMenuChoice ( paste_at_begin_marker );
m_Clipboard = OldClipboard ;
}
break ;
case transform :
{
int iBeginRow = m_NoteFieldEdit . m_iBeginMarker ;
int iEndRow = m_NoteFieldEdit . m_iEndMarker ;
TransformType tt = ( TransformType ) iAnswers [ c ];
StepsType st = GAMESTATE -> GetCurrentStyle () -> m_StepsType ;
switch ( tt )
{
DEFAULT_FAIL ( tt );
case noholds : NoteDataUtil :: RemoveHoldNotes ( m_NoteDataEdit , iBeginRow , iEndRow ); break ;
case nomines : NoteDataUtil :: RemoveMines ( m_NoteDataEdit , iBeginRow , iBeginRow ); break ;
case little : NoteDataUtil :: Little ( m_NoteDataEdit , iBeginRow , iEndRow ); break ;
case wide : NoteDataUtil :: Wide ( m_NoteDataEdit , iBeginRow , iEndRow ); break ;
case big : NoteDataUtil :: Big ( m_NoteDataEdit , iBeginRow , iEndRow ); break ;
case quick : NoteDataUtil :: Quick ( m_NoteDataEdit , iBeginRow , iEndRow ); break ;
case skippy : NoteDataUtil :: Skippy ( m_NoteDataEdit , iBeginRow , iEndRow ); break ;
case add_mines : NoteDataUtil :: AddMines ( m_NoteDataEdit , iBeginRow , iEndRow ); break ;
case echo : NoteDataUtil :: Echo ( m_NoteDataEdit , iBeginRow , iEndRow ); break ;
case stomp : NoteDataUtil :: Stomp ( m_NoteDataEdit , st , iBeginRow , iEndRow ); break ;
case planted : NoteDataUtil :: Planted ( m_NoteDataEdit , iBeginRow , iEndRow ); break ;
case floored : NoteDataUtil :: Floored ( m_NoteDataEdit , iBeginRow , iEndRow ); break ;
case twister : NoteDataUtil :: Twister ( m_NoteDataEdit , iBeginRow , iEndRow ); break ;
case nojumps : NoteDataUtil :: RemoveJumps ( m_NoteDataEdit , iBeginRow , iEndRow ); break ;
case nohands : NoteDataUtil :: RemoveHands ( m_NoteDataEdit , iBeginRow , iEndRow ); break ;
case noquads : NoteDataUtil :: RemoveQuads ( m_NoteDataEdit , iBeginRow , iEndRow ); break ;
case nostretch : NoteDataUtil :: RemoveStretch ( m_NoteDataEdit , st , iBeginRow , iBeginRow ); break ;
}
// bake in the additions
NoteDataUtil :: ConvertAdditionsToRegular ( m_NoteDataEdit );
}
break ;
case alter :
{
const NoteData OldClipboard ( m_Clipboard );
HandleAreaMenuChoice ( cut );
AlterType at = ( AlterType ) iAnswers [ c ];
switch ( at )
{
DEFAULT_FAIL ( at );
case autogen_to_fill_width :
{
NoteData temp ( m_Clipboard );
int iMaxNonEmptyTrack = NoteDataUtil :: GetMaxNonEmptyTrack ( temp );
if ( iMaxNonEmptyTrack == - 1 )
break ;
temp . SetNumTracks ( iMaxNonEmptyTrack + 1 );
NoteDataUtil :: LoadTransformedSlidingWindow ( temp , m_Clipboard , m_Clipboard . GetNumTracks () );
NoteDataUtil :: RemoveStretch ( m_Clipboard , GAMESTATE -> m_pCurSteps [ 0 ] -> m_StepsType );
}
break ;
case backwards : NoteDataUtil :: Backwards ( m_Clipboard ); break ;
case swap_sides : NoteDataUtil :: SwapSides ( m_Clipboard ); break ;
case copy_left_to_right : NoteDataUtil :: CopyLeftToRight ( m_Clipboard ); break ;
case copy_right_to_left : NoteDataUtil :: CopyRightToLeft ( m_Clipboard ); break ;
case clear_left : NoteDataUtil :: ClearLeft ( m_Clipboard ); break ;
case clear_right : NoteDataUtil :: ClearRight ( m_Clipboard ); break ;
case collapse_to_one : NoteDataUtil :: CollapseToOne ( m_Clipboard ); break ;
case collapse_left : NoteDataUtil :: CollapseLeft ( m_Clipboard ); break ;
case shift_left : NoteDataUtil :: ShiftLeft ( m_Clipboard ); break ;
case shift_right : NoteDataUtil :: ShiftRight ( m_Clipboard ); break ;
}
HandleAreaMenuChoice ( paste_at_begin_marker );
m_Clipboard = OldClipboard ;
}
break ;
case tempo :
{
// This affects all steps.
const NoteData OldClipboard ( m_Clipboard );
HandleAreaMenuChoice ( cut );
AlterType at = ( AlterType ) iAnswers [ c ];
float fScale = - 1 ;
switch ( at )
{
DEFAULT_FAIL ( at );
case compress_2x : fScale = 0.5f ; break ;
case compress_3_2 : fScale = 2.0f / 3 ; break ;
case compress_4_3 : fScale = 0.75f ; break ;
case expand_4_3 : fScale = 4.0f / 3 ; break ;
case expand_3_2 : fScale = 1.5f ; break ;
case expand_2x : fScale = 2 ; break ;
}
switch ( at )
{
DEFAULT_FAIL ( at );
case compress_2x : NoteDataUtil :: Scale ( m_Clipboard , fScale ); break ;
case compress_3_2 : NoteDataUtil :: Scale ( m_Clipboard , fScale ); break ;
case compress_4_3 : NoteDataUtil :: Scale ( m_Clipboard , fScale ); break ;
case expand_4_3 : NoteDataUtil :: Scale ( m_Clipboard , fScale ); break ;
case expand_3_2 : NoteDataUtil :: Scale ( m_Clipboard , fScale ); break ;
case expand_2x : NoteDataUtil :: Scale ( m_Clipboard , fScale ); break ;
}
int iOldClipboardRow = m_NoteFieldEdit . m_iEndMarker - m_NoteFieldEdit . m_iBeginMarker ;
int iNewClipboardRow = lrintf ( iOldClipboardRow * fScale );
int iDeltaRows = iNewClipboardRow - iOldClipboardRow ;
int iNewClipboardEndRow = m_NoteFieldEdit . m_iBeginMarker + iNewClipboardRow ;
if ( iDeltaRows > 0 )
NoteDataUtil :: InsertRows ( m_NoteDataEdit , m_NoteFieldEdit . m_iBeginMarker , iDeltaRows );
else
NoteDataUtil :: DeleteRows ( m_NoteDataEdit , m_NoteFieldEdit . m_iBeginMarker , - iDeltaRows );
m_pSong -> m_Timing . ScaleRegion ( fScale , m_NoteFieldEdit . m_iBeginMarker , m_NoteFieldEdit . m_iEndMarker );
HandleAreaMenuChoice ( paste_at_begin_marker );
const vector < Steps *> sIter = m_pSong -> GetAllSteps ();
RString sTempStyle , sTempDiff ;
for ( unsigned i = 0 ; i < sIter . size (); i ++ )
{
if ( sIter [ i ] -> IsAutogen () )
continue ;
2010-03-01 00:44:39 -06:00
// XXX: Edits are distinguished by description.
// Compare vs m_pSteps.
2010-01-26 21:00:30 -06:00
if ( ( sIter [ i ] -> m_StepsType == GAMESTATE -> m_pCurSteps [ PLAYER_1 ] -> m_StepsType ) &&
( sIter [ i ] -> GetDifficulty () == GAMESTATE -> m_pCurSteps [ PLAYER_1 ] -> GetDifficulty ()) )
continue ;
NoteData ndTemp ;
sIter [ i ] -> GetNoteData ( ndTemp );
NoteDataUtil :: ScaleRegion ( ndTemp , fScale , m_NoteFieldEdit . m_iBeginMarker , m_NoteFieldEdit . m_iEndMarker );
sIter [ i ] -> SetNoteData ( ndTemp );
}
m_NoteFieldEdit . m_iEndMarker = iNewClipboardEndRow ;
float fOldBPM = m_pSong -> GetBPMAtBeat ( NoteRowToBeat ( m_NoteFieldEdit . m_iBeginMarker ) );
float fNewBPM = fOldBPM * fScale ;
m_pSong -> m_Timing . SetBPMAtRow ( m_NoteFieldEdit . m_iBeginMarker , fNewBPM );
m_pSong -> m_Timing . SetBPMAtRow ( iNewClipboardEndRow , fOldBPM );
}
break ;
case play :
ASSERT ( m_NoteFieldEdit . m_iBeginMarker !=- 1 && m_NoteFieldEdit . m_iEndMarker !=- 1 );
m_iStartPlayingAt = m_NoteFieldEdit . m_iBeginMarker ;
m_iStopPlayingAt = m_NoteFieldEdit . m_iEndMarker ;
TransitionEditState ( STATE_PLAYING );
break ;
case record :
ASSERT ( m_NoteFieldEdit . m_iBeginMarker !=- 1 && m_NoteFieldEdit . m_iEndMarker !=- 1 );
m_iStartPlayingAt = m_NoteFieldEdit . m_iBeginMarker ;
m_iStopPlayingAt = m_NoteFieldEdit . m_iEndMarker ;
TransitionEditState ( STATE_RECORDING );
break ;
case insert_and_shift :
NoteDataUtil :: InsertRows ( m_NoteDataEdit , BeatToNoteRow ( GAMESTATE -> m_fSongBeat ), BeatToNoteRow ( 1 ) );
break ;
case delete_and_shift :
NoteDataUtil :: DeleteRows ( m_NoteDataEdit , BeatToNoteRow ( GAMESTATE -> m_fSongBeat ), BeatToNoteRow ( 1 ) );
break ;
case shift_pauses_forward :
m_pSong -> m_Timing . InsertRows ( BeatToNoteRow ( GAMESTATE -> m_fSongBeat ), BeatToNoteRow ( 1 ) );
break ;
case shift_pauses_backward :
m_pSong -> m_Timing . DeleteRows ( BeatToNoteRow ( GAMESTATE -> m_fSongBeat ), BeatToNoteRow ( 1 ) );
break ;
case convert_to_pause :
{
ASSERT ( m_NoteFieldEdit . m_iBeginMarker !=- 1 && m_NoteFieldEdit . m_iEndMarker !=- 1 );
float fMarkerStart = m_pSong -> m_Timing . GetElapsedTimeFromBeat ( NoteRowToBeat ( m_NoteFieldEdit . m_iBeginMarker ) );
float fMarkerEnd = m_pSong -> m_Timing . GetElapsedTimeFromBeat ( NoteRowToBeat ( m_NoteFieldEdit . m_iEndMarker ) );
// The length of the stop segment we're going to create. This includes time spent in any
// stops in the selection, which will be deleted and subsumed into the new stop.
float fStopLength = fMarkerEnd - fMarkerStart ;
// be sure not to clobber the row at the start - a row at the end
// can be dropped safely, though
NoteDataUtil :: DeleteRows ( m_NoteDataEdit ,
m_NoteFieldEdit . m_iBeginMarker + 1 ,
m_NoteFieldEdit . m_iEndMarker - m_NoteFieldEdit . m_iBeginMarker
);
m_pSong -> m_Timing . DeleteRows ( m_NoteFieldEdit . m_iBeginMarker ,
m_NoteFieldEdit . m_iEndMarker - m_NoteFieldEdit . m_iBeginMarker );
m_pSong -> m_Timing . SetStopAtRow ( m_NoteFieldEdit . m_iBeginMarker , fStopLength );
m_NoteFieldEdit . m_iBeginMarker = - 1 ;
m_NoteFieldEdit . m_iEndMarker = - 1 ;
break ;
}
case convert_pause_to_beat :
{
2011-02-12 17:57:27 -05:00
// TODO: Convert both Delays and Stops at once.
float fStopSeconds = m_pSong -> m_Timing . GetStopAtRow ( BeatToNoteRow ( GAMESTATE -> m_fSongBeat ) );
2010-01-26 21:00:30 -06:00
m_pSong -> m_Timing . SetStopAtBeat ( GAMESTATE -> m_fSongBeat , 0 );
float fStopBeats = fStopSeconds * m_pSong -> GetBPMAtBeat ( GAMESTATE -> m_fSongBeat ) / 60 ;
// don't move the step from where it is, just move everything later
NoteDataUtil :: InsertRows ( m_NoteDataEdit , BeatToNoteRow ( GAMESTATE -> m_fSongBeat ) + 1 , BeatToNoteRow ( fStopBeats ) );
m_pSong -> m_Timing . InsertRows ( BeatToNoteRow ( GAMESTATE -> m_fSongBeat ) + 1 , BeatToNoteRow ( fStopSeconds ) );
}
break ;
case undo :
Undo ();
break ;
};
if ( bSaveUndo )
CheckNumberOfNotesAndUndo ();
}
static LocalizedString ENTER_NEW_DESCRIPTION ( "ScreenEdit" , "Enter a new description." );
2011-02-14 23:05:52 -06:00
static LocalizedString ENTER_NEW_CHART_STYLE ( "ScreenEdit" , "Enter a new chart style." );
2011-02-11 01:51:01 -05:00
static LocalizedString ENTER_NEW_STEP_AUTHOR ( "ScreenEdit" , "Enter the author who made this step pattern." );
2010-01-26 21:00:30 -06:00
void ScreenEdit :: HandleStepsInformationChoice ( StepsInformationChoice c , const vector < int > & iAnswers )
{
Steps * pSteps = GAMESTATE -> m_pCurSteps [ PLAYER_1 ];
Difficulty dc = ( Difficulty ) iAnswers [ difficulty ];
pSteps -> SetDifficulty ( dc );
int iMeter = iAnswers [ meter ] + 1 ;
pSteps -> SetMeter ( iMeter );
switch ( c )
{
case description :
// todo: Call a screen with class ScreenTextEntry instead. -aj
ScreenTextEntry :: TextEntry (
SM_None ,
ENTER_NEW_DESCRIPTION ,
m_pSteps -> GetDescription (),
( dc == Difficulty_Edit ) ? MAX_EDIT_STEPS_DESCRIPTION_LENGTH : 255 ,
SongUtil :: ValidateCurrentStepsDescription ,
ChangeDescription ,
NULL
);
break ;
2011-02-14 23:05:52 -06:00
case chartstyle :
ScreenTextEntry :: TextEntry (
SM_None ,
ENTER_NEW_CHART_STYLE ,
m_pSteps -> GetChartStyle (),
255 ,
NULL ,
ChangeChartStyle ,
NULL
);
break ;
2011-02-11 01:51:01 -05:00
case step_credit :
ScreenTextEntry :: TextEntry (
SM_None ,
ENTER_NEW_STEP_AUTHOR ,
m_pSteps -> GetCredit (),
255 ,
SongUtil :: ValidateCurrentStepsCredit ,
ChangeStepCredit ,
NULL
);
break ;
2010-01-26 21:00:30 -06:00
}
}
static LocalizedString ENTER_MAIN_TITLE ( "ScreenEdit" , "Enter a new main title." );
static LocalizedString ENTER_SUB_TITLE ( "ScreenEdit" , "Enter a new sub title." );
static LocalizedString ENTER_ARTIST ( "ScreenEdit" , "Enter a new artist." );
2010-07-27 21:53:40 -05:00
static LocalizedString ENTER_GENRE ( "ScreenEdit" , "Enter a new genre." );
2010-01-26 21:00:30 -06:00
static LocalizedString ENTER_CREDIT ( "ScreenEdit" , "Enter a new credit." );
static LocalizedString ENTER_MAIN_TITLE_TRANSLIT ( "ScreenEdit" , "Enter a new main title transliteration." );
static LocalizedString ENTER_SUB_TITLE_TRANSLIT ( "ScreenEdit" , "Enter a new sub title transliteration." );
static LocalizedString ENTER_ARTIST_TRANSLIT ( "ScreenEdit" , "Enter a new artist transliteration." );
static LocalizedString ENTER_LAST_BEAT_HINT ( "ScreenEdit" , "Enter a new last beat hint." );
void ScreenEdit :: HandleSongInformationChoice ( SongInformationChoice c , const vector < int > & iAnswers )
{
Song * pSong = GAMESTATE -> m_pCurSong ;
// todo: Call a screen with class ScreenTextEntry instead.
// multiple times in this section, so I'm only saying it here. -aj
switch ( c )
{
DEFAULT_FAIL ( c );
case main_title :
ScreenTextEntry :: TextEntry ( SM_None , ENTER_MAIN_TITLE , pSong -> m_sMainTitle , 100 , NULL , ChangeMainTitle , NULL );
break ;
case sub_title :
ScreenTextEntry :: TextEntry ( SM_None , ENTER_SUB_TITLE , pSong -> m_sSubTitle , 100 , NULL , ChangeSubTitle , NULL );
break ;
case artist :
ScreenTextEntry :: TextEntry ( SM_None , ENTER_ARTIST , pSong -> m_sArtist , 100 , NULL , ChangeArtist , NULL );
break ;
2010-07-27 21:53:40 -05:00
case genre :
ScreenTextEntry :: TextEntry ( SM_None , ENTER_GENRE , pSong -> m_sGenre , 100 , NULL , ChangeGenre , NULL );
break ;
2010-01-26 21:00:30 -06:00
case credit :
ScreenTextEntry :: TextEntry ( SM_None , ENTER_CREDIT , pSong -> m_sCredit , 100 , NULL , ChangeCredit , NULL );
break ;
case main_title_transliteration :
ScreenTextEntry :: TextEntry ( SM_None , ENTER_MAIN_TITLE_TRANSLIT , pSong -> m_sMainTitleTranslit , 100 , NULL , ChangeMainTitleTranslit , NULL );
break ;
case sub_title_transliteration :
ScreenTextEntry :: TextEntry ( SM_None , ENTER_SUB_TITLE_TRANSLIT , pSong -> m_sSubTitleTranslit , 100 , NULL , ChangeSubTitleTranslit , NULL );
break ;
case artist_transliteration :
ScreenTextEntry :: TextEntry ( SM_None , ENTER_ARTIST_TRANSLIT , pSong -> m_sArtistTranslit , 100 , NULL , ChangeArtistTranslit , NULL );
break ;
case last_beat_hint :
ScreenTextEntry :: TextEntry ( SM_None , ENTER_LAST_BEAT_HINT , ssprintf ( "%.5f" , pSong -> m_fSpecifiedLastBeat ), 20 , ScreenTextEntry :: FloatValidate , ChangeLastBeatHint , NULL );
};
}
2011-01-18 00:49:03 -05:00
static LocalizedString ENTER_BPM_VALUE ( "ScreenEdit" , "Enter a new BPM value." );
static LocalizedString ENTER_STOP_VALUE ( "ScreenEdit" , "Enter a new Stop value." );
static LocalizedString ENTER_DELAY_VALUE ( "ScreenEdit" , "Enter a new Delay value." );
static LocalizedString ENTER_TIME_SIGNATURE_NUMERATOR_VALUE ( "ScreenEdit" , "Enter a new Time Signature numerator value." );
static LocalizedString ENTER_TIME_SIGNATURE_DENOMINATOR_VALUE ( "ScreenEdit" , "Enter a new Time Signature denominator value." );
2011-01-18 11:49:27 -05:00
static LocalizedString ENTER_TICKCOUNT_VALUE ( "ScreenEdit" , "Enter a new Tickcount value." );
2011-03-05 01:44:58 -05:00
static LocalizedString ENTER_COMBO_VALUE ( "ScreenEdit" , "Enter a new Combo value." );
2011-01-18 00:49:03 -05:00
void ScreenEdit :: HandleTimingDataInformationChoice ( TimingDataInformationChoice c , const vector < int > & iAnswers )
{
switch ( c )
{
DEFAULT_FAIL ( c );
case bpm :
// todo: Call a screen with class ScreenTextEntry instead. -aj
ScreenTextEntry :: TextEntry (
SM_BackFromBPMChange ,
ENTER_BPM_VALUE ,
ssprintf ( "%.4f" , m_pSong -> GetBPMAtBeat ( GAMESTATE -> m_fSongBeat ) ),
10
);
break ;
case stop :
// todo: Call a screen with class ScreenTextEntry instead. -aj
ScreenTextEntry :: TextEntry (
SM_BackFromStopChange ,
ENTER_STOP_VALUE ,
2011-02-12 17:57:27 -05:00
ssprintf ( "%.4f" , m_pSong -> m_Timing . GetStopAtRow ( BeatToNoteRow ( GAMESTATE -> m_fSongBeat ) ) ),
2011-01-18 00:49:03 -05:00
10
);
break ;
case delay :
// todo: Call a screen with class ScreenTextEntry instead. -aj
ScreenTextEntry :: TextEntry (
SM_BackFromDelayChange ,
ENTER_DELAY_VALUE ,
2011-02-12 17:57:27 -05:00
ssprintf ( "%.4f" , m_pSong -> m_Timing . GetDelayAtRow ( BeatToNoteRow ( GAMESTATE -> m_fSongBeat ) ) ),
2011-01-18 00:49:03 -05:00
10
);
break ;
case time_signature_numerator :
ScreenTextEntry :: TextEntry (
SM_BackFromTimeSignatureNumeratorChange ,
ENTER_TIME_SIGNATURE_NUMERATOR_VALUE ,
ssprintf ( "%d" , m_pSong -> m_Timing . GetTimeSignatureSegmentAtBeat ( GAMESTATE -> m_fSongBeat ). m_iNumerator ),
3
);
break ;
case time_signature_denominator :
ScreenTextEntry :: TextEntry (
SM_BackFromTimeSignatureDenominatorChange ,
ENTER_TIME_SIGNATURE_DENOMINATOR_VALUE ,
ssprintf ( "%d" , m_pSong -> m_Timing . GetTimeSignatureSegmentAtBeat ( GAMESTATE -> m_fSongBeat ). m_iDenominator ),
3
);
break ;
2011-01-18 11:49:27 -05:00
case tickcount :
ScreenTextEntry :: TextEntry (
SM_BackFromTickcountChange ,
ENTER_TICKCOUNT_VALUE ,
ssprintf ( "%d" , m_pSong -> m_Timing . GetTickcountAtBeat ( GAMESTATE -> m_fSongBeat ) ),
2
);
break ;
2011-03-05 01:44:58 -05:00
case combo :
ScreenTextEntry :: TextEntry (
SM_BackFromComboChange ,
ENTER_COMBO_VALUE ,
ssprintf ( "%d" , m_pSong -> m_Timing . GetComboAtBeat ( GAMESTATE -> m_fSongBeat ) ),
4
);
break ;
2011-01-18 00:49:03 -05:00
}
}
2010-01-26 21:00:30 -06:00
void ScreenEdit :: HandleBGChangeChoice ( BGChangeChoice c , const vector < int > & iAnswers )
{
BackgroundChange newChange ;
FOREACH ( BackgroundChange , m_pSong -> GetBackgroundChanges ( g_CurrentBGChangeLayer ), iter )
{
if ( iter -> m_fStartBeat == GAMESTATE -> m_fSongBeat )
{
newChange = * iter ;
// delete the old change. We'll add a new one below.
m_pSong -> GetBackgroundChanges ( g_CurrentBGChangeLayer ). erase ( iter );
break ;
}
}
newChange . m_fStartBeat = GAMESTATE -> m_fSongBeat ;
newChange . m_fRate = StringToFloat ( g_BackgroundChange . rows [ rate ]. choices [ iAnswers [ rate ]] ) / 100.f ;
newChange . m_sTransition = iAnswers [ transition ] ? g_BackgroundChange . rows [ transition ]. choices [ iAnswers [ transition ]] : RString ();
newChange . m_def . m_sEffect = iAnswers [ effect ] ? g_BackgroundChange . rows [ effect ]. choices [ iAnswers [ effect ]] : RString ();
newChange . m_def . m_sColor1 = iAnswers [ color1 ] ? g_BackgroundChange . rows [ color1 ]. choices [ iAnswers [ color1 ]] : RString ();
newChange . m_def . m_sColor2 = iAnswers [ color2 ] ? g_BackgroundChange . rows [ color2 ]. choices [ iAnswers [ color2 ]] : RString ();
switch ( iAnswers [ file1_type ] )
{
DEFAULT_FAIL ( iAnswers [ file1_type ] );
case none : newChange . m_def . m_sFile1 = "" ; break ;
case dynamic_random : newChange . m_def . m_sFile1 = RANDOM_BACKGROUND_FILE ; break ;
case baked_random : newChange . m_def . m_sFile1 = GetOneBakedRandomFile ( m_pSong ); break ;
case song_bganimation :
case song_movie :
case song_bitmap :
case global_bganimation :
case global_movie :
case global_movie_song_group :
case global_movie_song_group_and_genre :
{
BGChangeChoice row1 = ( BGChangeChoice )( file1_song_bganimation + iAnswers [ file1_type ]);
newChange . m_def . m_sFile1 = g_BackgroundChange . rows [ row1 ]. choices . empty () ? "" : g_BackgroundChange . rows [ row1 ]. choices [ iAnswers [ row1 ]];
}
break ;
}
switch ( iAnswers [ file2_type ] )
{
DEFAULT_FAIL ( iAnswers [ file2_type ]);
case none : newChange . m_def . m_sFile2 = "" ; break ;
case dynamic_random : newChange . m_def . m_sFile2 = RANDOM_BACKGROUND_FILE ; break ;
case baked_random : newChange . m_def . m_sFile2 = GetOneBakedRandomFile ( m_pSong ); break ;
case song_bganimation :
case song_movie :
case song_bitmap :
case global_bganimation :
case global_movie :
case global_movie_song_group :
case global_movie_song_group_and_genre :
{
BGChangeChoice row2 = ( BGChangeChoice )( file2_song_bganimation + iAnswers [ file2_type ]);
newChange . m_def . m_sFile2 = g_BackgroundChange . rows [ row2 ]. choices . empty () ? "" : g_BackgroundChange . rows [ row2 ]. choices [ iAnswers [ row2 ]];
}
break ;
}
if ( c == delete_change || newChange . m_def . m_sFile1 . empty () )
{
// don't add
}
else
{
m_pSong -> AddBackgroundChange ( g_CurrentBGChangeLayer , newChange );
}
g_CurrentBGChangeLayer = BACKGROUND_LAYER_Invalid ;
}
void ScreenEdit :: SetupCourseAttacks ()
{
/* 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 [ PLAYER_1 ] -> m_fLastDrawnBeat = - 100 ;
// Put course options into effect.
GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_ModsToApply . clear ();
GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> RemoveActiveAttacks ();
if ( GAMESTATE -> m_pCurCourse )
{
AttackArray Attacks ;
if ( EDIT_MODE == EditMode_CourseMods )
{
Attacks = GAMESTATE -> m_pCurCourse -> m_vEntries [ GAMESTATE -> m_iEditCourseEntryIndex ]. attacks ;
}
else
{
GAMESTATE -> m_pCurCourse -> RevertFromDisk (); // Remove this and have a separate reload key?
for ( unsigned e = 0 ; e < GAMESTATE -> m_pCurCourse -> m_vEntries . size (); ++ e )
{
if ( GAMESTATE -> m_pCurCourse -> m_vEntries [ e ]. songID . ToSong () != m_pSong )
continue ;
Attacks = GAMESTATE -> m_pCurCourse -> m_vEntries [ e ]. attacks ;
break ;
}
}
FOREACH ( Attack , Attacks , attack )
GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> LaunchAttack ( * attack );
}
GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> RebuildPlayerOptionsFromActiveAttacks ();
}
void ScreenEdit :: CopyToLastSave ()
{
ASSERT ( GAMESTATE -> m_pCurSong );
ASSERT ( GAMESTATE -> m_pCurSteps [ PLAYER_1 ] );
m_SongLastSave = * GAMESTATE -> m_pCurSong ;
m_vStepsLastSave . clear ();
const vector < Steps *> & vSteps = GAMESTATE -> m_pCurSong -> GetStepsByStepsType ( GAMESTATE -> m_pCurSteps [ PLAYER_1 ] -> m_StepsType );
FOREACH_CONST ( Steps * , vSteps , it )
m_vStepsLastSave . push_back ( ** it );
}
void ScreenEdit :: CopyFromLastSave ()
{
// We are assuming two things here:
// 1) No steps can be created by ScreenEdit
// 2) No steps can be deleted by ScreenEdit (except possibly when we exit)
* GAMESTATE -> m_pCurSong = m_SongLastSave ;
const vector < Steps *> & vSteps = GAMESTATE -> m_pCurSong -> GetStepsByStepsType ( GAMESTATE -> m_pCurSteps [ PLAYER_1 ] -> m_StepsType );
ASSERT_M ( vSteps . size () == m_vStepsLastSave . size (), ssprintf ( "Step sizes don't match: %d, %d" , int ( vSteps . size ()), int ( m_vStepsLastSave . size ())) );
for ( unsigned i = 0 ; i < vSteps . size (); ++ i )
* vSteps [ i ] = m_vStepsLastSave [ i ];
}
void ScreenEdit :: RevertFromDisk ()
{
ASSERT ( GAMESTATE -> m_pCurSteps [ PLAYER_1 ] );
StepsID id ;
id . FromSteps ( GAMESTATE -> m_pCurSteps [ PLAYER_1 ] );
ASSERT ( id . IsValid () );
GAMESTATE -> m_pCurSong -> ReloadFromSongDir ( GAMESTATE -> m_pCurSong -> GetSongDir () );
Steps * pNewSteps = id . ToSteps ( GAMESTATE -> m_pCurSong , true );
if ( ! pNewSteps )
{
// If the Steps we were currently editing vanished when we did the revert,
// put a blank Steps in its place. Note that this does not have to be the
// work of someone maliciously changing the simfile; it could happen to
// someone editing a new stepchart and reverting from disk, for example.
pNewSteps = new Steps ();
pNewSteps -> CreateBlank ( id . GetStepsType () );
pNewSteps -> SetDifficulty ( id . GetDifficulty () );
GAMESTATE -> m_pCurSong -> AddSteps ( pNewSteps );
}
GAMESTATE -> m_pCurSteps [ PLAYER_1 ]. Set ( pNewSteps );
m_pSteps = pNewSteps ;
CopyToLastSave ();
SetDirty ( false );
SONGMAN -> Invalidate ( GAMESTATE -> m_pCurSong );
}
void ScreenEdit :: SaveUndo ()
{
m_bHasUndo = true ;
m_Undo . CopyAll ( m_NoteDataEdit );
}
static LocalizedString UNDO ( "ScreenEdit" , "Undo" );
static LocalizedString CANT_UNDO ( "ScreenEdit" , "Can't undo - no undo data." );
void ScreenEdit :: Undo ()
{
if ( m_bHasUndo )
{
swap ( m_Undo , m_NoteDataEdit );
SCREENMAN -> SystemMessage ( UNDO );
}
else
{
SCREENMAN -> SystemMessage ( CANT_UNDO );
SCREENMAN -> PlayInvalidSound ();
}
}
void ScreenEdit :: ClearUndo ()
{
m_bHasUndo = false ;
m_Undo . ClearAll ();
}
static LocalizedString CREATES_MORE_THAN_NOTES ( "ScreenEdit" , "This change creates more than %d notes in a measure." );
static LocalizedString MORE_THAN_NOTES ( "ScreenEdit" , "More than %d notes per measure is not allowed. This change has been reverted." );
static LocalizedString CREATES_NOTES_PAST_END ( "ScreenEdit" , "This change creates notes past the end of the music and is not allowed." );
static LocalizedString CHANGE_REVERTED ( "ScreenEdit" , "The change has been reverted." );
void ScreenEdit :: CheckNumberOfNotesAndUndo ()
{
if ( EDIT_MODE . GetValue () != EditMode_Home )
return ;
2011-01-09 17:06:40 -05:00
TimeSignatureSegment curTime = GAMESTATE -> m_pCurSong -> m_Timing . GetTimeSignatureSegmentAtBeat ( GAMESTATE -> m_fSongBeat );
int rowsPerMeasure = curTime . m_iDenominator * curTime . m_iNumerator ;
2010-01-26 21:00:30 -06:00
2011-01-09 17:06:40 -05:00
for ( int row = 0 ; row <= m_NoteDataEdit . GetLastRow (); row += rowsPerMeasure )
2010-01-26 21:00:30 -06:00
{
int iNumNotesThisMeasure = 0 ;
2011-01-09 17:06:40 -05:00
FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE ( m_NoteDataEdit , r , row , row + rowsPerMeasure )
2010-01-26 21:00:30 -06:00
iNumNotesThisMeasure += m_NoteDataEdit . GetNumTapNonEmptyTracks ( r );
if ( iNumNotesThisMeasure > MAX_NOTES_PER_MEASURE )
{
Undo ();
m_bHasUndo = false ;
RString sError = ssprintf ( CREATES_MORE_THAN_NOTES . GetValue () + " \n\n " + MORE_THAN_NOTES . GetValue (), MAX_NOTES_PER_MEASURE , MAX_NOTES_PER_MEASURE );
ScreenPrompt :: Prompt ( SM_None , sError );
return ;
}
}
if ( GAMESTATE -> m_pCurSteps [ 0 ] -> IsAnEdit () )
{
/* Check that the action didn't push notes any farther past the last
* measure. This blocks Insert Beat from pushing past the end, but allows
* Delete Beat to pull back the notes that are already past the end.
*/
float fNewLastBeat = m_NoteDataEdit . GetLastBeat ();
bool bLastBeatIncreased = fNewLastBeat > m_Undo . GetLastBeat ();
bool bPassedTheEnd = fNewLastBeat > GetMaximumBeatForNewNote ();
if ( bLastBeatIncreased && bPassedTheEnd )
{
Undo ();
m_bHasUndo = false ;
RString sError = CREATES_NOTES_PAST_END . GetValue () + " \n\n " + CHANGE_REVERTED . GetValue ();
ScreenPrompt :: Prompt ( SM_None , sError );
return ;
}
}
}
float ScreenEdit :: GetMaximumBeatForNewNote () const
{
switch ( EDIT_MODE . GetValue () )
{
DEFAULT_FAIL ( EDIT_MODE . GetValue () );
case EditMode_Practice :
case EditMode_CourseMods :
case EditMode_Home :
{
float fEndBeat = GAMESTATE -> m_pCurSong -> m_fLastBeat ;
/* Round up to the next measure end. Some songs end on weird beats
* mid-measure, and it's odd to have movement capped to these weird
* beats. */
2011-01-09 17:06:40 -05:00
int beatsPerMeasure = GAMESTATE -> m_pCurSong -> m_Timing . GetTimeSignatureSegmentAtBeat ( GAMESTATE -> m_fSongBeat ). m_iNumerator ;
fEndBeat += beatsPerMeasure ;
fEndBeat = ftruncf ( fEndBeat , ( float ) beatsPerMeasure );
2010-01-26 21:00:30 -06:00
return fEndBeat ;
}
case EditMode_Full :
return NoteRowToBeat ( MAX_NOTE_ROW );
}
}
float ScreenEdit :: GetMaximumBeatForMoving () const
{
float fEndBeat = GetMaximumBeatForNewNote ();
/* Jump to GetLastBeat even if it's past m_pCurSong->m_fLastBeat
* so that users can delete garbage steps past then end that they have
* have inserted in a text editor. Once they delete all steps on
* GetLastBeat() and move off of that beat, they won't be able to return. */
fEndBeat = max ( fEndBeat , m_NoteDataEdit . GetLastBeat () );
return fEndBeat ;
}
struct EditHelpLine
{
const char * szEnglishDescription ;
vector < EditButton > veb ;
EditHelpLine (
const char * _szEnglishDescription ,
EditButton eb0 ,
EditButton eb1 = EditButton_Invalid ,
EditButton eb2 = EditButton_Invalid ,
EditButton eb3 = EditButton_Invalid ,
EditButton eb4 = EditButton_Invalid ,
EditButton eb5 = EditButton_Invalid ,
EditButton eb6 = EditButton_Invalid ,
EditButton eb7 = EditButton_Invalid ,
EditButton eb8 = EditButton_Invalid ,
EditButton eb9 = EditButton_Invalid )
{
szEnglishDescription = _szEnglishDescription ;
#define PUSH_IF_VALID( x ) if( x != EditButton_Invalid ) veb.push_back( x );
PUSH_IF_VALID ( eb0 );
PUSH_IF_VALID ( eb1 );
PUSH_IF_VALID ( eb2 );
PUSH_IF_VALID ( eb3 );
PUSH_IF_VALID ( eb4 );
PUSH_IF_VALID ( eb5 );
PUSH_IF_VALID ( eb6 );
PUSH_IF_VALID ( eb7 );
PUSH_IF_VALID ( eb8 );
PUSH_IF_VALID ( eb9 );
#undef PUSH_IF_VALID
}
};
static const EditHelpLine g_EditHelpLines [] =
{
EditHelpLine ( "Move cursor" , EDIT_BUTTON_SCROLL_UP_LINE , EDIT_BUTTON_SCROLL_DOWN_LINE ),
EditHelpLine ( "Jump measure" , EDIT_BUTTON_SCROLL_UP_PAGE , EDIT_BUTTON_SCROLL_DOWN_PAGE ),
EditHelpLine ( "Jump measure" , EDIT_BUTTON_SCROLL_PREV_MEASURE , EDIT_BUTTON_SCROLL_NEXT_MEASURE ),
EditHelpLine ( "Select region" , EDIT_BUTTON_SCROLL_SELECT ),
EditHelpLine ( "Jump to first/last beat" , EDIT_BUTTON_SCROLL_HOME , EDIT_BUTTON_SCROLL_END ),
EditHelpLine ( "Change zoom" , EDIT_BUTTON_SCROLL_SPEED_UP , EDIT_BUTTON_SCROLL_SPEED_DOWN ),
EditHelpLine ( "Play" , EDIT_BUTTON_PLAY_SELECTION ),
EditHelpLine ( "Play current beat to end" , EDIT_BUTTON_PLAY_FROM_CURSOR ),
EditHelpLine ( "Play whole song" , EDIT_BUTTON_PLAY_FROM_START ),
EditHelpLine ( "Record" , EDIT_BUTTON_RECORD_SELECTION ),
EditHelpLine ( "Set selection" , EDIT_BUTTON_LAY_SELECT ),
EditHelpLine ( "Next/prev steps of same StepsType" , EDIT_BUTTON_OPEN_NEXT_STEPS , EDIT_BUTTON_OPEN_PREV_STEPS ),
EditHelpLine ( "Decrease/increase BPM at cur beat" , EDIT_BUTTON_BPM_DOWN , EDIT_BUTTON_BPM_UP ),
EditHelpLine ( "Decrease/increase stop at cur beat" , EDIT_BUTTON_STOP_DOWN , EDIT_BUTTON_STOP_UP ),
2010-03-14 19:46:05 -05:00
//EditHelpLine( "Decrease/increase delay at cur beat", EDIT_BUTTON_DELAY_DOWN, EDIT_BUTTON_DELAY_UP ),
2010-01-26 21:00:30 -06:00
EditHelpLine ( "Decrease/increase music offset" , EDIT_BUTTON_OFFSET_DOWN , EDIT_BUTTON_OFFSET_UP ),
EditHelpLine ( "Decrease/increase sample music start" , EDIT_BUTTON_SAMPLE_START_DOWN , EDIT_BUTTON_SAMPLE_START_UP ),
EditHelpLine ( "Decrease/increase sample music length" , EDIT_BUTTON_SAMPLE_LENGTH_DOWN , EDIT_BUTTON_SAMPLE_LENGTH_UP ),
EditHelpLine ( "Play sample music" , EDIT_BUTTON_PLAY_SAMPLE_MUSIC ),
EditHelpLine ( "Add/Edit Background Change" , EDIT_BUTTON_OPEN_BGCHANGE_LAYER1_MENU ),
EditHelpLine ( "Insert beat and shift down" , EDIT_BUTTON_INSERT ),
EditHelpLine ( "Shift BPM changes and stops down one beat" , EDIT_BUTTON_INSERT_SHIFT_PAUSES ),
EditHelpLine ( "Delete beat and shift up" , EDIT_BUTTON_DELETE ),
EditHelpLine ( "Shift BPM changes and stops up one beat" , EDIT_BUTTON_DELETE_SHIFT_PAUSES ),
2011-03-13 20:03:54 -04:00
EditHelpLine ( "Cycle between tap notes" , EDIT_BUTTON_CYCLE_TAP_LEFT , EDIT_BUTTON_CYCLE_TAP_RIGHT ),
2010-01-26 21:00:30 -06:00
EditHelpLine ( "Add to/remove from right half" , EDIT_BUTTON_RIGHT_SIDE ),
2011-01-16 02:13:06 -05:00
EditHelpLine ( "Switch player (Routine only)" , EDIT_BUTTON_SWITCH_PLAYERS ),
2010-01-26 21:00:30 -06:00
};
static bool IsMapped ( EditButton eb , const MapEditToDI & editmap )
{
for ( int s = 0 ; s < NUM_EDIT_TO_DEVICE_SLOTS ; s ++ )
{
DeviceInput diPress = editmap . button [ eb ][ s ];
if ( diPress . IsValid () )
return true ;
}
return false ;
}
static void ProcessKeyName ( RString & s )
{
s . Replace ( "Key_" , "" );
}
static void ProcessKeyNames ( vector < RString > & vs )
{
FOREACH ( RString , vs , s )
ProcessKeyName ( * s );
sort ( vs . begin (), vs . end () );
vector < RString >:: iterator toDelete = unique ( vs . begin (), vs . end () );
vs . erase ( toDelete , vs . end ());
}
static RString GetDeviceButtonsLocalized ( const vector < EditButton > & veb , const MapEditToDI & editmap )
{
vector < RString > vsPress ;
vector < RString > vsHold ;
FOREACH_CONST ( EditButton , veb , eb )
{
if ( ! IsMapped ( * eb , editmap ) )
continue ;
for ( int s = 0 ; s < NUM_EDIT_TO_DEVICE_SLOTS ; s ++ )
{
DeviceInput diPress = editmap . button [ * eb ][ s ];
DeviceInput diHold = editmap . hold [ * eb ][ s ];
if ( diPress . IsValid () )
vsPress . push_back ( Capitalize ( INPUTMAN -> GetLocalizedInputString ( diPress )) );
if ( diHold . IsValid () )
vsHold . push_back ( Capitalize ( INPUTMAN -> GetLocalizedInputString ( diHold )) );
}
}
ProcessKeyNames ( vsPress );
ProcessKeyNames ( vsHold );
RString s = join ( "/" , vsPress );
if ( ! vsHold . empty () )
s = join ( "/" , vsHold ) + " + " + s ;
return s ;
}
void ScreenEdit :: DoHelp ()
{
g_EditHelp . rows . clear ();
for ( unsigned i = 0 ; i < ARRAYLEN ( g_EditHelpLines ); ++ i )
{
const EditHelpLine & hl = g_EditHelpLines [ i ];
if ( ! IsMapped ( hl . veb [ 0 ], m_EditMappingsDeviceInput ) )
continue ;
RString sButtons = GetDeviceButtonsLocalized ( hl . veb , m_EditMappingsDeviceInput );
RString sDescription = THEME -> GetString ( "EditHelpDescription" , hl . szEnglishDescription );
g_EditHelp . rows . push_back ( MenuRowDef ( - 1 , sDescription , false , EditMode_Practice , false , false , 0 , sButtons ) );
}
EditMiniMenu ( & g_EditHelp );
}
2010-12-26 00:31:46 -06:00
// lua start
#include "LuaBinding.h"
2011-03-16 21:59:46 -05:00
/** @brief Allow Lua to have access to ScreenEdit. */
2010-12-26 00:31:46 -06:00
class LunaScreenEdit : public Luna < ScreenEdit >
{
public :
DEFINE_METHOD ( GetEditState , GetEditState () )
LunaScreenEdit ()
{
ADD_METHOD ( GetEditState );
}
};
LUA_REGISTER_DERIVED_CLASS ( ScreenEdit , ScreenWithMenuElements )
2010-01-26 21:00:30 -06:00
/*
* (c) 2001-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.
*/