2011-03-17 01:43:45 -04: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"
#include "NoteTypes.h"
#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"
#include "TimingData.h"
#include "Game.h"
#include "RageSoundReader.h"
static Preference < float > g_iDefaultRecordLength ( "DefaultRecordLength" , 4 );
static Preference < bool > g_bEditorShowBGChangesPlay ( "EditorShowBGChangesPlay" , true );
2011-06-12 20:45:30 -04:00
/** @brief How long must the button be held to generate a hold in record mode? */
2011-03-17 01:43:45 -04:00
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 );
2011-06-10 03:04:47 -04:00
AutoScreenMessage ( SM_BackFromAlterMenu );
2011-03-17 01:43:45 -04:00
AutoScreenMessage ( SM_BackFromStepsInformation );
2011-07-07 17:52:30 -04:00
AutoScreenMessage ( SM_BackFromStepsData );
2011-03-17 01:43:45 -04:00
AutoScreenMessage ( SM_BackFromOptions );
AutoScreenMessage ( SM_BackFromSongInformation );
AutoScreenMessage ( SM_BackFromBGChange );
AutoScreenMessage ( SM_BackFromInsertTapAttack );
AutoScreenMessage ( SM_BackFromInsertTapAttackPlayerOptions );
2011-06-24 19:32:46 -04:00
AutoScreenMessage ( SM_BackFromInsertStepAttack );
AutoScreenMessage ( SM_BackFromInsertStepAttackPlayerOptions );
2011-03-17 01:43:45 -04:00
AutoScreenMessage ( SM_BackFromInsertCourseAttack );
AutoScreenMessage ( SM_BackFromInsertCourseAttackPlayerOptions );
AutoScreenMessage ( SM_BackFromCourseModeMenu );
AutoScreenMessage ( SM_DoRevertToLastSave );
AutoScreenMessage ( SM_DoRevertFromDisk );
AutoScreenMessage ( SM_BackFromTimingDataInformation );
2011-05-07 19:18:03 -04:00
AutoScreenMessage ( SM_BackFromDifficultyMeterChange );
2011-03-17 01:43:45 -04:00
AutoScreenMessage ( SM_BackFromBPMChange );
AutoScreenMessage ( SM_BackFromStopChange );
AutoScreenMessage ( SM_BackFromDelayChange );
2011-05-16 23:05:51 +07:00
AutoScreenMessage ( SM_BackFromTimeSignatureChange );
2011-03-17 01:43:45 -04:00
AutoScreenMessage ( SM_BackFromTickcountChange );
AutoScreenMessage ( SM_BackFromComboChange );
2011-04-05 00:35:45 -04:00
AutoScreenMessage ( SM_BackFromLabelChange );
2011-03-25 17:40:56 -04:00
AutoScreenMessage ( SM_BackFromWarpChange );
2011-05-15 15:53:20 -04:00
AutoScreenMessage ( SM_BackFromSpeedPercentChange );
AutoScreenMessage ( SM_BackFromSpeedWaitChange );
2011-05-15 23:48:03 -04:00
AutoScreenMessage ( SM_BackFromSpeedModeChange );
2011-05-25 22:44:41 +07:00
AutoScreenMessage ( SM_BackFromScrollChange );
2011-05-16 11:30:39 -04:00
AutoScreenMessage ( SM_BackFromFakeChange );
2011-05-14 00:43:06 -05:00
AutoScreenMessage ( SM_DoEraseStepTiming );
2011-03-17 01:43:45 -04:00
AutoScreenMessage ( SM_DoSaveAndExit );
AutoScreenMessage ( SM_DoExit );
AutoScreenMessage ( SM_SaveSuccessful );
AutoScreenMessage ( SM_SaveFailed );
static const char * EditStateNames [] = {
"Edit" ,
"Record" ,
"RecordPaused" ,
"Playing"
};
XToString ( EditState );
LuaXType ( EditState );
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 );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_UP_PAGE ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_SEMICOLON );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_DOWN_PAGE ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_PGDN );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_DOWN_PAGE ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_SQUOTE );
2011-06-12 20:34:23 -04:00
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_SCROLL_UP_TS ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LCTRL );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_SCROLL_UP_TS ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RCTRL );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_UP_TS ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_PGUP );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_UP_TS ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_SEMICOLON );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_SCROLL_DOWN_TS ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LCTRL );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_SCROLL_DOWN_TS ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RCTRL );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_DOWN_TS ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_PGDN );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SCROLL_DOWN_TS ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_SQUOTE );
2011-03-17 01:43:45 -04: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 );
2011-06-26 23:11:57 -04:00
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SEGMENT_NEXT ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_PERIOD );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_SEGMENT_NEXT ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LCTRL );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_SEGMENT_NEXT ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RCTRL );
2011-05-02 21:54:20 -04:00
2011-06-26 23:11:57 -04:00
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SEGMENT_PREV ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_COMMA );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_SEGMENT_PREV ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LCTRL );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_SEGMENT_PREV ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RCTRL );
2011-05-02 21:54:20 -04:00
2011-03-17 01:43:45 -04:00
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 ;
2011-06-10 03:04:47 -04:00
2011-03-17 01:43:45 -04: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 ][ 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 );
// 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 );
2011-09-25 02:31:00 -07:00
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_OPEN_COURSE_MENU ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Ch );
2011-03-17 01:43:45 -04:00
// 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 ][ 0 ] = GAME_BUTTON_START ;
return ;
case EditMode_Full :
2011-05-12 20:55:45 -04:00
// F4 = Show timing menu
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_OPEN_TIMING_MENU ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_F4 );
2011-03-17 01:43:45 -04:00
/* Don't allow F5/F6 in home mode. It breaks the "delay creation until first save" logic. */
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 );
2011-11-26 13:56:27 -05:00
2011-03-17 01:43:45 -04:00
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_DELAY_DOWN ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_F9 );
2011-11-26 13:56:27 -05:00
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_DELAY_DOWN ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LSHIFT );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_DELAY_DOWN ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RSHIFT );
2011-03-17 01:43:45 -04:00
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_DELAY_UP ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_F10 );
2011-11-26 13:56:27 -05:00
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_DELAY_UP ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LSHIFT );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_DELAY_UP ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RSHIFT );
2011-03-17 01:43:45 -04:00
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 );
2011-03-29 11:56:19 -05:00
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_PLAY_SAMPLE_MUSIC ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cl );
2011-03-17 01:43:45 -04:00
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 );
2011-06-24 19:32:46 -04:00
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_ADD_STEP_MODS ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cc );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_OPEN_STEP_ATTACK_MENU ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cv );
2011-03-17 01:43:45 -04:00
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 ;
2011-06-06 18:27:52 -04:00
default : break ;
2011-03-17 01:43:45 -04:00
}
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 );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_LAY_ROLL ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LSHIFT );
2011-05-27 12:49:42 -04:00
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_LAY_ROLL ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RSHIFT );
2011-03-19 19:28:57 -05:00
2011-03-17 01:43:45 -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 );
2011-06-26 23:11:57 -04:00
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_CYCLE_SEGMENT_LEFT ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cn );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_CYCLE_SEGMENT_LEFT ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LCTRL );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_CYCLE_SEGMENT_LEFT ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RCTRL );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_CYCLE_SEGMENT_RIGHT ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cm );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_CYCLE_SEGMENT_RIGHT ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_LCTRL );
m_EditMappingsDeviceInput . hold [ EDIT_BUTTON_CYCLE_SEGMENT_RIGHT ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_RCTRL );
2011-03-17 01:43:45 -04: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 );
2011-06-10 03:04:47 -04:00
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_OPEN_ALTER_MENU ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Ca );
2011-03-17 01:43:45 -04:00
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_OPEN_INPUT_HELP ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_F1 );
2011-03-19 19:28:57 -05:00
2011-03-17 01:43:45 -04:00
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 );
2011-03-19 19:28:57 -05:00
2011-03-17 01:43:45 -04:00
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 );
2011-03-19 19:28:57 -05:00
2011-03-17 01:43:45 -04:00
// Switch players, if it makes sense to do so.
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SWITCH_PLAYERS ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_SLASH );
2011-05-12 23:18:57 -04:00
// Allow song and step timing to be swapped.
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_SWITCH_TIMINGS ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Ct );
2011-03-19 19:28:57 -05:00
2011-07-06 13:44:25 -04:00
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_BACK ;
m_PlayMappingsMenuButton . button [ EDIT_BUTTON_RETURN_TO_EDIT ][ 1 ] = GAME_BUTTON_START ;
2011-03-17 01:43:45 -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 );
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 );
}
/* 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" ,
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 ),
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 :: 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-07-07 17:20:38 -04:00
MenuRowDef ( ScreenEdit :: edit_steps_information , "Edit steps information" , true , EditMode_Practice , true , true , 0 , NULL ),
2011-03-17 01:43:45 -04:00
MenuRowDef ( ScreenEdit :: edit_timing_data , "Edit Timing Data" , true , EditMode_Full , true , true , 0 , NULL ),
2011-07-07 17:52:30 -04:00
MenuRowDef ( ScreenEdit :: view_steps_data , "View steps data" , true , EditMode_Practice , true , true , 0 , NULL ),
2011-03-17 01:43:45 -04: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 )
);
2011-06-10 03:04:47 -04:00
static MenuDef g_AlterMenu (
"ScreenMiniMenuAlterMenu" ,
MenuRowDef ( ScreenEdit :: cut , "Cut" , true ,
EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: copy , "Copy" , true ,
EditMode_Practice , true , true , 0 , NULL ),
2011-07-26 13:55:06 -04:00
MenuRowDef ( ScreenEdit :: copy_partial_timing , "Copy Partial Timing" , true ,
EditMode_Practice , true , true , 0 , NULL ),
2011-06-10 03:04:47 -04:00
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 ,
2011-10-16 15:37:28 -04:00
EditMode_Practice , true , true , 0 , "Left" , "Right" , "Mirror" , "Backwards" , "Shuffle" , "SuperShuffle" ),
2011-06-10 03:04:47 -04:00
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 ),
2011-06-11 11:15:58 -04:00
MenuRowDef ( ScreenEdit :: preview_designation , "Designate as Music Preview" , true ,
EditMode_Full , true , true , 0 , NULL ),
2011-06-10 03:04:47 -04:00
MenuRowDef ( ScreenEdit :: convert_to_pause , "Convert selection to pause" , true ,
2011-06-10 16:43:38 -04:00
EditMode_Full , true , true , 0 , NULL ),
2011-06-10 17:03:53 -04:00
MenuRowDef ( ScreenEdit :: convert_to_delay , "Convert selection to delay" , true ,
EditMode_Full , true , true , 0 , NULL ),
2011-06-10 16:43:38 -04:00
MenuRowDef ( ScreenEdit :: convert_to_warp , "Convert selection to warp" , true ,
2011-06-10 16:52:23 -04:00
EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: convert_to_fake , "Convert selection to fake" , true ,
2011-07-04 17:30:36 -04:00
EditMode_Full , true , true , 0 , NULL ),
2011-07-07 21:41:08 -04:00
MenuRowDef ( ScreenEdit :: convert_to_attack , "Convert selection to attack" , true ,
EditMode_Full , true , true , 0 , NULL ),
2011-07-04 17:30:36 -04:00
MenuRowDef ( ScreenEdit :: routine_invert_notes , "Invert notes' player" , true ,
2011-07-04 18:15:21 -04:00
EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: routine_mirror_1_to_2 , "Mirror Player 1 to 2" , true ,
EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: routine_mirror_2_to_1 , "Mirror Player 2 to 1" , true ,
2011-06-10 16:52:23 -04:00
EditMode_Full , true , true , 0 , NULL )
2011-06-10 03:04:47 -04:00
);
2011-03-17 01:43:45 -04:00
static MenuDef g_AreaMenu (
"ScreenMiniMenuAreaMenu" ,
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 ),
2011-07-26 16:05:14 -04:00
MenuRowDef ( ScreenEdit :: paste_partial_timing_at_beat , "Paste Partial Timing at current beat" , true , EditMode_Practice , true , true , 0 , NULL ),
2011-11-27 18:33:34 -05:00
MenuRowDef ( ScreenEdit :: insert_and_shift , "Insert beat and shift down" , true , EditMode_Practice , true , true , 0 , "4th" , "8th" , "12th" , "16th" , "24th" , "32nd" , "48th" , "64th" , "192nd" ),
MenuRowDef ( ScreenEdit :: delete_and_shift , "Delete beat and shift up" , true , EditMode_Practice , true , true , 0 , "4th" , "8th" , "12th" , "16th" , "24th" , "32nd" , "48th" , "64th" , "192nd" ),
MenuRowDef ( ScreenEdit :: shift_pauses_forward , "Shift all timing changes down" , true , EditMode_Full , true , true , 0 , "4th" , "8th" , "12th" , "16th" , "24th" , "32nd" , "48th" , "64th" , "192nd" ),
MenuRowDef ( ScreenEdit :: shift_pauses_backward , "Shift all timing changes up" , true , EditMode_Full , true , true , 0 , "4th" , "8th" , "12th" , "16th" , "24th" , "32nd" , "48th" , "64th" , "192nd" ),
2011-06-10 03:04:47 -04:00
MenuRowDef ( ScreenEdit :: convert_pause_to_beat , "Convert pause to beats" , true ,
EditMode_Full , true , true , 0 , NULL ),
2011-06-24 00:50:32 -04:00
MenuRowDef ( ScreenEdit :: convert_delay_to_beat , "Convert delay to beats" , true ,
EditMode_Full , true , true , 0 , NULL ),
2011-06-30 01:23:59 -04:00
MenuRowDef ( ScreenEdit :: last_second_at_beat , "Designate last second at current beat" , true , EditMode_Full , true , true , 0 , NULL ),
2011-06-10 16:10:43 -04:00
MenuRowDef ( ScreenEdit :: undo , "Undo" , true , EditMode_Practice , true , true , 0 , NULL ),
2011-06-30 01:23:59 -04:00
MenuRowDef ( ScreenEdit :: clear_clipboard , "Clear clipboard" , true ,
2011-06-10 16:10:43 -04:00
EditMode_Practice , true , true , 0 , NULL )
2011-03-17 01:43:45 -04:00
);
static MenuDef g_StepsInformation (
"ScreenMiniMenuStepsInformation" ,
MenuRowDef ( ScreenEdit :: difficulty , "Difficulty" , true , EditMode_Practice , true , true , 0 , NULL ),
2011-05-07 19:18:03 -04:00
MenuRowDef ( ScreenEdit :: meter , "Meter" , true , EditMode_Practice , true , false , 0 , NULL ),
2011-07-07 17:52:30 -04:00
MenuRowDef ( ScreenEdit :: predict_meter , "Predicted Meter" , false , EditMode_Full , true , true , 0 , NULL ),
2011-07-07 14:20:21 -04:00
MenuRowDef ( ScreenEdit :: chartname , "Chart Name" , true , EditMode_Practice , true , true , 0 , NULL ),
2011-03-17 01:43:45 -04:00
MenuRowDef ( ScreenEdit :: description , "Description" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: chartstyle , "Chart Style" , true , EditMode_Practice , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: step_credit , "Step Author" , true , EditMode_Practice , true , true , 0 , NULL ),
2011-07-07 18:10:59 -04:00
MenuRowDef ( ScreenEdit :: step_display_bpm , "Display BPM" , true , EditMode_Full , true , true , 0 , "Actual" , "Specified" , "Random" ),
MenuRowDef ( ScreenEdit :: step_min_bpm , "Min BPM" , true , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: step_max_bpm , "Max BPM" , true , EditMode_Full , true , true , 0 , NULL )
2011-07-07 17:52:30 -04:00
);
static MenuDef g_StepsData (
"ScreenMiniMenuStepsData" ,
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 ),
2011-07-07 20:58:36 -04:00
MenuRowDef ( ScreenEdit :: rolls , "Rolls" , false , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: lifts , "Lifts" , false , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: fakes , "Fakes" , false , EditMode_Full , true , true , 0 , NULL ),
2011-07-07 17:52:30 -04:00
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 )
2011-03-17 01:43:45 -04:00
);
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 ),
MenuRowDef ( ScreenEdit :: genre , "Genre" , true , EditMode_Practice , true , true , 0 , NULL ),
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 ),
2011-06-30 01:11:38 -04:00
MenuRowDef ( ScreenEdit :: last_second_hint , "Last second hint" , true , EditMode_Full , true , true , 0 , NULL ),
2011-05-03 09:18:31 -04:00
MenuRowDef ( ScreenEdit :: preview_start , "Preview Start" , true , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: preview_length , "Preview Length" , true , EditMode_Full , true , true , 0 , NULL ),
2011-04-05 22:40:33 -04:00
MenuRowDef ( ScreenEdit :: display_bpm , "Display BPM" , true , EditMode_Full , true , true , 0 , "Actual" , "Specified" , "Random" ),
MenuRowDef ( ScreenEdit :: min_bpm , "Min BPM" , true , EditMode_Full , true , true , 0 , NULL ),
2011-05-02 01:44:14 -04:00
MenuRowDef ( ScreenEdit :: max_bpm , "Max BPM" , true , EditMode_Full , true , true , 0 , NULL )
2011-03-17 01:43:45 -04:00
);
2011-05-13 00:05:31 -04:00
static MenuDef g_TimingDataInformation (
2011-05-13 16:04:17 -04:00
"ScreenMiniMenuTimingDataInformation" ,
MenuRowDef ( ScreenEdit :: beat_0_offset , "Beat 0 Offset" , true , EditMode_Full , true , true , 0 , NULL ),
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 ),
2011-05-16 23:05:51 +07:00
MenuRowDef ( ScreenEdit :: time_signature , "Edit time signature" , true , EditMode_Full , true , true , 0 , NULL ),
2011-05-13 16:04:17 -04:00
MenuRowDef ( ScreenEdit :: label , "Edit label" , true , EditMode_Full , true , true , 0 , NULL ),
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-05-14 02:14:00 -04:00
MenuRowDef ( ScreenEdit :: warp , "Edit warp" , true , EditMode_Full , true , true , 0 , NULL ),
2011-05-15 15:53:20 -04:00
MenuRowDef ( ScreenEdit :: speed_percent , "Edit speed (percent)" , true , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: speed_wait , "Edit speed (wait)" , true , EditMode_Full , true , true , 0 , NULL ),
2011-05-15 23:48:03 -04:00
MenuRowDef ( ScreenEdit :: speed_mode , "Edit speed (mode)" , true , EditMode_Full , true , true , 0 , "Beats" , "Seconds" ),
2011-05-25 22:44:41 +07:00
MenuRowDef ( ScreenEdit :: scroll , "Edit scrolling factor" , true , EditMode_Full , true , true , 0 , NULL ),
2011-05-16 11:30:39 -04:00
MenuRowDef ( ScreenEdit :: fake , "Edit fake" , true , EditMode_Full , true , true , 0 , NULL ),
2011-07-26 13:55:06 -04:00
MenuRowDef ( ScreenEdit :: copy_full_timing , "Copy timing data" , true , EditMode_Full , true , true , 0 , NULL ),
MenuRowDef ( ScreenEdit :: paste_full_timing , "Paste timing data" , true , EditMode_Full , true , true , 0 , NULL ),
2011-05-15 15:53:20 -04:00
MenuRowDef ( ScreenEdit :: erase_step_timing , "Erase step timing" , true , EditMode_Full , true , true , 0 , NULL )
2011-03-17 01:43:45 -04: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 ),
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" ),
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" )
);
2011-07-12 21:56:17 -04:00
static MenuDef g_InsertStepAttack ( "ScreenMiniMenuInsertCourseAttack" ,
MenuRowDef ( ScreenEdit :: sa_duration , "Duration seconds" , true , EditMode_Practice , true , false , 3 , "5" , "10" , "15" , "20" , "25" , "30" , "35" , "40" , "45" ),
MenuRowDef ( ScreenEdit :: sa_set_mods , "Set modifiers" , true , EditMode_Practice , true , true , 0 , "Press Start" ),
MenuRowDef ( ScreenEdit :: sa_remove , "Remove" , true , EditMode_Practice , true , true , 0 , "Press Start" ));
2011-03-17 01:43:45 -04:00
static MenuDef g_CourseMode (
"ScreenMiniMenuCourseDisplay" ,
MenuRowDef ( - 1 , "Play mods from course" , true , EditMode_Practice , true , false , 0 , NULL )
);
// HACK: need to remember the track we're inserting on so that we can lay the
// attack note after coming back from menus.
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 ) );
// XXX: We need more supported noteskins.
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" );
2011-05-27 12:43:14 -04:00
static ThemeMetric < bool > LOOP_ON_CHART_END ( "ScreenEdit" , "LoopOnChartEnd" );
2011-03-17 01:43:45 -04:00
REGISTER_SCREEN_CLASS ( ScreenEdit );
void ScreenEdit :: Init ()
{
m_pSoundMusic = NULL ;
2011-05-12 22:24:25 -04:00
2011-05-21 18:26:15 -07:00
GAMESTATE -> m_bIsUsingStepTiming = false ;
2011-05-13 23:32:14 -04:00
GAMESTATE -> m_bInStepEditor = true ;
2011-03-17 01:43:45 -04:00
SubscribeToMessage ( "Judgment" );
ASSERT ( GAMESTATE -> m_pCurSong );
ASSERT ( GAMESTATE -> m_pCurSteps [ PLAYER_1 ] );
EDIT_MODE . Load ( m_sName , "EditMode" );
ScreenWithMenuElements :: Init ();
InitEditMappings ();
2011-06-26 23:11:57 -04:00
2011-07-14 23:54:06 -04:00
currentCycleSegment = SEGMENT_LABEL ;
2011-03-17 01:43:45 -04:00
// save the originals for reverting later
CopyToLastSave ();
m_CurrentAction = MAIN_MENU_CHOICE_INVALID ;
if ( GAMESTATE -> GetCurrentStyle () -> m_StyleType == StyleType_TwoPlayersSharedSides )
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 ];
2011-05-25 14:07:53 -04:00
if ( m_pSteps -> UsesSplitTiming () )
GAMESTATE -> m_bIsUsingStepTiming = true ;
2011-03-17 01:43:45 -04:00
m_bReturnToRecordMenuAfterPlay = false ;
m_fBeatToReturnTo = 0 ;
m_selectedTap = TAP_ORIGINAL_TAP ;
GAMESTATE -> m_bGameplayLeadIn . Set ( true );
GAMESTATE -> m_EditMode = EDIT_MODE . GetValue ();
2011-05-13 14:14:57 +07:00
SetBeat ( 0 );
m_fTrailingBeat = 0 ;
2011-03-17 01:43:45 -04:00
m_iShiftAnchor = - 1 ;
m_iStartPlayingAt = - 1 ;
m_iStopPlayingAt = - 1 ;
this -> AddChild ( & m_Background );
m_SnapDisplay . SetXY ( EDIT_X , PLAYER_Y_STANDARD );
m_SnapDisplay . Load ();
// xxx: hardcoded command -aj
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 ;
2011-03-27 18:25:30 -05:00
// 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.
// todo: We should allow certain noteskins (note-colored/rhythm) to be
// displayed. (Perhaps this should be a noteskin metric.) -aj
2011-03-17 01:43:45 -04:00
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 );
2011-07-12 22:27:14 -04:00
this -> originalPlayerOptions . FromString ( ModsLevel_Stage , EDIT_MODIFIERS );
2011-03-17 01:43:45 -04:00
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 );
2011-05-17 21:07:52 -07:00
m_NoteFieldRecord . Load ( & m_NoteDataRecord , - 120 , 425 );
2011-03-17 01:43:45 -04:00
this -> AddChild ( & m_NoteFieldRecord );
m_EditState = EditState_Invalid ;
TransitionEditState ( STATE_EDITING );
m_bRemoveNoteButtonDown = false ;
m_Clipboard . SetNumTracks ( m_NoteDataEdit . GetNumTracks () );
2011-06-28 12:25:32 -04:00
2011-07-26 12:21:31 -04:00
clipboardFullTiming = GAMESTATE -> m_pCurSong -> m_SongTiming ; // always have a backup.
2011-03-17 01:43:45 -04:00
m_bHasUndo = false ;
m_Undo . SetNumTracks ( m_NoteDataEdit . GetNumTracks () );
m_bDirty = m_NoteDataEdit . IsEmpty (); // require the usage of saving if empty.
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 );
2011-05-13 08:50:59 -04:00
m_soundSwitchPlayer . Load ( THEME -> GetPathS ( "ScreenEdit" , "switch player" ), true );
m_soundSwitchTiming . Load ( THEME -> GetPathS ( "ScreenEdit" , "switch timing" ), true );
2011-03-17 01:43:45 -04:00
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 ();
2011-05-12 22:24:25 -04:00
2011-05-17 00:07:43 -04:00
// Go back to Step Timing on leave.
GAMESTATE -> m_bIsUsingStepTiming = true ;
2011-05-13 23:32:14 -04:00
// DEFINITELY reset the InStepEditor variable.
GAMESTATE -> m_bInStepEditor = false ;
2011-03-17 01:43:45 -04:00
}
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 ;
2011-05-23 11:22:32 -04:00
m_GameplayAssist . PlayTicks ( m_Player -> GetNoteData (), m_Player -> GetPlayerState () );
2011-03-17 01:43:45 -04:00
}
2011-10-08 19:01:06 -04:00
static ThemeMetric < float > FADE_IN_PREVIEW ( "ScreenEdit" , "FadeInPreview" );
static ThemeMetric < float > FADE_OUT_PREVIEW ( "ScreenEdit" , "FadeOutPreview" );
2011-03-17 01:43:45 -04:00
void ScreenEdit :: PlayPreviewMusic ()
{
SOUND -> StopMusic ();
SOUND -> PlayMusic (
m_pSong -> GetMusicPath (),
NULL ,
false ,
m_pSong -> m_fMusicSampleStartSeconds ,
m_pSong -> m_fMusicSampleLengthSeconds ,
2011-10-08 19:01:06 -04:00
FADE_IN_PREVIEW ,
FADE_OUT_PREVIEW );
2011-03-17 01:43:45 -04:00
}
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 )
{
// Reload options.
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 );
2011-05-12 16:44:24 +07:00
GAMESTATE -> UpdateSongPosition ( fSeconds , GAMESTATE -> m_pCurSong -> m_SongTiming , tm , true );
2011-03-17 01:43:45 -04:00
}
if ( m_EditState == STATE_RECORDING )
{
2011-05-13 10:07:41 -04:00
// TODO: Find a way to prevent STATE_RECORDING when in Song Timing.
2011-03-17 01:43:45 -04:00
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 );
2011-05-11 20:53:40 +07:00
if ( GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_Position . m_fSongBeat <= fStartPlayingAtBeat )
2011-03-17 01:43:45 -04:00
continue ;
float fStartedHoldingSeconds = m_pSoundMusic -> GetPositionSeconds () - fSecsHeld ;
2011-05-10 16:55:00 +07:00
float fStartBeat = max ( fStartPlayingAtBeat , m_pSteps -> m_Timing . GetBeatFromElapsedTime ( fStartedHoldingSeconds ) );
2011-05-13 10:07:41 -04:00
float fEndBeat = max ( fStartBeat , GetBeat () );
2011-03-17 01:43:45 -04:00
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
TapNote tn = EditIsBeingPressed ( EDIT_BUTTON_LAY_ROLL ) ? TAP_ORIGINAL_ROLL_HEAD : TAP_ORIGINAL_HOLD_HEAD ;
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 );
2011-05-15 00:09:44 -04:00
if ( bButtonIsBeingPressed && m_EditState == STATE_RECORDING )
2011-03-17 01:43:45 -04:00
{
2011-05-10 16:55:00 +07:00
float fSeconds = m_pSteps -> m_Timing . GetElapsedTimeFromBeat ( fLastBeat );
fLastBeat = m_pSteps -> m_Timing . GetBeatFromElapsedTime ( fSeconds + 0.5f );
2011-03-17 01:43:45 -04:00
}
2011-05-10 16:55:00 +07:00
float fStopAtSeconds = m_pSteps -> m_Timing . GetElapsedTimeFromBeat ( NoteRowToBeat ( m_iStopPlayingAt ) ) + 1 ;
2011-05-10 21:21:23 +07:00
if ( GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_Position . m_fMusicSeconds > fStopAtSeconds )
2011-03-17 01:43:45 -04:00
{
2011-05-27 12:43:14 -04:00
TransitionEditState ( ( LOOP_ON_CHART_END ? STATE_PLAYING : STATE_EDITING ) );
2011-03-17 01:43:45 -04:00
}
}
//LOG->Trace( "ScreenEdit::Update(%f)", fDeltaTime );
ScreenWithMenuElements :: Update ( fDeltaTime );
// Update trailing beat
2011-05-13 15:19:42 +07:00
float fDelta = GetBeat () - m_fTrailingBeat ;
2011-03-17 01:43:45 -04:00
if ( fabsf ( fDelta ) < 10 )
2011-05-13 15:19:42 +07:00
fapproach ( m_fTrailingBeat , GetBeat (),
2011-03-17 01:43:45 -04:00
fDeltaTime * 40 / m_NoteFieldEdit . GetPlayerState () -> m_PlayerOptions . GetCurrent (). m_fScrollSpeed );
else
2011-05-13 15:19:42 +07:00
fapproach ( m_fTrailingBeat , GetBeat (),
2011-03-17 01:43:45 -04:00
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" );
static LocalizedString ROUTINE_PLAYER ( "ScreenEdit" , "Routine Player" );
2011-07-07 14:20:21 -04:00
static LocalizedString CHART_NAME ( "ScreenEdit" , "Chart Name" );
2011-03-17 01:43:45 -04:00
static LocalizedString DESCRIPTION ( "ScreenEdit" , "Description" );
static LocalizedString CHART_STYLE ( "ScreenEdit" , "Chart Style" );
2011-06-27 11:09:31 -04:00
static LocalizedString STEP_AUTHOR ( "ScreenEdit" , "Step Author" );
2011-03-17 01:43:45 -04:00
static LocalizedString MAIN_TITLE ( "ScreenEdit" , "Main title" );
static LocalizedString SUBTITLE ( "ScreenEdit" , "Subtitle" );
static LocalizedString TAP_NOTE_TYPE ( "ScreenEdit" , "Tap Note" );
2011-06-26 23:11:57 -04:00
static LocalizedString SEGMENT_TYPE ( "ScreenEdit" , "Segment" );
2011-03-17 01:43:45 -04: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" );
static LocalizedString LIFTS ( "ScreenEdit" , "Lifts" );
static LocalizedString FAKES ( "ScreenEdit" , "Fakes" );
2011-05-12 23:11:42 -04:00
static LocalizedString TIMING_MODE ( "ScreenEdit" , "Timing Mode" );
static LocalizedString STEP_TIMING ( "ScreenEdit" , "Step Timing" );
static LocalizedString SONG_TIMING ( "ScreenEdit" , "Song Timing" );
2011-03-17 01:43:45 -04:00
static LocalizedString BEAT_0_OFFSET ( "ScreenEdit" , "Beat 0 offset" );
static LocalizedString PREVIEW_START ( "ScreenEdit" , "Preview Start" );
static LocalizedString PREVIEW_LENGTH ( "ScreenEdit" , "Preview Length" );
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" );
2011-07-07 14:20:21 -04:00
static ThemeMetric < RString > CHART_NAME_FORMAT ( "ScreenEdit" , "ChartNameFormat" );
2011-03-17 01:43:45 -04:00
static ThemeMetric < RString > DESCRIPTION_FORMAT ( "ScreenEdit" , "DescriptionFormat" );
static ThemeMetric < RString > CHART_STYLE_FORMAT ( "ScreenEdit" , "ChartStyleFormat" );
2011-06-27 11:09:31 -04:00
static ThemeMetric < RString > STEP_AUTHOR_FORMAT ( "ScreenEdit" , "StepAuthorFormat" );
2011-03-17 01:43:45 -04:00
static ThemeMetric < RString > MAIN_TITLE_FORMAT ( "ScreenEdit" , "MainTitleFormat" );
static ThemeMetric < RString > SUBTITLE_FORMAT ( "ScreenEdit" , "SubtitleFormat" );
static ThemeMetric < RString > TAP_NOTE_TYPE_FORMAT ( "ScreenEdit" , "TapNoteTypeFormat" );
2011-06-26 23:11:57 -04:00
static ThemeMetric < RString > SEGMENT_TYPE_FORMAT ( "ScreenEdit" , "SegmentTypeFormat" );
2011-03-17 01:43:45 -04: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" );
static ThemeMetric < RString > NUM_LIFTS_FORMAT ( "ScreenEdit" , "NumLiftsFormat" );
static ThemeMetric < RString > NUM_FAKES_FORMAT ( "ScreenEdit" , "NumFakesFormat" );
2011-07-13 16:07:33 -04:00
static ThemeMetric < RString > NUM_STEPS_FORMAT_TWO_PLAYER ( "ScreenEdit" , "NumStepsFormatTwoPlayer" );
static ThemeMetric < RString > NUM_JUMPS_FORMAT_TWO_PLAYER ( "ScreenEdit" , "NumJumpsFormatTwoPlayer" );
static ThemeMetric < RString > NUM_HOLDS_FORMAT_TWO_PLAYER ( "ScreenEdit" , "NumHoldsFormatTwoPlayer" );
static ThemeMetric < RString > NUM_MINES_FORMAT_TWO_PLAYER ( "ScreenEdit" , "NumMinesFormatTwoPlayer" );
static ThemeMetric < RString > NUM_HANDS_FORMAT_TWO_PLAYER ( "ScreenEdit" , "NumHandsFormatTwoPlayer" );
static ThemeMetric < RString > NUM_ROLLS_FORMAT_TWO_PLAYER ( "ScreenEdit" , "NumRollsFormatTwoPlayer" );
static ThemeMetric < RString > NUM_LIFTS_FORMAT_TWO_PLAYER ( "ScreenEdit" , "NumLiftsFormatTwoPlayer" );
static ThemeMetric < RString > NUM_FAKES_FORMAT_TWO_PLAYER ( "ScreenEdit" , "NumFakesFormatTwoPlayer" );
2011-05-12 23:11:42 -04:00
static ThemeMetric < RString > TIMING_MODE_FORMAT ( "ScreenEdit" , "TimingModeFormat" );
2011-03-17 01:43:45 -04: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" );
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-05-13 15:19:42 +07:00
sText += ssprintf ( CURRENT_BEAT_FORMAT . GetValue (), CURRENT_BEAT . GetValue (). c_str (), GetBeat () );
sText += ssprintf ( CURRENT_SECOND_FORMAT . GetValue (), CURRENT_SECOND . GetValue (). c_str (), GetAppropriateTiming (). GetElapsedTimeFromBeat ( GetBeat ()) );
2011-03-17 01:43:45 -04:00
switch ( EDIT_MODE . GetValue () )
{
DEFAULT_FAIL ( EDIT_MODE . GetValue () );
case EditMode_Practice :
break ;
case EditMode_CourseMods :
case EditMode_Home :
case EditMode_Full :
sText += ssprintf ( SNAP_TO_FORMAT . GetValue (), SNAP_TO . GetValue (). c_str (), sNoteType . c_str () );
break ;
}
if ( m_NoteFieldEdit . m_iBeginMarker != - 1 )
{
sText += ssprintf ( SELECTION_BEAT_BEGIN_FORMAT . GetValue (), SELECTION_BEAT . GetValue (). c_str (), NoteRowToBeat ( m_NoteFieldEdit . m_iBeginMarker ) );
if ( m_NoteFieldEdit . m_iEndMarker != - 1 )
sText += ssprintf ( SELECTION_BEAT_END_FORMAT . GetValue (), NoteRowToBeat ( m_NoteFieldEdit . m_iEndMarker ) );
else
sText += SELECTION_BEAT_UNFINISHED_FORMAT ;
}
switch ( EDIT_MODE . GetValue () )
{
DEFAULT_FAIL ( EDIT_MODE . GetValue () );
case EditMode_Practice :
case EditMode_CourseMods :
case EditMode_Home :
break ;
case EditMode_Full :
sText += ssprintf ( DIFFICULTY_FORMAT . GetValue (), DIFFICULTY . GetValue (). c_str (), DifficultyToString ( m_pSteps -> GetDifficulty () ). c_str () );
if ( m_InputPlayerNumber != PLAYER_INVALID )
sText += ssprintf ( ROUTINE_PLAYER_FORMAT . GetValue (), ROUTINE_PLAYER . GetValue (). c_str (), m_InputPlayerNumber + 1 );
2011-07-07 14:20:21 -04:00
//sText += ssprintf( DESCRIPTION_FORMAT.GetValue(), DESCRIPTION.GetValue().c_str(), m_pSteps->GetDescription().c_str() );
sText += ssprintf ( CHART_NAME_FORMAT . GetValue (), CHART_NAME . GetValue (). c_str (), m_pSteps -> GetChartName (). c_str () );
2011-06-27 11:09:31 -04:00
sText += ssprintf ( STEP_AUTHOR_FORMAT . GetValue (), STEP_AUTHOR . GetValue (). c_str (), m_pSteps -> GetCredit (). c_str () );
//sText += ssprintf( CHART_STYLE_FORMAT.GetValue(), CHART_STYLE.GetValue().c_str(), m_pSteps->GetChartStyle().c_str() );
2011-03-17 01:43:45 -04:00
sText += ssprintf ( MAIN_TITLE_FORMAT . GetValue (), MAIN_TITLE . GetValue (). c_str (), m_pSong -> m_sMainTitle . c_str () );
if ( m_pSong -> m_sSubTitle . size () )
sText += ssprintf ( SUBTITLE_FORMAT . GetValue (), SUBTITLE . GetValue (). c_str (), m_pSong -> m_sSubTitle . c_str () );
2011-07-14 23:54:06 -04:00
sText += ssprintf ( SEGMENT_TYPE_FORMAT . GetValue (), SEGMENT_TYPE . GetValue (). c_str (), TimingSegmentTypeToString ( currentCycleSegment ). c_str () );
2011-03-17 01:43:45 -04:00
sText += ssprintf ( TAP_NOTE_TYPE_FORMAT . GetValue (), TAP_NOTE_TYPE . GetValue (). c_str (), TapNoteTypeToString ( m_selectedTap . type ). c_str () );
2011-06-26 23:11:57 -04:00
break ;
2011-03-17 01:43:45 -04:00
}
2011-06-08 16:14:11 -04:00
GAMESTATE -> SetProcessedTimingData ( & m_pSteps -> m_Timing );
2011-07-13 16:07:33 -04:00
const StepsTypeCategory & cat = GAMEMAN -> GetStepsTypeInfo ( m_pSteps -> m_StepsType ). m_StepsTypeCategory ;
if ( cat == StepsTypeCategory_Couple || cat == StepsTypeCategory_Routine )
{
pair < int , int > tmp = m_NoteDataEdit . GetNumTapNotesTwoPlayer ();
sText += ssprintf ( NUM_STEPS_FORMAT_TWO_PLAYER . GetValue (),
TAP_STEPS . GetValue (). c_str (),
tmp . first , tmp . second );
tmp = m_NoteDataEdit . GetNumJumpsTwoPlayer ();
sText += ssprintf ( NUM_JUMPS_FORMAT_TWO_PLAYER . GetValue (),
JUMPS . GetValue (). c_str (),
tmp . first , tmp . second );
tmp = m_NoteDataEdit . GetNumHandsTwoPlayer ();
sText += ssprintf ( NUM_HANDS_FORMAT_TWO_PLAYER . GetValue (),
HANDS . GetValue (). c_str (),
tmp . first , tmp . second );
tmp = m_NoteDataEdit . GetNumHoldNotesTwoPlayer ();
sText += ssprintf ( NUM_HOLDS_FORMAT_TWO_PLAYER . GetValue (),
HOLDS . GetValue (). c_str (),
tmp . first , tmp . second );
tmp = m_NoteDataEdit . GetNumMinesTwoPlayer ();
sText += ssprintf ( NUM_MINES_FORMAT_TWO_PLAYER . GetValue (),
MINES . GetValue (). c_str (),
tmp . first , tmp . second );
tmp = m_NoteDataEdit . GetNumRollsTwoPlayer ();
sText += ssprintf ( NUM_ROLLS_FORMAT_TWO_PLAYER . GetValue (),
ROLLS . GetValue (). c_str (),
tmp . first , tmp . second );
tmp = m_NoteDataEdit . GetNumLiftsTwoPlayer ();
sText += ssprintf ( NUM_LIFTS_FORMAT_TWO_PLAYER . GetValue (),
LIFTS . GetValue (). c_str (),
tmp . first , tmp . second );
tmp = m_NoteDataEdit . GetNumFakesTwoPlayer ();
sText += ssprintf ( NUM_FAKES_FORMAT_TWO_PLAYER . GetValue (),
FAKES . GetValue (). c_str (),
tmp . first , tmp . second );
}
else
{
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 () );
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 () );
2011-03-17 01:43:45 -04:00
}
switch ( EDIT_MODE . GetValue () )
{
DEFAULT_FAIL ( EDIT_MODE . GetValue () );
case EditMode_Practice :
case EditMode_CourseMods :
case EditMode_Home :
break ;
case EditMode_Full :
2011-05-12 23:11:42 -04:00
sText += ssprintf ( TIMING_MODE_FORMAT . GetValue (),
TIMING_MODE . GetValue (). c_str (),
2011-05-17 00:07:43 -04:00
( GAMESTATE -> m_bIsUsingStepTiming ?
2011-05-12 23:11:42 -04:00
STEP_TIMING . GetValue (). c_str () :
SONG_TIMING . GetValue (). c_str () ) );
2011-05-12 22:39:10 -04:00
sText += ssprintf ( BEAT_0_OFFSET_FORMAT . GetValue (),
BEAT_0_OFFSET . GetValue (). c_str (),
2011-05-12 23:01:19 -04:00
GetAppropriateTiming (). m_fBeat0OffsetInSeconds );
2011-03-17 01:43:45 -04:00
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 );
break ;
}
m_textInfo . SetText ( sText );
2011-06-08 16:14:11 -04:00
GAMESTATE -> SetProcessedTimingData ( NULL );
2011-03-17 01:43:45 -04:00
}
void ScreenEdit :: DrawPrimitives ()
{
2011-05-11 21:22:18 +07:00
if ( m_pSoundMusic -> IsPlaying () )
2011-03-17 01:43:45 -04:00
{
2011-05-11 21:22:18 +07:00
ScreenWithMenuElements :: DrawPrimitives ();
return ;
2011-03-17 01:43:45 -04:00
}
2011-05-11 21:22:18 +07:00
// HACK: Draw using the trailing beat
PlayerState * pPlayerState = const_cast < PlayerState *> ( m_NoteFieldEdit . GetPlayerState ());
2011-05-13 14:14:57 +07:00
float fPlayerSongBeat = pPlayerState -> m_Position . m_fSongBeat ; // save song beat
float fPlayerSongBeatNoOffset = pPlayerState -> m_Position . m_fSongBeatNoOffset ;
float fPlayerSongBeatVisible = pPlayerState -> m_Position . m_fSongBeatVisible ;
float fGameSongBeat = GAMESTATE -> m_Position . m_fSongBeat ; // save song beat
float fGameSongBeatNoOffset = GAMESTATE -> m_Position . m_fSongBeatNoOffset ;
float fGameSongBeatVisible = GAMESTATE -> m_Position . m_fSongBeatVisible ;
2011-05-11 21:22:18 +07:00
pPlayerState -> m_Position . m_fSongBeat = m_fTrailingBeat ; // put trailing beat in effect
pPlayerState -> m_Position . m_fSongBeatNoOffset = m_fTrailingBeat ; // put trailing beat in effect
pPlayerState -> m_Position . m_fSongBeatVisible = m_fTrailingBeat ; // put trailing beat in effect
2011-05-13 15:19:42 +07:00
GAMESTATE -> m_Position . m_fSongBeat = m_fTrailingBeat ; // put trailing beat in effect
GAMESTATE -> m_Position . m_fSongBeatNoOffset = m_fTrailingBeat ; // put trailing beat in effect
GAMESTATE -> m_Position . m_fSongBeatVisible = m_fTrailingBeat ; // put trailing beat in effect
2011-05-11 21:22:18 +07:00
2011-03-17 01:43:45 -04:00
ScreenWithMenuElements :: DrawPrimitives ();
2011-05-13 14:14:57 +07:00
pPlayerState -> m_Position . m_fSongBeat = fPlayerSongBeat ; // restore real song beat
pPlayerState -> m_Position . m_fSongBeatNoOffset = fPlayerSongBeatNoOffset ;
pPlayerState -> m_Position . m_fSongBeatVisible = fPlayerSongBeatVisible ;
GAMESTATE -> m_Position . m_fSongBeat = fGameSongBeat ; // restore real song beat
GAMESTATE -> m_Position . m_fSongBeatNoOffset = fGameSongBeatNoOffset ;
GAMESTATE -> m_Position . m_fSongBeatVisible = fGameSongBeatVisible ;
2011-05-11 21:22:18 +07:00
2011-03-17 01:43:45 -04:00
}
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 ;
}
2011-05-14 01:03:39 -04:00
static LocalizedString BG_CHANGE_STEP_TIMING ( "ScreenEdit" , "You must be in Song Timing Mode to edit BG Changes." );
2011-06-10 03:04:47 -04:00
static LocalizedString ALTER_MENU_NO_SELECTION ( "ScreenEdit" , "You must have an area selected to enter the Alter Menu." );
2011-03-17 01:43:45 -04:00
static LocalizedString SWITCHED_TO ( "ScreenEdit" , "Switched to" );
static LocalizedString NO_BACKGROUNDS_AVAILABLE ( "ScreenEdit" , "No backgrounds available" );
2011-05-13 09:20:42 -04:00
static ThemeMetric < bool > INVERT_SCROLL_BUTTONS ( "ScreenEdit" , "InvertScrollSpeedButtons" );
2011-03-17 14:41:26 -04:00
2011-03-17 01:43:45 -04:00
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-06-11 17:05:03 -04:00
TimingData & sTiming = GetAppropriateTiming ();
2011-06-01 14:01:35 -04:00
float playerBeat = GetAppropriatePosition (). m_fSongBeat ;
2011-07-14 23:15:48 -04:00
int beatsPerMeasure = sTiming . GetTimeSignatureSegmentAtBeat ( playerBeat ) -> GetNum ();
2011-03-17 01:43:45 -04: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 () );
2011-10-17 22:58:04 -04:00
if ( iCol >= m_NoteDataEdit . GetNumTracks () )
break ; // this button is not in the range of columns for this Style
2011-03-17 01:43:45 -04:00
2011-05-13 10:51:09 -04:00
const float fSongBeat = GetBeat ();
2011-03-17 01:43:45 -04:00
const int iSongIndex = BeatToNoteRow ( fSongBeat );
2011-10-17 22:58:04 -04:00
2011-03-17 01:43:45 -04:00
// 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 ();
TapNote tn = m_selectedTap ;
tn . pn = m_InputPlayerNumber ;
m_NoteDataEdit . SetTapNote ( iCol , iSongIndex , tn );
CheckNumberOfNotesAndUndo ();
}
}
break ;
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 ;
}
2011-06-26 23:11:57 -04:00
case EDIT_BUTTON_CYCLE_SEGMENT_LEFT :
{
2011-07-14 23:54:06 -04:00
int tmp = enum_add2 ( this -> currentCycleSegment , - 1 );
2011-07-15 00:14:13 -04:00
wrap ( * ConvertValue < int > ( & tmp ), NUM_TimingSegmentType );
2011-06-26 23:11:57 -04:00
break ;
}
case EDIT_BUTTON_CYCLE_SEGMENT_RIGHT :
{
2011-07-14 23:54:06 -04:00
int tmp = enum_add2 ( this -> currentCycleSegment , + 1 );
2011-07-15 00:14:13 -04:00
wrap ( * ConvertValue < int > ( & tmp ), NUM_TimingSegmentType );
2011-11-26 13:45:29 -05:00
break ;
}
2011-03-17 01:43:45 -04: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 :
2011-03-17 14:41:26 -04:00
INVERT_SCROLL_BUTTONS ? ++ iSpeed : -- iSpeed ;
2011-03-17 01:43:45 -04:00
break ;
case EDIT_BUTTON_SCROLL_SPEED_UP :
2011-03-17 14:41:26 -04:00
INVERT_SCROLL_BUTTONS ? -- iSpeed : ++ iSpeed ;
2011-03-17 01:43:45 -04:00
break ;
}
iSpeed = clamp ( iSpeed , 0 , ( int ) ARRAYLEN ( fSpeeds ) - 1 );
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 :
2011-06-12 20:34:23 -04:00
case EDIT_BUTTON_SCROLL_UP_TS :
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_SCROLL_DOWN_LINE :
case EDIT_BUTTON_SCROLL_DOWN_PAGE :
2011-06-12 20:34:23 -04:00
case EDIT_BUTTON_SCROLL_DOWN_TS :
2011-03-17 01:43:45 -04:00
{
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 () );
if ( EditB == EDIT_BUTTON_SCROLL_UP_LINE )
fBeatsToMove *= - 1 ;
break ;
case EDIT_BUTTON_SCROLL_UP_PAGE :
case EDIT_BUTTON_SCROLL_DOWN_PAGE :
2011-06-12 20:34:23 -04:00
fBeatsToMove = 4 ;
2011-03-17 01:43:45 -04:00
if ( EditB == EDIT_BUTTON_SCROLL_UP_PAGE )
fBeatsToMove *= - 1 ;
break ;
2011-06-12 20:34:23 -04:00
case EDIT_BUTTON_SCROLL_UP_TS :
case EDIT_BUTTON_SCROLL_DOWN_TS :
fBeatsToMove = beatsPerMeasure ;
if ( EditB == EDIT_BUTTON_SCROLL_UP_TS )
fBeatsToMove *= - 1 ;
break ;
2011-03-17 01:43:45 -04:00
}
if ( m_PlayerStateEdit . m_PlayerOptions . GetSong (). m_fScrolls [ PlayerOptions :: SCROLL_REVERSE ] > 0.5 )
fBeatsToMove *= - 1 ;
2011-05-13 15:19:42 +07:00
float fDestinationBeat = GetBeat () + fBeatsToMove ;
2011-03-17 01:43:45 -04:00
fDestinationBeat = Quantize ( fDestinationBeat , NoteTypeToBeat ( m_SnapDisplay . GetNoteType ()) );
ScrollTo ( fDestinationBeat );
}
break ;
case EDIT_BUTTON_SCROLL_NEXT_MEASURE :
{
2011-05-13 15:21:48 -04:00
float fDestinationBeat = GetBeat () + beatsPerMeasure ;
2011-03-17 01:43:45 -04:00
fDestinationBeat = ftruncf ( fDestinationBeat , ( float ) beatsPerMeasure );
ScrollTo ( fDestinationBeat );
break ;
}
case EDIT_BUTTON_SCROLL_PREV_MEASURE :
{
2011-05-13 15:21:48 -04:00
float fDestinationBeat = QuantizeUp ( GetBeat (), ( float ) beatsPerMeasure );
2011-03-17 01:43:45 -04:00
fDestinationBeat -= ( float ) beatsPerMeasure ;
ScrollTo ( fDestinationBeat );
break ;
}
case EDIT_BUTTON_SCROLL_NEXT :
{
2011-05-13 15:21:48 -04:00
int iRow = BeatToNoteRow ( GetBeat () );
2011-03-17 01:43:45 -04:00
NoteDataUtil :: GetNextEditorPosition ( m_NoteDataEdit , iRow );
ScrollTo ( NoteRowToBeat ( iRow ) );
}
break ;
case EDIT_BUTTON_SCROLL_PREV :
{
2011-05-13 15:21:48 -04:00
int iRow = BeatToNoteRow ( GetBeat () );
2011-03-17 01:43:45 -04:00
NoteDataUtil :: GetPrevEditorPosition ( m_NoteDataEdit , iRow );
ScrollTo ( NoteRowToBeat ( iRow ) );
}
break ;
2011-06-26 23:11:57 -04:00
case EDIT_BUTTON_SEGMENT_NEXT :
{
2011-07-14 23:54:06 -04:00
// TODO: Work around Stops and Delays. We MAY have to separate them.
2011-06-26 23:11:57 -04:00
TimingData & timing = GetAppropriateTiming ();
2011-07-14 23:54:06 -04:00
ScrollTo ( timing . GetNextSegmentBeatAtBeat ( this -> currentCycleSegment ,
GetBeat ()));
2011-06-26 23:11:57 -04:00
}
break ;
case EDIT_BUTTON_SEGMENT_PREV :
{
2011-07-14 23:54:06 -04:00
// TODO: Work around Stops and Delays. We MAY have to separate them.
2011-06-26 23:11:57 -04:00
TimingData & timing = GetAppropriateTiming ();
2011-07-14 23:54:06 -04:00
ScrollTo ( timing . GetPreviousSegmentBeatAtBeat ( this -> currentCycleSegment ,
GetBeat ()));
2011-06-26 23:11:57 -04:00
}
break ;
2011-03-17 01:43:45 -04:00
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 :
{
2011-06-01 13:41:49 -04:00
const int iCurrentRow = BeatToNoteRow ( GetAppropriatePosition (). m_fSongBeat );
2011-03-17 01:43:45 -04:00
if ( m_NoteFieldEdit . m_iBeginMarker ==- 1 && m_NoteFieldEdit . m_iEndMarker ==- 1 )
{
// lay begin marker
2011-06-01 13:41:49 -04:00
m_NoteFieldEdit . m_iBeginMarker = BeatToNoteRow ( GetAppropriatePosition (). m_fSongBeat );
2011-03-17 01:43:45 -04:00
}
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 :
{
2011-09-24 02:01:46 -04:00
// TODO: Improve behavior if timing changes are shifted down on beat 0.
g_AreaMenu . rows [ shift_pauses_forward ]. bEnabled = ( GetBeat () != 0 );
2011-05-15 00:09:44 -04:00
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 ;
2011-07-26 16:05:14 -04:00
g_AreaMenu . rows [ paste_partial_timing_at_beat ]. bEnabled = ! this -> clipboardTiming . empty ();
2011-03-17 01:43:45 -04:00
g_AreaMenu . rows [ undo ]. bEnabled = m_bHasUndo ;
EditMiniMenu ( & g_AreaMenu , SM_BackFromAreaMenu );
}
break ;
2011-06-10 03:04:47 -04:00
case EDIT_BUTTON_OPEN_ALTER_MENU :
{
bool bAreaSelected = m_NoteFieldEdit . m_iBeginMarker !=- 1 && m_NoteFieldEdit . m_iEndMarker !=- 1 ;
if ( ! bAreaSelected )
{
SCREENMAN -> SystemMessage ( ALTER_MENU_NO_SELECTION );
SCREENMAN -> PlayInvalidSound ();
}
else
{
2011-09-24 02:01:46 -04:00
// TODO: Improve interaction when field is 0.
g_AlterMenu . rows [ convert_to_delay ]. bEnabled = ( m_NoteFieldEdit . m_iBeginMarker > 0 );
g_AlterMenu . rows [ convert_to_pause ]. bEnabled = ( m_NoteFieldEdit . m_iBeginMarker > 0 );
2011-07-04 18:15:21 -04:00
bool isRoutine = ( m_InputPlayerNumber != PLAYER_INVALID );
g_AlterMenu . rows [ routine_invert_notes ]. bEnabled = isRoutine ;
g_AlterMenu . rows [ routine_mirror_1_to_2 ]. bEnabled = isRoutine ;
g_AlterMenu . rows [ routine_mirror_2_to_1 ]. bEnabled = isRoutine ;
2011-06-10 03:04:47 -04:00
EditMiniMenu ( & g_AlterMenu , SM_BackFromAlterMenu );
}
break ;
}
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_OPEN_EDIT_MENU :
EditMiniMenu ( & g_MainMenu , SM_BackFromMainMenu );
break ;
case EDIT_BUTTON_OPEN_INPUT_HELP :
DoHelp ();
break ;
2011-05-12 20:55:45 -04:00
case EDIT_BUTTON_OPEN_TIMING_MENU :
{
DisplayTimingMenu ();
break ;
}
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_OPEN_NEXT_STEPS :
case EDIT_BUTTON_OPEN_PREV_STEPS :
{
// don't keep undo when changing Steps
ClearUndo ();
2011-06-26 13:36:42 -04:00
// get the second of the current step.
float curSecond = GetAppropriateTiming (). GetElapsedTimeFromBeat ( GetBeat ());
2011-03-17 01:43:45 -04:00
// 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)" ,
2011-12-09 21:15:29 -05:00
GAMEMAN -> GetStepsTypeInfo ( st ). szName ,
2011-03-17 01:43:45 -04:00
DifficultyToString ( pSteps -> GetDifficulty () ). c_str (),
2011-10-09 13:02:24 -04:00
pSteps -> GetChartName (). c_str (),
2011-03-17 01:43:45 -04:00
it - vSteps . begin () + 1 ,
int ( vSteps . size ()) );
SCREENMAN -> SystemMessage ( s );
m_soundSwitchSteps . Play ();
2011-06-26 13:36:42 -04:00
ScrollTo ( GetAppropriateTiming (). GetBeatFromElapsedTime ( curSecond ) );
2011-03-17 01:43:45 -04:00
}
break ;
case EDIT_BUTTON_BPM_UP :
case EDIT_BUTTON_BPM_DOWN :
{
2011-05-13 10:07:41 -04:00
float fBPM = GetAppropriateTiming (). GetBPMAtBeat ( GetBeat () );
2011-03-17 01:43:45 -04:00
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 ;
}
2011-09-15 03:28:58 +00:00
2011-03-17 01:43:45 -04:00
float fNewBPM = fBPM + fDelta ;
2011-05-13 10:07:41 -04:00
GetAppropriateTiming (). SetBPMAtBeat ( GetBeat (), fNewBPM );
2011-03-17 01:43:45 -04:00
( 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 ;
}
2011-09-15 03:28:58 +00:00
// is there a StopSegment on the current row?
2011-11-26 13:33:21 -05:00
TimingData & timing = GetAppropriateTiming ();
StopSegment * seg = timing . GetStopSegmentAtRow ( GetRow () );
int i = timing . GetSegmentIndexAtRow ( SEGMENT_STOP , GetRow ());
if ( i == - 1 || seg -> GetRow () != GetRow ()) // invalid
2011-09-15 03:28:58 +00:00
{
2011-03-17 01:43:45 -04:00
if ( fDelta > 0 )
2011-11-26 13:33:21 -05:00
timing . AddSegment ( StopSegment ( GetRow (), fDelta ) );
2011-11-26 13:40:14 -05:00
else
break ;
2011-03-17 01:43:45 -04:00
}
2011-11-26 13:33:21 -05:00
else
2011-03-17 01:43:45 -04:00
{
2011-11-26 13:33:21 -05:00
vector < TimingSegment *> & stops = timing . GetTimingSegments ( SEGMENT_STOP );
seg -> SetPause ( seg -> GetPause () + fDelta );
if ( seg -> GetPause () <= 0 )
2011-07-14 13:00:03 -04:00
stops . erase ( stops . begin () + i , stops . begin () + i + 1 );
2011-03-17 01:43:45 -04:00
}
2011-11-26 13:33:21 -05:00
2011-03-17 01:43:45 -04:00
( fDelta > 0 ? m_soundValueIncrease : m_soundValueDecrease ). Play ();
SetDirty ( true );
}
break ;
2011-11-26 13:56:27 -05:00
// TODO: Combine the stop and delay call somehow?
case EDIT_BUTTON_DELAY_UP :
case EDIT_BUTTON_DELAY_DOWN :
{
float fDelta ;
switch ( EditB )
{
DEFAULT_FAIL ( EditB );
case EDIT_BUTTON_DELAY_UP : fDelta = + 0.020f ; break ;
case EDIT_BUTTON_DELAY_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 ;
}
// is there a StopSegment on the current row?
TimingData & timing = GetAppropriateTiming ();
DelaySegment * seg = timing . GetDelaySegmentAtRow ( GetRow () );
int i = timing . GetSegmentIndexAtRow ( SEGMENT_DELAY , GetRow ());
if ( i == - 1 || seg -> GetRow () != GetRow ()) // invalid
{
if ( fDelta > 0 )
timing . AddSegment ( DelaySegment ( GetRow (), fDelta ) );
else
break ;
}
else
{
vector < TimingSegment *> & stops = timing . GetTimingSegments ( SEGMENT_DELAY );
seg -> SetPause ( seg -> GetPause () + fDelta );
if ( seg -> GetPause () <= 0 )
stops . erase ( stops . begin () + i , stops . begin () + i + 1 );
}
( fDelta > 0 ? m_soundValueIncrease : m_soundValueDecrease ). Play ();
SetDirty ( true );
}
break ;
2011-03-17 01:43:45 -04:00
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 ;
}
2011-05-13 10:07:41 -04:00
GetAppropriateTiming (). m_fBeat0OffsetInSeconds += fDelta ;
2011-03-17 01:43:45 -04:00
( fDelta > 0 ? m_soundValueIncrease : m_soundValueDecrease ). Play ();
2011-06-30 13:35:25 -04:00
if ( GAMESTATE -> m_bIsUsingStepTiming )
{
GAMESTATE -> m_pCurSteps [ PLAYER_1 ] -> m_Attacks . UpdateStartTimes ( fDelta );
}
else
{
GAMESTATE -> m_pCurSong -> m_Attacks . UpdateStartTimes ( fDelta );
2011-07-12 22:42:53 -04:00
GAMESTATE -> m_pCurSong -> m_fMusicSampleStartSeconds += fDelta ;
2011-06-30 13:35:25 -04:00
}
2011-03-17 01:43:45 -04:00
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 :
2011-05-17 00:07:43 -04:00
if ( ! GAMESTATE -> m_bIsUsingStepTiming )
2011-03-17 01:43:45 -04:00
{
2011-05-12 23:25:50 -04:00
switch ( EditB )
2011-03-17 01:43:45 -04:00
{
2011-05-12 23:25:50 -04:00
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 ;
2011-03-17 01:43:45 -04:00
}
2011-05-12 23:25:50 -04:00
{
// 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_pPlayerState [ PLAYER_1 ] -> m_Position . m_fSongBeat )
{
bAlreadyBGChangeHere = true ;
bgChange = * bgc ;
}
}
2011-03-17 01:43:45 -04:00
#define FILL_ENABLED( x ) menu.rows[x].bEnabled = menu.rows[x].choices.size() > 0;
2011-05-12 23:25:50 -04:00
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 );
2011-03-17 01:43:45 -04:00
#undef FILL_ENABLED
2011-05-12 23:25:50 -04:00
menu . rows [ delete_change ]. bEnabled = bAlreadyBGChangeHere ;
2011-03-17 01:43:45 -04:00
2011-05-12 23:25:50 -04:00
// 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 );
2011-03-17 01:43:45 -04:00
2011-05-12 23:25:50 -04:00
EditMiniMenu ( & g_BackgroundChange , SM_BackFromBGChange );
}
2011-03-17 01:43:45 -04:00
}
2011-05-14 01:03:39 -04:00
else
{
SCREENMAN -> SystemMessage ( BG_CHANGE_STEP_TIMING );
2011-05-14 01:31:28 -04:00
SCREENMAN -> PlayInvalidSound ();
2011-05-14 01:03:39 -04:00
}
2011-03-17 01:43:45 -04:00
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 ;
2011-06-24 19:32:46 -04:00
case EDIT_BUTTON_OPEN_STEP_ATTACK_MENU :
{
TimingData & timing = GetAppropriateTiming ();
float startTime = timing . GetElapsedTimeFromBeat ( GetBeat ());
AttackArray & attacks =
( GAMESTATE -> m_bIsUsingStepTiming ? m_pSteps -> m_Attacks : m_pSong -> m_Attacks );
int index = FindAttackAtTime ( attacks , startTime );
if ( index >= 0 )
{
2011-06-30 01:11:38 -04:00
const RString sDuration = ssprintf ( "%.6f" , attacks [ index ]. fSecsRemaining );
2011-06-24 19:32:46 -04:00
2011-07-12 21:56:17 -04:00
g_InsertStepAttack . rows [ sa_remove ]. bEnabled = true ;
if ( g_InsertStepAttack . rows [ sa_duration ]. choices . size () == 9 )
g_InsertStepAttack . rows [ sa_duration ]. choices . push_back ( sDuration );
2011-06-24 19:32:46 -04:00
else
2011-07-12 21:56:17 -04:00
g_InsertStepAttack . rows [ sa_duration ]. choices . back () = sDuration ;
g_InsertStepAttack . rows [ sa_duration ]. iDefaultChoice = 9 ;
2011-06-24 19:32:46 -04:00
}
else
{
2011-07-12 21:56:17 -04:00
if ( g_InsertStepAttack . rows [ sa_duration ]. choices . size () == 10 )
g_InsertStepAttack . rows [ sa_duration ]. choices . pop_back ();
g_InsertStepAttack . rows [ sa_duration ]. iDefaultChoice = 3 ;
2011-06-24 19:32:46 -04:00
}
2011-07-12 21:56:17 -04:00
EditMiniMenu ( & g_InsertStepAttack , SM_BackFromInsertStepAttack );
2011-06-24 19:32:46 -04:00
break ;
}
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_OPEN_COURSE_ATTACK_MENU :
{
2011-05-13 10:07:41 -04:00
// TODO: Give Song/Step Timing switches/functions here?
2011-03-17 01:43:45 -04:00
Course * pCourse = GAMESTATE -> m_pCurCourse ;
if ( pCourse == NULL )
break ;
CourseEntry & ce = pCourse -> m_vEntries [ GAMESTATE -> m_iEditCourseEntryIndex ];
2011-05-11 20:53:40 +07:00
float fStartTime = m_pSteps -> m_Timing . GetElapsedTimeFromBeat ( GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_Position . m_fSongBeat );
2011-03-17 01:43:45 -04:00
int iAttack = FindAttackAtTime ( ce . attacks , fStartTime );
if ( iAttack >= 0 )
{
2011-06-30 01:11:38 -04:00
const RString sDuration = ssprintf ( "%.6f" , ce . attacks [ iAttack ]. fSecsRemaining );
2011-03-17 01:43:45 -04:00
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 ;
2011-06-24 19:32:46 -04:00
case EDIT_BUTTON_ADD_STEP_MODS :
{
float start = - 1 ;
float end = - 1 ;
PlayerOptions po ;
if ( m_NoteFieldEdit . m_iBeginMarker == - 1 ) // not highlighted
{
po . FromString ( "" );
}
else
{
TimingData & timing = GetAppropriateTiming ();
start = timing . GetElapsedTimeFromBeat ( NoteRowToBeat ( m_NoteFieldEdit . m_iBeginMarker ));
AttackArray & attacks =
( GAMESTATE -> m_bIsUsingStepTiming ? m_pSteps -> m_Attacks : m_pSong -> m_Attacks );
int index = FindAttackAtTime ( attacks , start );
if ( index >= 0 )
{
po . FromString ( "" );
}
if ( m_NoteFieldEdit . m_iEndMarker == - 1 )
{
end = m_pSong -> m_fMusicLengthSeconds ;
}
else
{
end = timing . GetElapsedTimeFromBeat ( NoteRowToBeat ( m_NoteFieldEdit . m_iEndMarker ));
}
}
2011-07-12 22:27:14 -04:00
ModsGroup < PlayerOptions > & toEdit = GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_PlayerOptions ;
this -> originalPlayerOptions . Assign ( ModsLevel_Preferred , toEdit . GetPreferred ());
2011-06-24 19:32:46 -04:00
g_fLastInsertAttackPositionSeconds = start ;
g_fLastInsertAttackDurationSeconds = end - start ;
2011-07-12 22:27:14 -04:00
toEdit . Assign ( ModsLevel_Stage , po );
2011-06-24 19:32:46 -04:00
SCREENMAN -> AddNewScreenToTop ( "ScreenPlayerOptions" , SM_BackFromInsertStepAttackPlayerOptions );
break ;
}
2011-03-17 01:43:45 -04:00
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
{
2011-05-13 10:07:41 -04:00
// TODO: Give Song/Step Timing switches/functions here?
2011-05-10 16:55:00 +07:00
fStart = m_pSteps -> m_Timing . GetElapsedTimeFromBeat ( NoteRowToBeat ( m_NoteFieldEdit . m_iBeginMarker ) );
2011-03-17 01:43:45 -04:00
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
2011-05-10 16:55:00 +07:00
fEnd = m_pSteps -> m_Timing . GetElapsedTimeFromBeat ( NoteRowToBeat ( m_NoteFieldEdit . m_iEndMarker ) );
2011-03-17 01:43:45 -04:00
}
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 ;
2011-05-10 21:21:23 +07:00
bgChange . m_fStartBeat = GAMESTATE -> m_Position . m_fSongBeat ;
2011-03-17 01:43:45 -04:00
FOREACH ( BackgroundChange , m_pSong -> GetBackgroundChanges ( iLayer ), bgc )
{
2011-05-10 21:21:23 +07:00
if ( bgc -> m_fStartBeat == GAMESTATE -> m_Position . m_fSongBeat )
2011-03-17 01:43:45 -04:00
{
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 )
{
2011-06-10 03:04:47 -04:00
HandleAlterMenuChoice ( record );
2011-03-17 01:43:45 -04:00
}
else
{
if ( g_iDefaultRecordLength . Get () == - 1 )
{
2011-06-01 14:01:35 -04:00
m_iStartPlayingAt = BeatToNoteRow ( GetAppropriatePosition (). m_fSongBeat );
2011-03-17 01:43:45 -04:00
m_iStopPlayingAt = max ( m_iStartPlayingAt , m_NoteDataEdit . GetLastRow () + 1 );
}
else
{
2011-06-01 14:01:35 -04:00
m_iStartPlayingAt = BeatToNoteRow ( ftruncf ( GetAppropriatePosition (). m_fSongBeat , g_iDefaultRecordLength . Get ()) );
2011-03-17 01:43:45 -04:00
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 :
2011-06-01 14:01:35 -04:00
m_iStartPlayingAt = BeatToNoteRow ( GetAppropriatePosition (). m_fSongBeat );
2011-03-17 01:43:45 -04:00
m_iStopPlayingAt = max ( m_iStartPlayingAt , m_NoteDataEdit . GetLastRow () );
TransitionEditState ( STATE_RECORDING );
break ;
case EDIT_BUTTON_INSERT :
2011-05-15 00:09:44 -04:00
HandleAreaMenuChoice ( insert_and_shift );
2011-03-17 01:43:45 -04:00
SCREENMAN -> PlayInvalidSound ();
break ;
case EDIT_BUTTON_INSERT_SHIFT_PAUSES :
HandleAreaMenuChoice ( shift_pauses_forward );
SCREENMAN -> PlayInvalidSound ();
break ;
case EDIT_BUTTON_DELETE :
2011-05-15 00:09:44 -04:00
HandleAreaMenuChoice ( delete_and_shift );
2011-03-17 01:43:45 -04:00
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 ;
2011-05-13 08:50:59 -04:00
m_soundSwitchPlayer . Play ();
2011-03-17 01:43:45 -04:00
}
break ;
2011-05-12 23:18:57 -04:00
case EDIT_BUTTON_SWITCH_TIMINGS :
2011-05-17 00:07:43 -04:00
GAMESTATE -> m_bIsUsingStepTiming = ! GAMESTATE -> m_bIsUsingStepTiming ;
2011-05-13 08:50:59 -04:00
m_soundSwitchTiming . Play ();
2011-05-12 23:18:57 -04:00
break ;
2011-06-06 18:27:52 -04:00
default : break ;
2011-03-17 01:43:45 -04:00
}
}
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
2011-05-13 10:51:09 -04:00
float fBeat = GetBeat ();
2011-03-17 01:43:45 -04:00
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 :
2011-05-15 00:09:44 -04:00
TransitionEditState ( STATE_RECORDING );
2011-03-17 01:43:45 -04:00
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 ;
2011-06-06 18:27:52 -04:00
default : break ;
2011-03-17 01:43:45 -04:00
}
}
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 )
{
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:
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 ;
2011-06-06 18:27:52 -04:00
default : break ;
2011-03-17 01:43:45 -04:00
}
}
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. */
2011-06-01 14:01:35 -04:00
m_fBeatToReturnTo = GetAppropriatePosition (). m_fSongBeat ;
2011-03-17 01:43:45 -04:00
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 ;
}
2011-05-13 10:07:41 -04:00
GetAppropriateTiming (). m_fBeat0OffsetInSeconds += fOffsetDelta ;
2011-07-12 22:42:53 -04:00
if ( ! GAMESTATE -> m_bIsUsingStepTiming )
{
GAMESTATE -> m_pCurSong -> m_fMusicSampleStartSeconds += fOffsetDelta ;
}
2011-03-17 01:43:45 -04:00
}
break ;
2011-06-06 18:27:52 -04:00
default : break ;
2011-03-17 01:43:45 -04:00
}
}
}
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.
2011-06-01 14:01:35 -04:00
m_fBeatToReturnTo = GetAppropriatePosition (). m_fSongBeat ;
2011-03-17 01:43:45 -04:00
break ;
case STATE_PLAYING :
AdjustSync :: HandleSongEnd ();
2011-06-01 15:27:14 -04:00
if ( ! GAMESTATE -> m_bIsUsingStepTiming )
GAMESTATE -> m_pCurSteps [ PLAYER_1 ] -> m_Timing = backupStepTiming ;
2011-03-17 01:43:45 -04:00
if ( AdjustSync :: IsSyncDataChanged () )
ScreenSaveSync :: PromptSaveSync ();
break ;
case STATE_RECORDING :
SetDirty ( true );
2011-06-01 15:27:14 -04:00
if ( ! GAMESTATE -> m_bIsUsingStepTiming )
GAMESTATE -> m_pCurSteps [ PLAYER_1 ] -> m_Timing = backupStepTiming ;
2011-03-17 01:43:45 -04:00
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 ;
2011-06-06 18:27:52 -04:00
default : break ;
2011-03-17 01:43:45 -04:00
}
}
// 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 ();
// 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-05-13 14:14:57 +07:00
// Restore the cursor position + Quantize + Clamp
SetBeat ( max ( 0 , Quantize ( m_fBeatToReturnTo , NoteTypeToBeat ( m_SnapDisplay . GetNoteType ()) ) ) );
2011-05-15 21:15:53 -04:00
GAMESTATE -> m_bInStepEditor = true ;
2011-03-17 01:43:45 -04:00
break ;
case STATE_PLAYING :
case STATE_RECORDING :
{
if ( bStateChanging )
AdjustSync :: ResetOriginalSyncData ();
2011-05-13 10:07:41 -04:00
/* Give a 1 second lead-in. If we're loading Player, this must be done first.
* Also be sure to get the right timing. */
float fSeconds = GetAppropriateTiming (). GetElapsedTimeFromBeat ( NoteRowToBeat ( m_iStartPlayingAt ) ) - 1 ;
GAMESTATE -> UpdateSongPosition ( fSeconds , GetAppropriateTiming (), RageZeroTimer , true );
2011-03-17 01:43:45 -04:00
GAMESTATE -> m_bGameplayLeadIn . Set ( false );
2011-06-01 15:27:14 -04:00
if ( ! GAMESTATE -> m_bIsUsingStepTiming )
{
2011-07-23 01:45:10 -04:00
backupStepTiming = GAMESTATE -> m_pCurSteps [ PLAYER_1 ] -> m_Timing ;
2011-06-01 15:27:14 -04:00
GAMESTATE -> m_pCurSteps [ PLAYER_1 ] -> m_Timing = GAMESTATE -> m_pCurSong -> m_SongTiming ;
}
2011-03-17 01:43:45 -04:00
/* Reset the note skin, in case preferences have changed. */
// XXX
// GAMESTATE->ResetNoteSkins();
//GAMESTATE->res
2011-05-15 21:15:53 -04:00
GAMESTATE -> m_bInStepEditor = false ;
2011-03-17 01:43:45 -04:00
break ;
}
case STATE_RECORDING_PAUSED :
2011-05-15 21:15:53 -04:00
GAMESTATE -> m_bInStepEditor = false ;
2011-03-17 01:43:45 -04:00
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 );
2011-07-05 15:04:24 -04:00
m_pSong -> ReCalculateRadarValuesAndLastSecond ();
2011-03-17 01:43:45 -04:00
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 ;
2011-06-06 18:27:52 -04:00
default : break ;
2011-03-17 01:43:45 -04:00
}
// 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 :
2011-06-06 18:27:52 -04:00
{
2011-05-13 10:07:41 -04:00
const float fStartSeconds = GetAppropriateTiming (). GetElapsedTimeFromBeat ( GetBeat () );
2011-03-17 01:43:45 -04:00
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 ;
2011-06-06 18:27:52 -04:00
}
default : break ;
2011-03-17 01:43:45 -04:00
}
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.
2011-06-01 14:20:41 -04:00
const float fOriginalBeat = GetAppropriatePosition (). m_fSongBeat ;
2011-03-17 01:43:45 -04:00
if ( fOriginalBeat == fDestinationBeat )
return ;
2011-05-13 14:14:57 +07:00
SetBeat ( fDestinationBeat );
2011-03-17 01:43:45 -04:00
// 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 ;
2011-05-15 00:09:44 -04:00
// create a new hold note
int iStartRow = BeatToNoteRow ( min ( fOriginalBeat , fDestinationBeat ) );
int iEndRow = BeatToNoteRow ( max ( fOriginalBeat , fDestinationBeat ) );
2011-03-17 01:43:45 -04:00
2011-05-15 00:09:44 -04:00
// 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.
TapNote tn = EditIsBeingPressed ( EDIT_BUTTON_LAY_ROLL ) ? TAP_ORIGINAL_ROLL_HEAD : TAP_ORIGINAL_HOLD_HEAD ;
2011-03-17 01:43:45 -04:00
2011-05-15 00:09:44 -04:00
tn . pn = m_InputPlayerNumber ;
m_NoteDataEdit . AddHoldNote ( iCol , iStartRow , iEndRow , tn );
2011-03-17 01:43:45 -04:00
}
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 )
{
2011-07-26 16:05:14 -04:00
AreaMenuChoice amc = static_cast < AreaMenuChoice > ( ScreenMiniMenu :: s_iLastRowCode );
const vector < int > & answers = ScreenMiniMenu :: s_viLastAnswers ;
HandleAreaMenuChoice ( amc , answers );
2011-03-17 01:43:45 -04:00
}
2011-06-10 03:04:47 -04:00
else if ( SM == SM_BackFromAlterMenu )
{
HandleAlterMenuChoice ( ( AlterMenuChoice ) ScreenMiniMenu :: s_iLastRowCode , ScreenMiniMenu :: s_viLastAnswers );
}
2011-03-17 01:43:45 -04:00
else if ( SM == SM_BackFromStepsInformation )
{
HandleStepsInformationChoice ( ( StepsInformationChoice ) ScreenMiniMenu :: s_iLastRowCode , ScreenMiniMenu :: s_viLastAnswers );
}
2011-07-07 17:52:30 -04:00
else if ( SM == SM_BackFromStepsData )
{
HandleStepsDataChoice (( StepsDataChoice ) ScreenMiniMenu :: s_iLastRowCode ,
ScreenMiniMenu :: s_viLastAnswers );
}
2011-03-17 01:43:45 -04:00
else if ( SM == SM_BackFromSongInformation )
{
HandleSongInformationChoice ( ( SongInformationChoice ) ScreenMiniMenu :: s_iLastRowCode , ScreenMiniMenu :: s_viLastAnswers );
}
else if ( SM == SM_BackFromTimingDataInformation )
{
HandleTimingDataInformationChoice ( ( TimingDataInformationChoice ) ScreenMiniMenu :: s_iLastRowCode , ScreenMiniMenu :: s_viLastAnswers );
}
2011-05-07 19:18:03 -04:00
else if ( SM == SM_BackFromDifficultyMeterChange )
{
2011-05-11 15:58:31 -04:00
int i = StringToInt ( ScreenTextEntry :: s_sLastAnswer );
2011-05-07 19:18:03 -04:00
GAMESTATE -> m_pCurSteps [ PLAYER_1 ] -> SetMeter ( i );
SetDirty ( true );
}
2011-05-29 23:42:14 +07:00
else if ( SM == SM_BackFromBPMChange && ! ScreenTextEntry :: s_bCancelledLast )
2011-03-17 01:43:45 -04:00
{
float fBPM = StringToFloat ( ScreenTextEntry :: s_sLastAnswer );
2011-09-15 03:28:58 +00:00
2011-03-17 01:43:45 -04:00
if ( fBPM > 0 )
2011-09-15 03:28:58 +00:00
GetAppropriateTiming (). AddSegment ( BPMSegment ( GetRow (), fBPM ) );
2011-03-17 01:43:45 -04:00
SetDirty ( true );
}
2011-05-29 23:42:14 +07:00
else if ( SM == SM_BackFromStopChange && ! ScreenTextEntry :: s_bCancelledLast )
2011-03-17 01:43:45 -04:00
{
float fStop = StringToFloat ( ScreenTextEntry :: s_sLastAnswer );
2011-09-15 03:28:58 +00:00
2011-03-17 01:43:45 -04:00
if ( fStop >= 0 )
2011-09-15 03:28:58 +00:00
GetAppropriateTiming (). AddSegment ( StopSegment ( GetRow (), fStop ) );
2011-03-17 01:43:45 -04:00
SetDirty ( true );
}
2011-05-29 23:42:14 +07:00
else if ( SM == SM_BackFromDelayChange && ! ScreenTextEntry :: s_bCancelledLast )
2011-03-17 01:43:45 -04:00
{
float fDelay = StringToFloat ( ScreenTextEntry :: s_sLastAnswer );
2011-09-15 03:28:58 +00:00
2011-03-17 01:43:45 -04:00
if ( fDelay >= 0 )
2011-09-15 03:28:58 +00:00
GetAppropriateTiming (). AddSegment ( DelaySegment ( GetRow (), fDelay ) );
2011-03-17 01:43:45 -04:00
SetDirty ( true );
}
2011-05-29 23:42:14 +07:00
else if ( SM == SM_BackFromTimeSignatureChange && ! ScreenTextEntry :: s_bCancelledLast )
2011-03-17 01:43:45 -04:00
{
2011-05-16 23:05:51 +07:00
int iNum , iDen ;
2011-09-15 03:28:58 +00:00
2011-05-16 23:35:40 +07:00
if ( sscanf ( ScreenTextEntry :: s_sLastAnswer . c_str (), " %d / %d " , & iNum , & iDen ) == 2 )
2011-09-15 03:28:58 +00:00
GetAppropriateTiming (). AddSegment ( TimeSignatureSegment ( GetRow (), iNum , iDen ) );
2011-03-17 01:43:45 -04:00
SetDirty ( true );
}
2011-05-29 23:42:14 +07:00
else if ( SM == SM_BackFromTickcountChange && ! ScreenTextEntry :: s_bCancelledLast )
2011-03-17 01:43:45 -04:00
{
2011-05-11 15:58:31 -04:00
int iTick = StringToInt ( ScreenTextEntry :: s_sLastAnswer );
2011-09-15 03:28:58 +00:00
2011-03-17 01:43:45 -04:00
if ( iTick >= 0 && iTick <= ROWS_PER_BEAT )
2011-09-15 03:28:58 +00:00
GetAppropriateTiming (). AddSegment ( TickcountSegment ( GetRow (), iTick ) );
2011-03-17 01:43:45 -04:00
SetDirty ( true );
}
2011-05-29 23:42:14 +07:00
else if ( SM == SM_BackFromComboChange && ! ScreenTextEntry :: s_bCancelledLast )
2011-03-17 01:43:45 -04:00
{
2011-07-09 02:28:15 -04:00
int iCombo , iMiss ;
2011-09-15 03:28:58 +00:00
2011-07-09 02:28:15 -04:00
if ( sscanf ( ScreenTextEntry :: s_sLastAnswer . c_str (), " %d / %d " , & iCombo , & iMiss ) == 2 )
2011-09-15 03:28:58 +00:00
GetAppropriateTiming (). AddSegment ( ComboSegment ( GetRow (), iCombo , iMiss ) );
2011-03-17 01:43:45 -04:00
SetDirty ( true );
}
2011-05-29 23:42:14 +07:00
else if ( SM == SM_BackFromLabelChange && ! ScreenTextEntry :: s_bCancelledLast )
2011-04-05 00:35:45 -04:00
{
RString sLabel = ScreenTextEntry :: s_sLastAnswer ;
2011-09-15 03:28:58 +00:00
2011-05-12 23:25:50 -04:00
if ( ! GetAppropriateTiming (). DoesLabelExist ( sLabel ) )
2011-04-05 01:21:54 -04:00
{
2011-09-15 03:28:58 +00:00
// XXX: these should be in the NotesWriters where they're needed.
2011-04-05 01:21:54 -04:00
sLabel . Replace ( "=" , "_" );
sLabel . Replace ( "," , "_" );
2011-09-15 03:28:58 +00:00
GetAppropriateTiming (). AddSegment ( LabelSegment ( GetRow (), sLabel ) );
2011-04-05 14:18:29 -04:00
SetDirty ( true );
2011-04-05 01:21:54 -04:00
}
2011-04-05 00:35:45 -04:00
}
2011-05-29 23:42:14 +07:00
else if ( SM == SM_BackFromWarpChange && ! ScreenTextEntry :: s_bCancelledLast )
2011-03-25 17:40:56 -04:00
{
float fWarp = StringToFloat ( ScreenTextEntry :: s_sLastAnswer );
2011-05-16 10:57:14 -04:00
if ( fWarp >= 0 ) // allow 0 to kill a warp.
2011-05-16 10:56:00 -04:00
{
GetAppropriateTiming (). SetWarpAtBeat ( GetBeat (), fWarp );
SetDirty ( true );
}
2011-03-25 17:40:56 -04:00
}
2011-05-29 23:42:14 +07:00
else if ( SM == SM_BackFromSpeedPercentChange && ! ScreenTextEntry :: s_bCancelledLast )
2011-05-15 15:53:20 -04:00
{
float fNum = StringToFloat ( ScreenTextEntry :: s_sLastAnswer );
GetAppropriateTiming (). SetSpeedPercentAtBeat ( GetBeat (), fNum );
SetDirty ( true );
}
2011-05-29 23:42:14 +07:00
else if ( SM == SM_BackFromSpeedWaitChange && ! ScreenTextEntry :: s_bCancelledLast )
2011-05-15 15:53:20 -04:00
{
float fDen = StringToFloat ( ScreenTextEntry :: s_sLastAnswer );
if ( fDen >= 0 )
{
GetAppropriateTiming (). SetSpeedWaitAtBeat ( GetBeat (), fDen );
}
SetDirty ( true );
}
2011-05-29 23:42:14 +07:00
else if ( SM == SM_BackFromSpeedModeChange && ! ScreenTextEntry :: s_bCancelledLast )
2011-05-15 23:48:03 -04:00
{
2011-05-16 22:44:56 +07:00
if ( ScreenTextEntry :: s_sLastAnswer . substr ( 0 , 1 ) == "b" || ScreenTextEntry :: s_sLastAnswer . substr ( 0 , 1 ) == "B" )
2011-05-15 23:48:03 -04:00
{
2011-09-11 17:13:10 +00:00
GetAppropriateTiming (). SetSpeedModeAtBeat ( GetBeat (), SpeedSegment :: UNIT_BEATS );
2011-05-15 23:48:03 -04:00
}
2011-05-16 22:44:56 +07:00
else if ( ScreenTextEntry :: s_sLastAnswer . substr ( 0 , 1 ) == "s" || ScreenTextEntry :: s_sLastAnswer . substr ( 0 , 1 ) == "S" )
2011-05-15 23:48:03 -04:00
{
2011-09-11 17:13:10 +00:00
GetAppropriateTiming (). SetSpeedModeAtBeat ( GetBeat (), SpeedSegment :: UNIT_SECONDS );
2011-05-15 23:48:03 -04:00
}
2011-05-16 22:44:56 +07:00
else
{
int tmp = StringToInt ( ScreenTextEntry :: s_sLastAnswer );
2011-09-11 17:13:10 +00:00
SpeedSegment :: BaseUnit unit = ( tmp == 0 ) ?
SpeedSegment :: UNIT_BEATS : SpeedSegment :: UNIT_SECONDS ;
GetAppropriateTiming (). SetSpeedModeAtBeat ( GetBeat (), unit );
2011-05-16 22:44:56 +07:00
}
2011-05-15 23:48:03 -04:00
SetDirty ( true );
}
2011-05-29 23:42:14 +07:00
else if ( SM == SM_BackFromScrollChange && ! ScreenTextEntry :: s_bCancelledLast )
2011-05-25 22:44:41 +07:00
{
float fNum = StringToFloat ( ScreenTextEntry :: s_sLastAnswer );
GetAppropriateTiming (). SetScrollAtBeat ( GetBeat (), fNum );
SetDirty ( true );
}
2011-05-29 23:42:14 +07:00
else if ( SM == SM_BackFromFakeChange && ! ScreenTextEntry :: s_bCancelledLast )
2011-05-16 11:30:39 -04:00
{
float fFake = StringToFloat ( ScreenTextEntry :: s_sLastAnswer );
if ( fFake >= 0 ) // allow 0 to kill a warp.
{
2011-09-15 03:28:58 +00:00
GetAppropriateTiming (). AddSegment ( FakeSegment ( GetRow (), fFake ) );
2011-05-16 11:30:39 -04:00
SetDirty ( true );
}
}
2011-05-15 15:53:20 -04:00
2011-03-17 01:43:45 -04: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 ();
2011-05-10 21:21:23 +07:00
const int row = BeatToNoteRow ( GAMESTATE -> m_Position . m_fSongBeat );
2011-03-17 01:43:45 -04:00
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 ();
}
2011-06-24 19:32:46 -04:00
else if ( SM == SM_BackFromInsertStepAttack )
{
int iDurationChoice = ScreenMiniMenu :: s_viLastAnswers [ 0 ];
TimingData & timing = GetAppropriateTiming ();
g_fLastInsertAttackPositionSeconds = timing . GetElapsedTimeFromBeat ( GetBeat () );
2011-07-12 21:56:17 -04:00
g_fLastInsertAttackDurationSeconds = StringToFloat ( g_InsertStepAttack . rows [ 0 ]. choices [ iDurationChoice ] );
2011-06-24 19:32:46 -04:00
AttackArray & attacks = GAMESTATE -> m_bIsUsingStepTiming ? m_pSteps -> m_Attacks : m_pSong -> m_Attacks ;
int iAttack = FindAttackAtTime ( attacks , g_fLastInsertAttackPositionSeconds );
if ( ScreenMiniMenu :: s_iLastRowCode == ScreenEdit :: remove )
{
2011-07-03 22:31:47 -04:00
if ( iAttack > 0 )
attacks . erase ( attacks . begin () + iAttack );
2011-06-24 19:32:46 -04:00
}
else
{
2011-07-12 22:27:14 -04:00
ModsGroup < PlayerOptions > & toEdit = GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_PlayerOptions ;
this -> originalPlayerOptions . Assign ( ModsLevel_Preferred , toEdit . GetPreferred ());
2011-06-24 19:32:46 -04:00
PlayerOptions po ;
if ( iAttack >= 0 )
po . FromString ( attacks [ iAttack ]. sModifiers );
2011-07-12 22:27:14 -04:00
toEdit . Assign ( ModsLevel_Preferred , po );
2011-06-24 19:32:46 -04:00
SCREENMAN -> AddNewScreenToTop ( "ScreenPlayerOptions" , SM_BackFromInsertStepAttackPlayerOptions );
}
}
2011-03-17 01:43:45 -04:00
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 ;
2011-05-13 10:07:41 -04:00
// TODO: Handle Song/Step Timing functions/switches here?
2011-03-17 01:43:45 -04:00
2011-05-10 21:21:23 +07:00
g_fLastInsertAttackPositionSeconds = m_pSteps -> m_Timing . GetElapsedTimeFromBeat ( GAMESTATE -> m_Position . m_fSongBeat );
2011-03-17 01:43:45 -04:00
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 );
}
}
2011-06-24 19:32:46 -04:00
else if ( SM == SM_BackFromInsertStepAttackPlayerOptions )
{
2011-07-12 22:27:14 -04:00
ModsGroup < PlayerOptions > & toRestore = GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_PlayerOptions ;
PlayerOptions poChosen = toRestore . GetPreferred ();
2011-06-24 19:32:46 -04:00
RString mods = poChosen . GetString ();
if ( g_fLastInsertAttackPositionSeconds >= 0 )
{
Attack a ( ATTACK_LEVEL_1 ,
g_fLastInsertAttackPositionSeconds ,
g_fLastInsertAttackDurationSeconds ,
mods ,
false ,
false );
AttackArray & attacks = GAMESTATE -> m_bIsUsingStepTiming ? m_pSteps -> m_Attacks : m_pSong -> m_Attacks ;
int index = FindAttackAtTime ( attacks , g_fLastInsertAttackPositionSeconds );
if ( index >= 0 )
attacks [ index ] = a ;
else
attacks . push_back ( a );
}
2011-07-12 22:27:14 -04:00
toRestore . Assign ( ModsLevel_Preferred , this -> originalPlayerOptions . GetPreferred ());
2011-06-24 19:32:46 -04:00
}
2011-03-17 01:43:45 -04:00
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 );
}
}
2011-05-14 02:14:00 -04:00
else if ( SM == SM_DoEraseStepTiming )
2011-05-14 00:43:06 -05:00
{
if ( ScreenPrompt :: s_LastAnswer == ANSWER_YES )
{
SaveUndo ();
m_pSteps -> m_Timing = m_pSong -> m_SongTiming ;
SetDirty ( true );
}
}
2011-03-17 01:43:45 -04:00
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 :
// Don't save; just exit.
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
{
/* We committed the steps to SongManager. Revert to the last save, and
* recommit the reversion to SongManager. */
LOG -> Trace ( "Save failed. Changes uncommitted from memory." );
CopyFromLastSave ();
m_pSteps -> SetNoteData ( m_NoteDataEdit );
}
else if ( SM == SM_DoExit )
{
// IMPORTANT: CopyFromLastSave before deleting the Steps below
CopyFromLastSave ();
/* 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 */
// At this point, the last good song copy is in use.
Song * pSong = GAMESTATE -> m_pCurSong ;
const vector < Steps *> & apSteps = pSong -> GetAllSteps ();
vector < Steps *> apToDelete ;
FOREACH_CONST ( Steps * , apSteps , s )
{
// If we're not on the same style, let it go.
if ( GAMESTATE -> m_pCurSteps [ PLAYER_1 ] -> m_StepsType != ( * s ) -> m_StepsType )
continue ;
// If autogenned, it isn't being saved.
if ( ( * s ) -> IsAutogen () )
continue ;
// If the notedata has content, let it go.
2011-03-17 12:31:16 -04:00
if ( ! ( * s ) -> GetNoteData (). IsEmpty () )
2011-03-17 01:43:45 -04:00
continue ;
// It's hard to say if these steps were saved to disk or not.
/*
if( !(*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 );
}
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. */
2011-05-13 14:14:57 +07:00
SetBeat ( m_fTrailingBeat );
2011-03-17 01:43:45 -04:00
}
else if ( SM == SM_LoseFocus )
{
// Snap the trailing beat, in case we lose focus while tweening.
2011-05-13 15:19:42 +07:00
m_fTrailingBeat = GetBeat (); //GAMESTATE->m_pPlayerState[PLAYER_1]->m_Position.m_fSongBeat;
2011-03-17 01:43:45 -04:00
}
ScreenWithMenuElements :: HandleScreenMessage ( SM );
}
void ScreenEdit :: OnSnapModeChange ()
{
m_soundChangeSnap . Play ();
NoteType nt = m_SnapDisplay . GetNoteType ();
2011-05-13 14:14:57 +07:00
int iStepIndex = BeatToNoteRow ( GetBeat () );
2011-03-17 01:43:45 -04:00
int iElementsPerNoteType = BeatToNoteRow ( NoteTypeToBeat ( nt ) );
int iStepIndexHangover = iStepIndex % iElementsPerNoteType ;
2011-05-13 14:14:57 +07:00
SetBeat ( GetBeat () - NoteRowToBeat ( iStepIndexHangover ) );
2011-03-17 01:43:45 -04:00
}
// Helper function for below
// Begin helper functions for InputEdit
static void ChangeDescription ( const RString & sNew )
{
Steps * pSteps = GAMESTATE -> m_pCurSteps [ PLAYER_1 ];
// Don't erase edit descriptions.
if ( sNew . empty () && pSteps -> GetDifficulty () == Difficulty_Edit )
return ;
pSteps -> SetDescription ( sNew );
}
2011-07-07 14:20:21 -04:00
static void ChangeChartName ( const RString & sNew )
{
Steps * pSteps = GAMESTATE -> m_pCurSteps [ PLAYER_1 ];
pSteps -> SetChartName ( sNew );
}
2011-03-17 01:43:45 -04:00
static void ChangeChartStyle ( const RString & sNew )
{
Steps * pSteps = GAMESTATE -> m_pCurSteps [ PLAYER_1 ];
pSteps -> SetChartStyle ( sNew );
}
static void ChangeStepCredit ( const RString & sNew )
{
Steps * pSteps = GAMESTATE -> m_pCurSteps [ PLAYER_1 ];
pSteps -> SetCredit ( sNew );
}
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 ;
}
static void ChangeGenre ( const RString & sNew )
{
Song * pSong = GAMESTATE -> m_pCurSong ;
pSong -> m_sGenre = sNew ;
}
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 ;
}
2011-05-03 09:18:31 -04:00
static void ChangeBeat0Offset ( const RString & sNew )
{
2011-09-15 03:28:58 +00:00
TimingData & timing = ( GAMESTATE -> m_bIsUsingStepTiming ?
GAMESTATE -> m_pCurSteps [ PLAYER_1 ] -> m_Timing :
2011-06-30 01:11:38 -04:00
GAMESTATE -> m_pCurSong -> m_SongTiming );
2011-06-30 13:35:25 -04:00
float old = timing . m_fBeat0OffsetInSeconds ;
2011-09-15 03:28:58 +00:00
timing . m_fBeat0OffsetInSeconds = StringToFloat ( sNew );
2011-06-30 13:35:25 -04:00
float delta = timing . m_fBeat0OffsetInSeconds - old ;
2011-09-15 03:28:58 +00:00
2011-06-30 13:35:25 -04:00
if ( GAMESTATE -> m_bIsUsingStepTiming )
{
GAMESTATE -> m_pCurSteps [ PLAYER_1 ] -> m_Attacks . UpdateStartTimes ( delta );
}
else
{
GAMESTATE -> m_pCurSong -> m_Attacks . UpdateStartTimes ( delta );
2011-07-12 22:42:53 -04:00
GAMESTATE -> m_pCurSong -> m_fMusicSampleStartSeconds += delta ;
2011-06-30 13:35:25 -04:00
}
2011-05-03 09:18:31 -04:00
}
2011-06-30 01:11:38 -04:00
static void ChangeLastSecondHint ( const RString & sNew )
2011-03-17 01:43:45 -04:00
{
2011-06-30 01:11:38 -04:00
Song & s = * GAMESTATE -> m_pCurSong ;
2011-06-30 02:19:37 -04:00
s . SetSpecifiedLastSecond ( StringToFloat ( sNew ));
2011-03-17 01:43:45 -04:00
}
2011-05-03 09:18:31 -04:00
static void ChangePreviewStart ( const RString & sNew )
{
GAMESTATE -> m_pCurSong -> m_fMusicSampleStartSeconds = StringToFloat ( sNew );
}
static void ChangePreviewLength ( const RString & sNew )
{
GAMESTATE -> m_pCurSong -> m_fMusicSampleLengthSeconds = StringToFloat ( sNew );
}
2011-04-05 22:40:33 -04:00
static void ChangeMinBPM ( const RString & sNew )
{
GAMESTATE -> m_pCurSong -> m_fSpecifiedBPMMin = StringToFloat ( sNew );
}
2011-07-07 18:10:59 -04:00
static void ChangeStepsMinBPM ( const RString & sNew )
{
Steps * step = GAMESTATE -> m_pCurSteps [ PLAYER_1 ];
step -> SetMinBPM ( StringToFloat ( sNew ));
}
2011-04-05 22:40:33 -04:00
static void ChangeMaxBPM ( const RString & sNew )
{
GAMESTATE -> m_pCurSong -> m_fSpecifiedBPMMax = StringToFloat ( sNew );
}
2011-07-07 18:10:59 -04:00
static void ChangeStepsMaxBPM ( const RString & sNew )
{
Steps * step = GAMESTATE -> m_pCurSteps [ PLAYER_1 ];
step -> SetMaxBPM ( StringToFloat ( sNew ));
}
2011-05-12 23:01:19 -04:00
TimingData & ScreenEdit :: GetAppropriateTiming () const
{
2011-05-17 00:07:43 -04:00
if ( GAMESTATE -> m_bIsUsingStepTiming )
2011-05-12 23:01:19 -04:00
{
return m_pSteps -> m_Timing ;
}
return m_pSong -> m_SongTiming ;
}
2011-06-01 13:41:49 -04:00
SongPosition & ScreenEdit :: GetAppropriatePosition () const
{
if ( GAMESTATE -> m_bIsUsingStepTiming )
{
return GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_Position ;
}
return GAMESTATE -> m_Position ;
}
2011-05-13 14:14:57 +07:00
inline void ScreenEdit :: SetBeat ( float fBeat )
{
2011-05-17 00:07:43 -04:00
if ( ! GAMESTATE -> m_bIsUsingStepTiming )
2011-05-13 14:14:57 +07:00
{
GAMESTATE -> m_Position . m_fSongBeat = fBeat ;
GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_Position . m_fSongBeat = m_pSteps -> m_Timing . GetBeatFromElapsedTime ( m_pSong -> m_SongTiming . GetElapsedTimeFromBeat ( fBeat ));
}
else
{
GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_Position . m_fSongBeat = fBeat ;
GAMESTATE -> m_Position . m_fSongBeat = m_pSong -> m_SongTiming . GetBeatFromElapsedTime ( m_pSteps -> m_Timing . GetElapsedTimeFromBeat ( fBeat ));
}
}
inline float ScreenEdit :: GetBeat ()
{
2011-05-17 00:07:43 -04:00
if ( ! GAMESTATE -> m_bIsUsingStepTiming )
2011-05-13 14:14:57 +07:00
{
return GAMESTATE -> m_Position . m_fSongBeat ;
}
return GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_Position . m_fSongBeat ;
}
2011-05-27 13:30:12 -04:00
inline int ScreenEdit :: GetRow ()
{
return BeatToNoteRow ( GetBeat ());
}
2011-05-12 20:55:45 -04:00
void ScreenEdit :: DisplayTimingMenu ()
{
2011-05-13 14:14:57 +07:00
float fBeat = GetBeat ();
2011-05-12 23:01:19 -04:00
TimingData & pTime = GetAppropriateTiming ();
2011-07-14 23:15:48 -04:00
bool bHasSpeedOnThisRow = pTime . GetSpeedSegmentAtBeat ( fBeat ) -> GetBeat () == fBeat ;
2011-09-15 03:28:58 +00:00
2011-06-30 01:11:38 -04:00
g_TimingDataInformation . rows [ beat_0_offset ]. SetOneUnthemedChoice ( ssprintf ( "%.6f" , pTime . m_fBeat0OffsetInSeconds ) );
g_TimingDataInformation . rows [ bpm ]. SetOneUnthemedChoice ( ssprintf ( "%.6f" , pTime . GetBPMAtBeat ( fBeat ) ) );
g_TimingDataInformation . rows [ stop ]. SetOneUnthemedChoice ( ssprintf ( "%.6f" , pTime . GetStopAtBeat ( fBeat ) ) ) ;
g_TimingDataInformation . rows [ delay ]. SetOneUnthemedChoice ( ssprintf ( "%.6f" , pTime . GetDelayAtBeat ( fBeat ) ) );
2011-09-15 03:28:58 +00:00
g_TimingDataInformation . rows [ time_signature ]. SetOneUnthemedChoice (
ssprintf ( "%d / %d" ,
pTime . GetTimeSignatureSegmentAtBeat ( fBeat ) -> GetNum (),
pTime . GetTimeSignatureSegmentAtBeat ( fBeat ) -> GetDen ()
)
);
2011-05-13 16:04:17 -04:00
g_TimingDataInformation . rows [ label ]. SetOneUnthemedChoice ( pTime . GetLabelAtBeat ( fBeat ). c_str () );
g_TimingDataInformation . rows [ tickcount ]. SetOneUnthemedChoice ( ssprintf ( "%d" , pTime . GetTickcountAtBeat ( fBeat ) ) );
2011-07-09 02:28:15 -04:00
g_TimingDataInformation . rows [ combo ]. SetOneUnthemedChoice ( ssprintf ( "%d / %d" ,
pTime . GetComboAtBeat ( fBeat ),
pTime . GetMissComboAtBeat ( fBeat ) ) );
2011-06-30 01:11:38 -04:00
g_TimingDataInformation . rows [ warp ]. SetOneUnthemedChoice ( ssprintf ( "%.6f" , pTime . GetWarpAtBeat ( fBeat ) ) );
g_TimingDataInformation . rows [ speed_percent ]. SetOneUnthemedChoice ( bHasSpeedOnThisRow ? ssprintf ( "%.6f" , pTime . GetSpeedPercentAtBeat ( fBeat ) ) : "---" );
g_TimingDataInformation . rows [ speed_wait ]. SetOneUnthemedChoice ( bHasSpeedOnThisRow ? ssprintf ( "%.6f" , pTime . GetSpeedWaitAtBeat ( fBeat ) ) : "---" );
2011-09-15 03:28:58 +00:00
2011-05-15 23:48:03 -04:00
RString starting = ( pTime . GetSpeedModeAtBeat ( fBeat ) == 1 ? "Seconds" : "Beats" );
g_TimingDataInformation . rows [ speed_mode ]. SetOneUnthemedChoice ( starting . c_str () );
2011-09-15 03:28:58 +00:00
2011-06-30 01:11:38 -04:00
g_TimingDataInformation . rows [ scroll ]. SetOneUnthemedChoice ( ssprintf ( "%.6f" , pTime . GetScrollAtBeat ( fBeat ) ) );
g_TimingDataInformation . rows [ fake ]. SetOneUnthemedChoice ( ssprintf ( "%.6f" , pTime . GetFakeAtBeat ( fBeat ) ) );
2011-09-15 03:28:58 +00:00
2011-09-12 19:43:41 -04:00
g_TimingDataInformation . rows [ speed_wait ]. bEnabled = bHasSpeedOnThisRow ;
g_TimingDataInformation . rows [ speed_mode ]. bEnabled = bHasSpeedOnThisRow ;
2011-09-15 03:28:58 +00:00
2011-05-12 20:55:45 -04:00
EditMiniMenu ( & g_TimingDataInformation , SM_BackFromTimingDataInformation );
}
2011-03-17 01:43:45 -04:00
// 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?" );
void ScreenEdit :: HandleMainMenuChoice ( MainMenuChoice c , const vector < int > & iAnswers )
{
2011-06-08 18:20:37 -04:00
GAMESTATE -> SetProcessedTimingData ( & m_pSteps -> m_Timing );
2011-03-17 01:43:45 -04:00
switch ( c )
{
DEFAULT_FAIL ( c );
case play_selection :
if ( m_NoteFieldEdit . m_iBeginMarker !=- 1 && m_NoteFieldEdit . m_iEndMarker !=- 1 )
2011-06-10 03:04:47 -04:00
HandleAlterMenuChoice ( play );
2011-03-17 01:43:45 -04:00
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 :
{
2011-05-11 20:53:40 +07:00
m_iStartPlayingAt = BeatToNoteRow ( GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_Position . m_fSongBeat );
2011-03-17 01:43:45 -04:00
m_iStopPlayingAt = max ( m_iStartPlayingAt , m_NoteDataEdit . GetLastRow () );
TransitionEditState ( STATE_PLAYING );
}
break ;
case set_selection_start :
{
2011-05-11 20:53:40 +07:00
const int iCurrentRow = BeatToNoteRow ( GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_Position . m_fSongBeat );
2011-03-17 01:43:45 -04:00
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 :
{
2011-05-11 20:53:40 +07:00
const int iCurrentRow = BeatToNoteRow ( GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_Position . m_fSongBeat );
2011-03-17 01:43:45 -04:00
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 ];
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 );
2011-05-09 14:44:19 -04:00
g_StepsInformation . rows [ meter ]. SetOneUnthemedChoice ( ssprintf ( "%d" , pSteps -> GetMeter ()) );
2011-03-17 01:43:45 -04:00
g_StepsInformation . rows [ meter ]. bEnabled = ( EDIT_MODE . GetValue () >= EditMode_Home );
g_StepsInformation . rows [ predict_meter ]. SetOneUnthemedChoice ( ssprintf ( "%.2f" , pSteps -> PredictMeter ()) );
2011-07-07 14:20:21 -04:00
g_StepsInformation . rows [ chartname ]. bEnabled = ( EDIT_MODE . GetValue () >= EditMode_Full );
g_StepsInformation . rows [ chartname ]. SetOneUnthemedChoice ( pSteps -> GetChartName ());
2011-03-17 01:43:45 -04:00
g_StepsInformation . rows [ description ]. bEnabled = ( EDIT_MODE . GetValue () >= EditMode_Full );
g_StepsInformation . rows [ description ]. SetOneUnthemedChoice ( pSteps -> GetDescription () );
g_StepsInformation . rows [ chartstyle ]. bEnabled = ( EDIT_MODE . GetValue () >= EditMode_Full );
g_StepsInformation . rows [ chartstyle ]. SetOneUnthemedChoice ( pSteps -> GetChartStyle () );
g_StepsInformation . rows [ step_credit ]. bEnabled = ( EDIT_MODE . GetValue () >= EditMode_Full );
g_StepsInformation . rows [ step_credit ]. SetOneUnthemedChoice ( pSteps -> GetCredit () );
2011-07-07 18:45:38 -04:00
g_StepsInformation . rows [ step_display_bpm ]. iDefaultChoice = pSteps -> GetDisplayBPM ();
g_StepsInformation . rows [ step_min_bpm ]. SetOneUnthemedChoice ( ssprintf ( "%.6f" , pSteps -> GetMinBPM ()));
g_StepsInformation . rows [ step_max_bpm ]. SetOneUnthemedChoice ( ssprintf ( "%.6f" , pSteps -> GetMaxBPM ()));
2011-03-17 01:43:45 -04:00
EditMiniMenu ( & g_StepsInformation , SM_BackFromStepsInformation , SM_None );
}
break ;
2011-07-07 17:52:30 -04:00
case view_steps_data :
{
float fMusicSeconds = m_pSoundMusic -> GetLengthSeconds ();
2011-07-13 16:07:33 -04:00
Steps * pSteps = GAMESTATE -> m_pCurSteps [ PLAYER_1 ];
const StepsTypeCategory & cat = GAMEMAN -> GetStepsTypeInfo ( pSteps -> m_StepsType ). m_StepsTypeCategory ;
if ( cat == StepsTypeCategory_Couple || cat == StepsTypeCategory_Routine )
{
pair < int , int > tmp = m_NoteDataEdit . GetNumTapNotesTwoPlayer ();
g_StepsData . rows [ tap_notes ]. SetOneUnthemedChoice ( ssprintf ( "%d / %d" , tmp . first , tmp . second ) );
tmp = m_NoteDataEdit . GetNumJumpsTwoPlayer ();
g_StepsData . rows [ jumps ]. SetOneUnthemedChoice ( ssprintf ( "%d / %d" , tmp . first , tmp . second ) );
tmp = m_NoteDataEdit . GetNumHandsTwoPlayer ();
g_StepsData . rows [ hands ]. SetOneUnthemedChoice ( ssprintf ( "%d / %d" , tmp . first , tmp . second ) );
tmp = m_NoteDataEdit . GetNumQuadsTwoPlayer ();
g_StepsData . rows [ quads ]. SetOneUnthemedChoice ( ssprintf ( "%d / %d" , tmp . first , tmp . second ) );
tmp = m_NoteDataEdit . GetNumHoldNotesTwoPlayer ();
g_StepsData . rows [ holds ]. SetOneUnthemedChoice ( ssprintf ( "%d / %d" , tmp . first , tmp . second ) );
tmp = m_NoteDataEdit . GetNumMinesTwoPlayer ();
g_StepsData . rows [ mines ]. SetOneUnthemedChoice ( ssprintf ( "%d / %d" , tmp . first , tmp . second ) );
tmp = m_NoteDataEdit . GetNumRollsTwoPlayer ();
g_StepsData . rows [ rolls ]. SetOneUnthemedChoice ( ssprintf ( "%d / %d" , tmp . first , tmp . second ) );
tmp = m_NoteDataEdit . GetNumLiftsTwoPlayer ();
g_StepsData . rows [ lifts ]. SetOneUnthemedChoice ( ssprintf ( "%d / %d" , tmp . first , tmp . second ) );
tmp = m_NoteDataEdit . GetNumFakesTwoPlayer ();
g_StepsData . rows [ fakes ]. SetOneUnthemedChoice ( ssprintf ( "%d / %d" , tmp . first , tmp . second ) );
}
else
{
g_StepsData . rows [ tap_notes ]. SetOneUnthemedChoice ( ssprintf ( "%d" , m_NoteDataEdit . GetNumTapNotes ()) );
g_StepsData . rows [ jumps ]. SetOneUnthemedChoice ( ssprintf ( "%d" , m_NoteDataEdit . GetNumJumps ()) );
g_StepsData . rows [ hands ]. SetOneUnthemedChoice ( ssprintf ( "%d" , m_NoteDataEdit . GetNumHands ()) );
g_StepsData . rows [ quads ]. SetOneUnthemedChoice ( ssprintf ( "%d" , m_NoteDataEdit . GetNumQuads ()) );
g_StepsData . rows [ holds ]. SetOneUnthemedChoice ( ssprintf ( "%d" , m_NoteDataEdit . GetNumHoldNotes ()) );
g_StepsData . rows [ mines ]. SetOneUnthemedChoice ( ssprintf ( "%d" , m_NoteDataEdit . GetNumMines ()) );
g_StepsData . rows [ rolls ]. SetOneUnthemedChoice ( ssprintf ( "%d" , m_NoteDataEdit . GetNumRolls ()) );
g_StepsData . rows [ lifts ]. SetOneUnthemedChoice ( ssprintf ( "%d" , m_NoteDataEdit . GetNumLifts ()) );
g_StepsData . rows [ fakes ]. SetOneUnthemedChoice ( ssprintf ( "%d" , m_NoteDataEdit . GetNumFakes ()) );
}
2011-07-07 17:52:30 -04:00
g_StepsData . rows [ stream ]. SetOneUnthemedChoice ( ssprintf ( "%.2f" , NoteDataUtil :: GetStreamRadarValue ( m_NoteDataEdit , fMusicSeconds )) );
g_StepsData . rows [ voltage ]. SetOneUnthemedChoice ( ssprintf ( "%.2f" , NoteDataUtil :: GetVoltageRadarValue ( m_NoteDataEdit , fMusicSeconds )) );
g_StepsData . rows [ air ]. SetOneUnthemedChoice ( ssprintf ( "%.2f" , NoteDataUtil :: GetAirRadarValue ( m_NoteDataEdit , fMusicSeconds )) );
g_StepsData . rows [ freeze ]. SetOneUnthemedChoice ( ssprintf ( "%.2f" , NoteDataUtil :: GetFreezeRadarValue ( m_NoteDataEdit , fMusicSeconds )) );
g_StepsData . rows [ chaos ]. SetOneUnthemedChoice ( ssprintf ( "%.2f" , NoteDataUtil :: GetChaosRadarValue ( m_NoteDataEdit , fMusicSeconds )) );
EditMiniMenu ( & g_StepsData , SM_BackFromStepsData , SM_None );
break ;
}
2011-03-17 01:43:45 -04:00
case save :
case save_on_exit :
{
m_CurrentAction = c ;
// copy edit into current Steps
m_pSteps -> SetNoteData ( m_NoteDataEdit );
2011-06-24 22:11:07 -04:00
// don't forget the attacks.
m_pSong -> m_Attacks = GAMESTATE -> m_pCurSong -> m_Attacks ;
m_pSong -> m_sAttackString = GAMESTATE -> m_pCurSong -> m_Attacks . ToVectorString ();
m_pSteps -> m_Attacks = GAMESTATE -> m_pCurSteps [ PLAYER_1 ] -> m_Attacks ;
m_pSteps -> m_sAttackString = GAMESTATE -> m_pCurSteps [ PLAYER_1 ] -> m_Attacks . ToVectorString ();
2011-03-17 01:43:45 -04:00
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 );
g_SongInformation . rows [ genre ]. SetOneUnthemedChoice ( pSong -> m_sGenre );
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 );
2011-06-30 02:19:37 -04:00
g_SongInformation . rows [ last_second_hint ]. SetOneUnthemedChoice ( ssprintf ( "%.6f" , pSong -> GetSpecifiedLastSecond ()) );
2011-06-30 01:11:38 -04:00
g_SongInformation . rows [ preview_start ]. SetOneUnthemedChoice ( ssprintf ( "%.6f" , pSong -> m_fMusicSampleStartSeconds ) );
g_SongInformation . rows [ preview_length ]. SetOneUnthemedChoice ( ssprintf ( "%.6f" , pSong -> m_fMusicSampleLengthSeconds ) );
2011-04-05 22:40:33 -04:00
g_SongInformation . rows [ display_bpm ]. iDefaultChoice = pSong -> m_DisplayBPMType ;
2011-06-30 01:11:38 -04:00
g_SongInformation . rows [ min_bpm ]. SetOneUnthemedChoice ( ssprintf ( "%.6f" , pSong -> m_fSpecifiedBPMMin ) );
g_SongInformation . rows [ max_bpm ]. SetOneUnthemedChoice ( ssprintf ( "%.6f" , pSong -> m_fSpecifiedBPMMax ) );
2011-03-17 01:43:45 -04:00
EditMiniMenu ( & g_SongInformation , SM_BackFromSongInformation );
}
break ;
case edit_timing_data :
{
2011-05-12 20:55:45 -04:00
DisplayTimingMenu ();
2011-03-17 01:43:45 -04:00
}
break ;
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 ;
};
2011-06-08 18:20:37 -04:00
GAMESTATE -> SetProcessedTimingData ( NULL );
2011-03-17 01:43:45 -04:00
}
2011-06-10 03:04:47 -04:00
void ScreenEdit :: HandleAlterMenuChoice ( AlterMenuChoice c , const vector < int > & iAnswers , bool bAllowUndo )
{
2011-07-26 13:55:06 -04:00
ASSERT_M ( m_NoteFieldEdit . m_iBeginMarker !=- 1 && m_NoteFieldEdit . m_iEndMarker !=- 1 ,
"You can only alter a selection of notes with a selection to begin with!" );
2011-06-10 03:04:47 -04:00
bool bSaveUndo = true ;
switch ( c )
{
2011-06-10 16:10:43 -04:00
case play :
case record :
2011-06-10 03:04:47 -04:00
case cut :
case copy :
{
bSaveUndo = false ;
}
default :
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 )
{
case cut :
{
HandleAlterMenuChoice ( copy );
HandleAlterMenuChoice ( clear );
}
break ;
case copy :
{
2011-07-26 13:55:06 -04:00
2011-06-10 03:04:47 -04:00
m_Clipboard . ClearAll ();
m_Clipboard . CopyRange ( m_NoteDataEdit , m_NoteFieldEdit . m_iBeginMarker , m_NoteFieldEdit . m_iEndMarker );
}
break ;
2011-07-26 13:55:06 -04:00
case copy_partial_timing :
{
this -> clipboardTiming = GetAppropriateTiming (). CopyRange ( m_NoteFieldEdit . m_iBeginMarker ,
m_NoteFieldEdit . m_iEndMarker );
break ;
}
2011-06-10 03:04:47 -04:00
case clear :
{
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 );
HandleAlterMenuChoice ( 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 ;
2011-10-16 15:48:50 -04:00
case turn_backwards : NoteDataUtil :: Turn ( m_Clipboard , st , NoteDataUtil :: backwards ); break ;
2011-06-10 03:04:47 -04:00
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 ;
2011-07-07 01:15:06 -04:00
case nomines : NoteDataUtil :: RemoveMines ( m_NoteDataEdit , iBeginRow , iEndRow ); break ;
2011-06-10 03:04:47 -04:00
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 );
HandleAlterMenuChoice ( 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.
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 ;
}
int iStartIndex = m_NoteFieldEdit . m_iBeginMarker ;
int iEndIndex = m_NoteFieldEdit . m_iEndMarker ;
int iNewEndIndex = iEndIndex + lrintf ( ( iEndIndex - iStartIndex ) * ( fScale - 1 ) );
// scale currently editing notes
NoteDataUtil :: ScaleRegion ( m_NoteDataEdit , fScale , iStartIndex , iEndIndex );
// scale timing data
GetAppropriateTiming (). ScaleRegion ( fScale ,
m_NoteFieldEdit . m_iBeginMarker ,
m_NoteFieldEdit . m_iEndMarker , true );
m_NoteFieldEdit . m_iEndMarker = iNewEndIndex ;
break ;
}
case play :
m_iStartPlayingAt = m_NoteFieldEdit . m_iBeginMarker ;
m_iStopPlayingAt = m_NoteFieldEdit . m_iEndMarker ;
TransitionEditState ( STATE_PLAYING );
break ;
case record :
m_iStartPlayingAt = m_NoteFieldEdit . m_iBeginMarker ;
m_iStopPlayingAt = m_NoteFieldEdit . m_iEndMarker ;
TransitionEditState ( STATE_RECORDING );
break ;
2011-06-11 11:15:58 -04:00
case preview_designation :
{
float fMarkerStart = GetAppropriateTiming (). GetElapsedTimeFromBeat ( NoteRowToBeat ( m_NoteFieldEdit . m_iBeginMarker ) );
float fMarkerEnd = GetAppropriateTiming (). GetElapsedTimeFromBeat ( NoteRowToBeat ( m_NoteFieldEdit . m_iEndMarker ) );
GAMESTATE -> m_pCurSong -> m_fMusicSampleStartSeconds = fMarkerStart ;
GAMESTATE -> m_pCurSong -> m_fMusicSampleLengthSeconds = fMarkerEnd - fMarkerStart ;
break ;
}
2011-06-10 16:43:38 -04:00
case convert_to_pause :
{
float fMarkerStart = GetAppropriateTiming (). GetElapsedTimeFromBeat ( NoteRowToBeat ( m_NoteFieldEdit . m_iBeginMarker ) );
float fMarkerEnd = GetAppropriateTiming (). 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
);
GetAppropriateTiming (). DeleteRows ( m_NoteFieldEdit . m_iBeginMarker + 1 ,
m_NoteFieldEdit . m_iEndMarker - m_NoteFieldEdit . m_iBeginMarker );
GetAppropriateTiming (). SetStopAtRow ( m_NoteFieldEdit . m_iBeginMarker , fStopLength );
m_NoteFieldEdit . m_iBeginMarker = - 1 ;
m_NoteFieldEdit . m_iEndMarker = - 1 ;
break ;
}
2011-06-10 17:03:53 -04:00
case convert_to_delay :
{
float fMarkerStart = GetAppropriateTiming (). GetElapsedTimeFromBeat ( NoteRowToBeat ( m_NoteFieldEdit . m_iBeginMarker ) );
float fMarkerEnd = GetAppropriateTiming (). GetElapsedTimeFromBeat ( NoteRowToBeat ( m_NoteFieldEdit . m_iEndMarker ) );
// The length of the delay 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 ;
NoteDataUtil :: DeleteRows ( m_NoteDataEdit ,
m_NoteFieldEdit . m_iBeginMarker ,
m_NoteFieldEdit . m_iEndMarker - m_NoteFieldEdit . m_iBeginMarker
);
GetAppropriateTiming (). DeleteRows ( m_NoteFieldEdit . m_iBeginMarker ,
m_NoteFieldEdit . m_iEndMarker - m_NoteFieldEdit . m_iBeginMarker );
GetAppropriateTiming (). SetDelayAtRow ( m_NoteFieldEdit . m_iBeginMarker , fStopLength );
m_NoteFieldEdit . m_iBeginMarker = - 1 ;
m_NoteFieldEdit . m_iEndMarker = - 1 ;
break ;
}
2011-06-10 16:43:38 -04:00
case convert_to_warp :
{
float startBeat = NoteRowToBeat ( m_NoteFieldEdit . m_iBeginMarker );
float lengthBeat = NoteRowToBeat ( m_NoteFieldEdit . m_iEndMarker ) - startBeat ;
GetAppropriateTiming (). SetWarpAtBeat ( startBeat , lengthBeat );
SetDirty ( true );
break ;
}
2011-07-07 21:41:08 -04:00
case convert_to_attack :
{
float startBeat = NoteRowToBeat ( m_NoteFieldEdit . m_iBeginMarker );
float endBeat = NoteRowToBeat ( m_NoteFieldEdit . m_iEndMarker );
TimingData & timing = GetAppropriateTiming ();
float & start = g_fLastInsertAttackPositionSeconds ;
float & length = g_fLastInsertAttackDurationSeconds ;
start = timing . GetElapsedTimeFromBeat ( startBeat );
length = timing . GetElapsedTimeFromBeat ( endBeat ) - start ;
AttackArray & attacks = GAMESTATE -> m_bIsUsingStepTiming ?
m_pSteps -> m_Attacks : m_pSong -> m_Attacks ;
int iAttack = FindAttackAtTime ( attacks , start );
2011-07-12 22:27:14 -04:00
ModsGroup < PlayerOptions > & toEdit = GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_PlayerOptions ;
this -> originalPlayerOptions . Assign ( ModsLevel_Preferred , toEdit . GetPreferred ());
2011-07-07 21:41:08 -04:00
PlayerOptions po ;
if ( iAttack >= 0 )
po . FromString ( attacks [ iAttack ]. sModifiers );
2011-07-12 22:27:14 -04:00
toEdit . Assign ( ModsLevel_Preferred , po );
2011-07-07 21:41:08 -04:00
SCREENMAN -> AddNewScreenToTop ( "ScreenPlayerOptions" , SM_BackFromInsertStepAttackPlayerOptions );
SetDirty ( true );
break ;
}
2011-06-10 16:52:23 -04:00
case convert_to_fake :
{
2011-09-15 03:28:58 +00:00
int startRow = m_NoteFieldEdit . m_iBeginMarker ;
float lengthBeat = NoteRowToBeat ( m_NoteFieldEdit . m_iEndMarker ) - NoteRowToBeat ( startRow );
GetAppropriateTiming (). AddSegment ( FakeSegment ( startRow , lengthBeat ) );
2011-06-10 16:52:23 -04:00
SetDirty ( true );
break ;
}
2011-07-04 17:30:36 -04:00
case routine_invert_notes :
{
NoteData & nd = this -> m_NoteDataEdit ;
NoteField & nf = this -> m_NoteFieldEdit ;
FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE ( nd , r ,
nf . m_iBeginMarker ,
nf . m_iEndMarker )
{
for ( int t = 0 ; t < nd . GetNumTracks (); t ++ )
{
const TapNote & tn = nd . GetTapNote ( t , r );
if ( tn . type != TapNote :: empty )
{
TapNote nTap = tn ;
nTap . pn = ( tn . pn == PLAYER_1 ?
PLAYER_2 : PLAYER_1 );
m_NoteDataEdit . SetTapNote ( t , r , nTap );
}
}
}
break ;
}
2011-07-04 18:15:21 -04:00
case routine_mirror_1_to_2 :
case routine_mirror_2_to_1 :
{
PlayerNumber oPN = ( c == routine_mirror_1_to_2 ?
PLAYER_1 : PLAYER_2 );
PlayerNumber nPN = ( c == routine_mirror_1_to_2 ?
PLAYER_2 : PLAYER_1 );
int nTrack = - 1 ;
NoteData & nd = this -> m_NoteDataEdit ;
NoteField & nf = this -> m_NoteFieldEdit ;
int tracks = nd . GetNumTracks ();
FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE ( nd , r ,
nf . m_iBeginMarker ,
nf . m_iEndMarker )
{
for ( int t = 0 ; t < tracks ; t ++ )
{
const TapNote & tn = nd . GetTapNote ( t , r );
if ( tn . type != TapNote :: empty && tn . pn == oPN )
{
TapNote nTap = tn ;
nTap . pn = nPN ;
StepsType curType = GAMESTATE -> m_pCurSteps [ PLAYER_1 ] -> m_StepsType ;
2011-07-26 13:55:06 -04:00
// TODO: Find a better way to do this.
2011-07-04 18:15:21 -04:00
if ( curType == StepsType_dance_routine )
{
nTrack = tracks - t - 1 ;
}
else if ( curType == StepsType_pump_routine )
{
switch ( t )
{
case 0 : nTrack = 8 ; break ;
case 1 : nTrack = 9 ; break ;
case 2 : nTrack = 7 ; break ;
case 3 : nTrack = 5 ; break ;
case 4 : nTrack = 6 ; break ;
case 5 : nTrack = 3 ; break ;
case 6 : nTrack = 4 ; break ;
case 7 : nTrack = 2 ; break ;
case 8 : nTrack = 0 ; break ;
case 9 : nTrack = 1 ; break ;
default : FAIL_M ( ssprintf ( "Invalid column %d for pump-routine" , t )); break ;
}
}
m_NoteDataEdit . SetTapNote ( nTrack , r , nTap );
}
}
}
break ;
}
2011-07-20 11:11:04 -04:00
default : break ;
2011-06-10 03:04:47 -04:00
}
2011-03-17 01:43:45 -04:00
}
void ScreenEdit :: HandleAreaMenuChoice ( AreaMenuChoice c , const vector < int > & iAnswers , bool bAllowUndo )
{
2011-06-10 16:10:43 -04:00
bool bSaveUndo = true ;
2011-03-17 01:43:45 -04:00
switch ( c )
{
2011-06-10 16:10:43 -04:00
case clear_clipboard :
2011-03-17 01:43:45 -04:00
case undo :
bSaveUndo = false ;
break ;
2011-06-10 16:10:43 -04:00
default :
2011-03-17 01:43:45 -04:00
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 );
2011-09-15 03:28:58 +00:00
2011-03-17 01:43:45 -04:00
case paste_at_current_beat :
case paste_at_begin_marker :
{
int iDestFirstRow = - 1 ;
switch ( c )
{
DEFAULT_FAIL ( c );
case paste_at_current_beat :
2011-06-01 13:50:42 -04:00
iDestFirstRow = BeatToNoteRow ( GetAppropriatePosition (). m_fSongBeat );
2011-03-17 01:43:45 -04:00
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 ;
2011-07-26 16:05:14 -04:00
case paste_partial_timing_at_beat :
{
2011-09-15 03:28:58 +00:00
#if 0
2011-07-26 16:05:14 -04:00
int firstRow = BeatToNoteRow(GetAppropriatePosition().m_fSongBeat);
2011-09-15 03:28:58 +00:00
FOREACH_TimingSegmentType( tst )
2011-07-26 16:05:14 -04:00
{
/* TODO: Maybe wipe out the already there timing data first?
* We need to identify the max row within the timing data first. */
2011-09-15 03:28:58 +00:00
const vector<TimingSegment*> &vSegs = clipboardTiming.GetTimingSegments(tst);
/* TODO: this is an exact dupe of TimingData::CopyRange... */
for (unsigned i = 0; i < vSegs.size(); i++)
2011-07-26 16:05:14 -04:00
{
2011-09-15 03:28:58 +00:00
const TimingSegment *seg = vSegs[i];
TimingSegment *cpy = seg->Copy();
int oldRow = cpy->GetRow() + firstRow;
2011-07-26 16:05:14 -04:00
int newRow = oldRow + firstRow;
cpy->SetRow(newRow);
2011-09-15 03:28:58 +00:00
GetAppropriateTiming().AddSegment( cpy );
2011-07-26 16:05:14 -04:00
}
}
2011-09-15 03:28:58 +00:00
#endif
2011-07-26 16:05:14 -04:00
break ;
}
2011-11-27 18:33:34 -05:00
2011-03-17 01:43:45 -04:00
case insert_and_shift :
2011-11-27 18:33:34 -05:00
NoteDataUtil :: InsertRows ( m_NoteDataEdit , GetRow (),
iAnswers . size () > 0 ?
NoteTypeToRow (( NoteType ) iAnswers [ c ]) : 48 );
2011-03-17 01:43:45 -04:00
break ;
case delete_and_shift :
2011-11-27 18:33:34 -05:00
NoteDataUtil :: DeleteRows ( m_NoteDataEdit , GetRow (),
iAnswers . size () > 0 ?
NoteTypeToRow (( NoteType ) iAnswers [ c ]) : 48 );
2011-03-17 01:43:45 -04:00
break ;
case shift_pauses_forward :
2011-11-27 18:33:34 -05:00
GetAppropriateTiming (). InsertRows ( GetRow (),
iAnswers . size () > 0 ?
NoteTypeToRow (( NoteType ) iAnswers [ c ]) : 48 );
2011-03-17 01:43:45 -04:00
break ;
case shift_pauses_backward :
2011-11-27 18:33:34 -05:00
GetAppropriateTiming (). DeleteRows ( GetRow () + 1 ,
iAnswers . size () > 0 ?
NoteTypeToRow (( NoteType ) iAnswers [ c ]) : 48 );
2011-03-17 01:43:45 -04:00
break ;
case convert_pause_to_beat :
2011-06-24 00:50:32 -04:00
{
float fStopSeconds = GetAppropriateTiming (). GetStopAtRow ( GetRow ());
GetAppropriateTiming (). SetStopAtBeat ( GetBeat () , 0 );
2011-03-17 01:43:45 -04:00
2011-06-24 00:50:32 -04:00
float fStopBeats = fStopSeconds * GetAppropriateTiming (). GetBPMAtBeat ( GetBeat () ) / 60 ;
2011-03-17 01:43:45 -04:00
2011-06-24 00:50:32 -04:00
// don't move the step from where it is, just move everything later
NoteDataUtil :: InsertRows ( m_NoteDataEdit , GetRow () + 1 , BeatToNoteRow ( fStopBeats ) );
GetAppropriateTiming (). InsertRows ( GetRow () + 1 , BeatToNoteRow ( fStopBeats ) );
}
break ;
case convert_delay_to_beat :
{
TimingData & timing = GetAppropriateTiming ();
float pause = timing . GetDelayAtRow ( GetRow ());
timing . SetDelayAtRow ( GetRow (), 0 );
2011-09-15 03:28:58 +00:00
2011-06-24 00:50:32 -04:00
float pauseBeats = pause * timing . GetBPMAtBeat ( GetBeat ()) / 60 ;
2011-09-15 03:28:58 +00:00
2011-06-24 00:50:32 -04:00
NoteDataUtil :: InsertRows ( m_NoteDataEdit , GetRow (), BeatToNoteRow ( pauseBeats ));
timing . InsertRows ( GetRow (), BeatToNoteRow ( pauseBeats ));
2011-03-17 01:43:45 -04:00
break ;
2011-06-24 00:50:32 -04:00
}
2011-06-30 01:23:59 -04:00
case last_second_at_beat :
{
TimingData & timing = GetAppropriateTiming ();
Song & s = * GAMESTATE -> m_pCurSong ;
2011-06-30 02:19:37 -04:00
s . SetSpecifiedLastSecond ( timing . GetElapsedTimeFromBeat ( GetBeat ()));
2011-06-30 01:23:59 -04:00
break ;
}
2011-03-17 01:43:45 -04:00
case undo :
Undo ();
break ;
2011-06-10 16:10:43 -04:00
case clear_clipboard :
{
m_Clipboard . ClearAll ();
break ;
}
2011-03-17 01:43:45 -04:00
};
if ( bSaveUndo )
CheckNumberOfNotesAndUndo ();
}
2011-07-07 17:52:30 -04:00
void ScreenEdit :: HandleStepsDataChoice ( StepsDataChoice c , const vector < int > & iAnswers )
{
return ; // nothing is done with the choices. Yet.
}
2011-03-17 01:43:45 -04:00
static LocalizedString ENTER_NEW_DESCRIPTION ( "ScreenEdit" , "Enter a new description." );
2011-07-07 15:09:24 -04:00
static LocalizedString ENTER_NEW_CHART_NAME ( "ScreenEdit" , "Enter a new chart name." );
2011-03-17 01:43:45 -04:00
static LocalizedString ENTER_NEW_CHART_STYLE ( "ScreenEdit" , "Enter a new chart style." );
static LocalizedString ENTER_NEW_STEP_AUTHOR ( "ScreenEdit" , "Enter the author who made this step pattern." );
2011-05-07 19:18:03 -04:00
static LocalizedString ENTER_NEW_METER ( "ScreenEdit" , "Enter a new meter." );
2011-07-07 18:10:59 -04:00
static LocalizedString ENTER_MIN_BPM ( "ScreenEdit" , "Enter a new min BPM." );
static LocalizedString ENTER_MAX_BPM ( "ScreenEdit" , "Enter a new max BPM." );
2011-03-17 01:43:45 -04: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 );
2011-07-07 18:10:59 -04:00
pSteps -> SetDisplayBPM ( static_cast < DisplayBPM > ( iAnswers [ step_display_bpm ]));
2011-03-17 01:43:45 -04:00
switch ( c )
{
2011-07-07 14:20:21 -04:00
case chartname :
{
ScreenTextEntry :: TextEntry ( SM_None ,
ENTER_NEW_CHART_NAME ,
m_pSteps -> GetChartName (),
MAX_STEPS_DESCRIPTION_LENGTH ,
SongUtil :: ValidateCurrentStepsChartName ,
ChangeChartName ,
NULL );
break ;
}
case description :
{
ScreenTextEntry :: TextEntry ( SM_None ,
ENTER_NEW_DESCRIPTION ,
m_pSteps -> GetDescription (),
MAX_STEPS_DESCRIPTION_LENGTH ,
SongUtil :: ValidateCurrentStepsDescription ,
2011-07-07 21:06:05 -04:00
ChangeDescription ,
NULL );
break ;
}
case chartstyle :
{
ScreenTextEntry :: TextEntry ( SM_None ,
ENTER_NEW_CHART_STYLE ,
m_pSteps -> GetChartStyle (),
255 ,
NULL ,
ChangeChartStyle ,
NULL );
break ;
}
case step_credit :
{
ScreenTextEntry :: TextEntry ( SM_None ,
ENTER_NEW_STEP_AUTHOR ,
m_pSteps -> GetCredit (),
255 ,
SongUtil :: ValidateCurrentStepsCredit ,
ChangeStepCredit ,
NULL );
break ;
}
case meter :
{
ScreenTextEntry :: TextEntry ( SM_BackFromDifficultyMeterChange ,
ENTER_NEW_METER ,
ssprintf ( "%d" , m_pSteps -> GetMeter ()),
4 );
2011-07-07 14:20:21 -04:00
break ;
}
2011-07-07 18:10:59 -04:00
case step_min_bpm :
2011-07-07 21:06:05 -04:00
{
2011-07-07 18:10:59 -04:00
ScreenTextEntry :: TextEntry ( SM_None , ENTER_MIN_BPM ,
ssprintf ( "%.6f" , pSteps -> GetMinBPM ()), 20 ,
ScreenTextEntry :: FloatValidate ,
2011-07-07 21:06:05 -04:00
ChangeStepsMinBPM , NULL );
2011-07-07 18:10:59 -04:00
break ;
2011-07-07 21:06:05 -04:00
}
2011-07-07 18:10:59 -04:00
case step_max_bpm :
2011-07-07 21:06:05 -04:00
{
2011-07-07 18:10:59 -04:00
ScreenTextEntry :: TextEntry ( SM_None , ENTER_MAX_BPM ,
ssprintf ( "%.6f" , pSteps -> GetMaxBPM ()), 20 ,
ScreenTextEntry :: FloatValidate ,
2011-07-07 21:06:05 -04:00
ChangeStepsMaxBPM , NULL );
2011-07-07 18:10:59 -04:00
break ;
2011-07-07 21:06:05 -04:00
}
2011-05-07 19:18:03 -04:00
default :
break ;
2011-03-17 01:43:45 -04:00
}
2011-07-07 21:06:05 -04:00
SetDirty ( true );
2011-03-17 01:43:45 -04: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." );
static LocalizedString ENTER_GENRE ( "ScreenEdit" , "Enter a new genre." );
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." );
2011-06-30 01:11:38 -04:00
static LocalizedString ENTER_LAST_SECOND_HINT ( "ScreenEdit" , "Enter a new last second hint." );
2011-05-03 09:18:31 -04:00
static LocalizedString ENTER_PREVIEW_START ( "ScreenEdit" , "Enter a new preview start." );
static LocalizedString ENTER_PREVIEW_LENGTH ( "ScreenEdit" , "Enter a new preview length." );
2011-03-17 01:43:45 -04:00
void ScreenEdit :: HandleSongInformationChoice ( SongInformationChoice c , const vector < int > & iAnswers )
{
Song * pSong = GAMESTATE -> m_pCurSong ;
2011-04-05 22:40:33 -04:00
pSong -> m_DisplayBPMType = static_cast < DisplayBPM > ( iAnswers [ display_bpm ]);
2011-03-17 01:43:45 -04:00
switch ( 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 ;
case genre :
ScreenTextEntry :: TextEntry ( SM_None , ENTER_GENRE , pSong -> m_sGenre , 100 , NULL , ChangeGenre , NULL );
break ;
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 ;
2011-06-30 01:11:38 -04:00
case last_second_hint :
ScreenTextEntry :: TextEntry ( SM_None , ENTER_LAST_SECOND_HINT ,
2011-06-30 02:19:37 -04:00
ssprintf ( "%.6f" , pSong -> GetSpecifiedLastSecond ()), 20 ,
2011-06-30 01:11:38 -04:00
ScreenTextEntry :: FloatValidate , ChangeLastSecondHint , NULL );
2011-04-05 22:40:33 -04:00
break ;
2011-05-03 09:18:31 -04:00
case preview_start :
ScreenTextEntry :: TextEntry ( SM_None , ENTER_PREVIEW_START ,
2011-06-30 01:11:38 -04:00
ssprintf ( "%.6f" , pSong -> m_fMusicSampleStartSeconds ), 20 ,
2011-05-03 09:18:31 -04:00
ScreenTextEntry :: FloatValidate , ChangePreviewStart , NULL );
break ;
case preview_length :
ScreenTextEntry :: TextEntry ( SM_None , ENTER_PREVIEW_LENGTH ,
2011-06-30 01:11:38 -04:00
ssprintf ( "%.6f" , pSong -> m_fMusicSampleLengthSeconds ), 20 ,
2011-05-03 09:18:31 -04:00
ScreenTextEntry :: FloatValidate , ChangePreviewLength , NULL );
break ;
2011-04-05 22:40:33 -04:00
case min_bpm :
ScreenTextEntry :: TextEntry ( SM_None , ENTER_MIN_BPM ,
2011-06-30 01:11:38 -04:00
ssprintf ( "%.6f" , pSong -> m_fSpecifiedBPMMin ), 20 ,
2011-04-05 22:40:33 -04:00
ScreenTextEntry :: FloatValidate , ChangeMinBPM , NULL );
break ;
case max_bpm :
ScreenTextEntry :: TextEntry ( SM_None , ENTER_MAX_BPM ,
2011-06-30 01:11:38 -04:00
ssprintf ( "%.6f" , pSong -> m_fSpecifiedBPMMax ), 20 ,
2011-04-05 22:40:33 -04:00
ScreenTextEntry :: FloatValidate , ChangeMaxBPM , NULL );
break ;
2011-06-06 18:27:52 -04:00
default : break ;
2011-03-17 01:43:45 -04:00
};
2011-07-07 21:06:05 -04:00
SetDirty ( true );
2011-03-17 01:43:45 -04:00
}
2011-05-12 21:23:48 -04:00
2011-05-12 21:41:20 -04:00
static LocalizedString ENTER_BEAT_0_OFFSET ( "ScreenEdit" , "Enter the offset for the song." );
2011-03-17 01:43:45 -04: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." );
2011-05-16 23:05:51 +07:00
static LocalizedString ENTER_TIME_SIGNATURE_VALUE ( "ScreenEdit" , "Enter a new Time Signature." );
2011-03-17 01:43:45 -04:00
static LocalizedString ENTER_TICKCOUNT_VALUE ( "ScreenEdit" , "Enter a new Tickcount value." );
static LocalizedString ENTER_COMBO_VALUE ( "ScreenEdit" , "Enter a new Combo value." );
2011-04-05 00:35:45 -04:00
static LocalizedString ENTER_LABEL_VALUE ( "ScreenEdit" , "Enter a new Label value." );
2011-03-25 17:40:56 -04:00
static LocalizedString ENTER_WARP_VALUE ( "ScreenEdit" , "Enter a new Warp value." );
2011-05-15 15:53:20 -04:00
static LocalizedString ENTER_SPEED_PERCENT_VALUE ( "ScreenEdit" , "Enter a new Speed percent value." );
static LocalizedString ENTER_SPEED_WAIT_VALUE ( "ScreenEdit" , "Enter a new Speed wait value." );
2011-05-15 23:48:03 -04:00
static LocalizedString ENTER_SPEED_MODE_VALUE ( "ScreenEdit" , "Enter a new Speed mode value." );
2011-05-25 22:44:41 +07:00
static LocalizedString ENTER_SCROLL_VALUE ( "ScreenEdit" , "Enter a new Scroll value." );
2011-05-16 11:30:39 -04:00
static LocalizedString ENTER_FAKE_VALUE ( "ScreenEdit" , "Enter a new Fake value." );
2011-05-14 00:43:06 -05:00
static LocalizedString CONFIRM_TIMING_ERASE ( "ScreenEdit" , "Are you sure you want to erase this chart's timing data?" );
2011-03-17 01:43:45 -04:00
void ScreenEdit :: HandleTimingDataInformationChoice ( TimingDataInformationChoice c , const vector < int > & iAnswers )
{
switch ( c )
{
DEFAULT_FAIL ( c );
2011-05-12 21:23:48 -04:00
case beat_0_offset :
ScreenTextEntry :: TextEntry ( SM_None , ENTER_BEAT_0_OFFSET ,
2011-06-30 01:11:38 -04:00
ssprintf ( "%.6f" , GetAppropriateTiming (). m_fBeat0OffsetInSeconds ), 20 ,
2011-05-12 21:23:48 -04:00
ScreenTextEntry :: FloatValidate , ChangeBeat0Offset , NULL );
break ;
case bpm :
2011-03-17 01:43:45 -04:00
ScreenTextEntry :: TextEntry (
SM_BackFromBPMChange ,
ENTER_BPM_VALUE ,
2011-05-13 09:53:06 -04:00
ssprintf ( "%.4f" , GetAppropriateTiming (). GetBPMAtBeat ( GetBeat () ) ),
2011-03-17 01:43:45 -04:00
10
);
break ;
case stop :
ScreenTextEntry :: TextEntry (
SM_BackFromStopChange ,
ENTER_STOP_VALUE ,
2011-05-13 09:53:06 -04:00
ssprintf ( "%.4f" , GetAppropriateTiming (). GetStopAtBeat ( GetBeat () ) ),
2011-03-17 01:43:45 -04:00
10
);
break ;
case delay :
ScreenTextEntry :: TextEntry (
SM_BackFromDelayChange ,
ENTER_DELAY_VALUE ,
2011-05-13 09:53:06 -04:00
ssprintf ( "%.4f" , GetAppropriateTiming (). GetDelayAtBeat ( GetBeat () ) ),
2011-03-17 01:43:45 -04:00
10
);
break ;
2011-05-16 23:05:51 +07:00
case time_signature :
2011-05-31 14:27:55 -04:00
{
2011-09-10 03:08:59 +00:00
const TimeSignatureSegment * ts = GetAppropriateTiming (). GetTimeSignatureSegmentAtBeat ( GetBeat () );
2011-03-17 01:43:45 -04:00
ScreenTextEntry :: TextEntry (
2011-05-16 23:05:51 +07:00
SM_BackFromTimeSignatureChange ,
ENTER_TIME_SIGNATURE_VALUE ,
2011-07-14 23:15:48 -04:00
ssprintf ( "%d/%d" , ts -> GetNum (), ts -> GetDen () ),
2011-05-16 23:05:51 +07:00
8
2011-03-17 01:43:45 -04:00
);
break ;
2011-05-31 14:27:55 -04:00
}
2011-03-17 01:43:45 -04:00
case tickcount :
ScreenTextEntry :: TextEntry (
SM_BackFromTickcountChange ,
ENTER_TICKCOUNT_VALUE ,
2011-05-13 09:53:06 -04:00
ssprintf ( "%d" , GetAppropriateTiming (). GetTickcountAtBeat ( GetBeat () ) ),
2011-03-17 01:43:45 -04:00
2
);
break ;
case combo :
2011-07-09 02:28:15 -04:00
{
2011-09-10 03:08:59 +00:00
const ComboSegment * cs = GetAppropriateTiming (). GetComboSegmentAtBeat ( GetBeat ());
2011-07-09 02:28:15 -04:00
ScreenTextEntry :: TextEntry ( SM_BackFromComboChange ,
ENTER_COMBO_VALUE ,
ssprintf ( "%d/%d" ,
2011-07-14 23:15:48 -04:00
cs -> GetCombo (),
cs -> GetMissCombo ()),
2011-07-09 02:28:15 -04:00
7 );
break ;
}
2011-04-05 00:35:45 -04:00
case label :
ScreenTextEntry :: TextEntry (
SM_BackFromLabelChange ,
ENTER_LABEL_VALUE ,
2011-05-13 09:53:06 -04:00
ssprintf ( "%s" , GetAppropriateTiming (). GetLabelAtBeat ( GetBeat () ). c_str () ),
2011-04-05 00:35:45 -04:00
64
);
break ;
2011-03-25 17:40:56 -04:00
case warp :
ScreenTextEntry :: TextEntry (
SM_BackFromWarpChange ,
ENTER_WARP_VALUE ,
2011-06-30 01:11:38 -04:00
ssprintf ( "%.6f" , GetAppropriateTiming (). GetWarpAtBeat ( GetBeat () ) ),
2011-03-25 17:40:56 -04:00
10
);
2011-05-14 13:33:12 -04:00
break ;
2011-05-15 15:53:20 -04:00
case speed_percent :
ScreenTextEntry :: TextEntry (
SM_BackFromSpeedPercentChange ,
ENTER_SPEED_PERCENT_VALUE ,
2011-07-14 23:15:48 -04:00
ssprintf ( "%.6f" , GetAppropriateTiming (). GetSpeedSegmentAtBeat ( GetBeat () ) -> GetRatio () ),
2011-05-15 15:53:20 -04:00
10
);
break ;
2011-05-25 22:44:41 +07:00
case scroll :
ScreenTextEntry :: TextEntry (
SM_BackFromScrollChange ,
ENTER_SCROLL_VALUE ,
2011-07-14 23:15:48 -04:00
ssprintf ( "%.6f" , GetAppropriateTiming (). GetScrollSegmentAtBeat ( GetBeat () ) -> GetRatio () ),
2011-05-25 22:44:41 +07:00
10
);
break ;
2011-05-15 15:53:20 -04:00
case speed_wait :
ScreenTextEntry :: TextEntry (
SM_BackFromSpeedWaitChange ,
ENTER_SPEED_WAIT_VALUE ,
2011-09-11 17:13:10 +00:00
ssprintf ( "%.6f" , GetAppropriateTiming (). GetSpeedSegmentAtBeat ( GetBeat () ) -> GetDelay () ),
2011-05-15 15:53:20 -04:00
10
);
break ;
2011-05-15 23:48:03 -04:00
case speed_mode :
{
ScreenTextEntry :: TextEntry (
SM_BackFromSpeedModeChange ,
ENTER_SPEED_MODE_VALUE ,
2011-05-16 09:41:07 -04:00
"" ,
3
2011-05-15 23:48:03 -04:00
);
break ;
}
2011-05-16 11:30:39 -04:00
case fake :
{
ScreenTextEntry :: TextEntry (
SM_BackFromFakeChange ,
ENTER_FAKE_VALUE ,
2011-06-30 01:11:38 -04:00
ssprintf ( "%.6f" , GetAppropriateTiming (). GetFakeAtBeat ( GetBeat () ) ),
2011-05-16 11:30:39 -04:00
10
);
2011-05-16 12:48:36 -04:00
break ;
2011-05-16 11:30:39 -04:00
}
2011-07-26 13:55:06 -04:00
case copy_full_timing :
2011-06-28 12:25:32 -04:00
{
2011-07-26 12:21:31 -04:00
clipboardFullTiming = GetAppropriateTiming ();
2011-06-28 12:25:32 -04:00
break ;
}
2011-07-26 13:55:06 -04:00
case paste_full_timing :
2011-06-28 12:25:32 -04:00
{
if ( GAMESTATE -> m_bIsUsingStepTiming )
{
2011-07-26 12:21:31 -04:00
GAMESTATE -> m_pCurSteps [ PLAYER_1 ] -> m_Timing = clipboardFullTiming ;
2011-06-28 12:25:32 -04:00
}
else
{
2011-07-26 12:21:31 -04:00
GAMESTATE -> m_pCurSong -> m_SongTiming = clipboardFullTiming ;
2011-06-28 12:25:32 -04:00
}
SetDirty ( true );
break ;
}
2011-05-14 00:43:06 -05:00
case erase_step_timing :
ScreenPrompt :: Prompt ( SM_DoEraseStepTiming , CONFIRM_TIMING_ERASE , PROMPT_YES_NO , ANSWER_NO );
2011-03-25 17:40:56 -04:00
break ;
2011-05-15 23:48:03 -04:00
2011-03-17 01:43:45 -04:00
}
}
void ScreenEdit :: HandleBGChangeChoice ( BGChangeChoice c , const vector < int > & iAnswers )
{
BackgroundChange newChange ;
FOREACH ( BackgroundChange , m_pSong -> GetBackgroundChanges ( g_CurrentBGChangeLayer ), iter )
{
2011-05-10 21:21:23 +07:00
if ( iter -> m_fStartBeat == GAMESTATE -> m_Position . m_fSongBeat )
2011-03-17 01:43:45 -04:00
{
newChange = * iter ;
// delete the old change. We'll add a new one below.
m_pSong -> GetBackgroundChanges ( g_CurrentBGChangeLayer ). erase ( iter );
break ;
}
}
2011-05-10 21:21:23 +07:00
newChange . m_fStartBeat = GAMESTATE -> m_Position . m_fSongBeat ;
2011-03-17 01:43:45 -04:00
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 );
}
2011-06-26 23:58:24 -04:00
else
2011-06-24 17:29:34 -04:00
{
2011-06-26 23:58:24 -04:00
const PlayerOptions & p = GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_PlayerOptions . GetCurrent ();
2011-06-27 15:04:03 -04:00
if ( GAMESTATE -> m_pCurSong && p . m_fNoAttack == 0 && p . m_fRandAttack == 0 )
2011-06-24 17:29:34 -04:00
{
2011-06-26 23:58:24 -04:00
AttackArray & attacks = GAMESTATE -> m_bIsUsingStepTiming ?
GAMESTATE -> m_pCurSteps [ PLAYER_1 ] -> m_Attacks :
GAMESTATE -> m_pCurSong -> m_Attacks ;
if ( attacks . size () > 0 )
2011-06-24 17:29:34 -04:00
{
2011-06-26 23:58:24 -04:00
FOREACH ( Attack , attacks , attack )
{
float fBeat = GetAppropriateTiming (). GetBeatFromElapsedTime ( attack -> fStartSecond );
if ( fBeat >= GetBeat ())
GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> LaunchAttack ( * attack );
}
2011-06-24 17:29:34 -04:00
}
}
}
2011-03-17 01:43:45 -04:00
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.
2011-05-09 22:47:47 +07:00
pNewSteps = GAMESTATE -> m_pCurSong -> CreateSteps ();
2011-03-17 01:43:45 -04:00
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 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-09-10 03:08:59 +00:00
2011-09-15 03:28:58 +00:00
const float fBeat = GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_Position . m_fSongBeat ;
const TimeSignatureSegment * curTime = GAMESTATE -> m_pCurSong -> m_SongTiming . GetTimeSignatureSegmentAtBeat ( fBeat );
2011-07-14 23:15:48 -04:00
int rowsPerMeasure = curTime -> GetDen () * curTime -> GetNum ();
2011-03-17 01:43:45 -04:00
for ( int row = 0 ; row <= m_NoteDataEdit . GetLastRow (); row += rowsPerMeasure )
{
int iNumNotesThisMeasure = 0 ;
FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE ( m_NoteDataEdit , r , row , row + rowsPerMeasure )
iNumNotesThisMeasure += m_NoteDataEdit . GetNumTapNonEmptyTracks ( r );
}
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 :
{
2011-06-30 01:11:38 -04:00
Song & s = * GAMESTATE -> m_pCurSong ;
2011-06-30 02:10:58 -04:00
float fEndBeat = s . GetLastBeat ();
2011-03-17 01:43:45 -04:00
/* 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-06-30 02:10:58 -04:00
TimingData & timing = s . m_SongTiming ;
2011-06-01 14:01:35 -04:00
float playerBeat = GetAppropriatePosition (). m_fSongBeat ;
2011-07-14 23:15:48 -04:00
int beatsPerMeasure = timing . GetTimeSignatureSegmentAtBeat ( playerBeat ) -> GetNum ();
2011-03-17 01:43:45 -04:00
fEndBeat += beatsPerMeasure ;
fEndBeat = ftruncf ( fEndBeat , ( float ) beatsPerMeasure );
return fEndBeat ;
}
case EditMode_Full :
return NoteRowToBeat ( MAX_NOTE_ROW );
}
}
float ScreenEdit :: GetMaximumBeatForMoving () const
{
float fEndBeat = GetMaximumBeatForNewNote ();
2011-06-30 01:11:38 -04:00
/* Jump to GetLastBeat even if it's past the song's last beat
2011-03-17 01:43:45 -04:00
* 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
}
};
2011-05-12 23:18:57 -04:00
// TODO: Identify which of these can be removed and sent to a readme.
2011-03-17 01:43:45 -04:00
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 ),
2011-11-26 13:56:27 -05:00
EditHelpLine ( "Decrease/increase delay at cur beat" , EDIT_BUTTON_DELAY_DOWN , EDIT_BUTTON_DELAY_UP ),
2011-03-17 01:43:45 -04: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 ),
EditHelpLine ( "Cycle between tap notes" , EDIT_BUTTON_CYCLE_TAP_LEFT , EDIT_BUTTON_CYCLE_TAP_RIGHT ),
EditHelpLine ( "Add to/remove from right half" , EDIT_BUTTON_RIGHT_SIDE ),
2011-05-12 23:18:57 -04:00
EditHelpLine ( "Switch Timing" , EDIT_BUTTON_SWITCH_TIMINGS ),
2011-03-17 01:43:45 -04:00
EditHelpLine ( "Switch player (Routine only)" , EDIT_BUTTON_SWITCH_PLAYERS ),
};
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 );
2011-05-13 00:40:10 -04:00
// TODO: Better way of hiding routine only key on non-routine.
2011-07-13 16:07:33 -04:00
if ( hl . veb [ 0 ] == EDIT_BUTTON_SWITCH_PLAYERS && m_InputPlayerNumber == PLAYER_INVALID )
2011-05-13 00:40:10 -04:00
{
continue ;
}
2011-03-17 01:43:45 -04:00
g_EditHelp . rows . push_back ( MenuRowDef ( - 1 , sDescription , false , EditMode_Practice , false , false , 0 , sButtons ) );
}
EditMiniMenu ( & g_EditHelp );
}
// lua start
#include "LuaBinding.h"
/** @brief Allow Lua to have access to ScreenEdit. */
class LunaScreenEdit : public Luna < ScreenEdit >
{
public :
DEFINE_METHOD ( GetEditState , GetEditState () )
LunaScreenEdit ()
{
ADD_METHOD ( GetEditState );
}
};
LUA_REGISTER_DERIVED_CLASS ( ScreenEdit , ScreenWithMenuElements )
/*
* (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.
*/