2011-03-17 01:43:45 -04:00
#include "global.h"
#include "ScreenEdit.h"
#include "ActorUtil.h"
#include "AdjustSync.h"
2015-12-11 00:02:31 -07:00
#include "ArrowEffects.h"
2011-03-17 01:43:45 -04:00
#include "BackgroundUtil.h"
#include "CommonMetrics.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"
2015-03-11 18:55:06 -06:00
#include "RageSoundReader_FileReader.h"
2011-03-17 01:43:45 -04:00
#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"
2014-11-17 04:24:20 -07:00
#include "SpecialFiles.h"
2011-03-17 01:43:45 -04:00
#include "StepsUtil.h"
#include "Style.h"
#include "ThemeManager.h"
#include "ThemeMetric.h"
#include "TimingData.h"
#include "Game.h"
#include "RageSoundReader.h"
2023-04-19 14:22:59 +02:00
#include <cfloat>
#include <cmath>
2023-04-19 23:04:25 +02:00
#include <cstddef>
2023-04-19 14:22:59 +02:00
#include <utility>
2023-04-20 19:02:13 +02:00
#include <vector>
2023-04-19 14:22:59 +02:00
2011-03-17 01:43:45 -04:00
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? */
2024-09-08 23:13:50 -07:00
constexpr uint_fast64_t record_hold_default = 300000 ; // 0.3 seconds in microseconds
uint_fast64_t record_hold_seconds = record_hold_default ;
constexpr uint_fast64_t time_between_autosave = 300000000 ; // 300 seconds in microseconds
2011-03-17 01:43:45 -04:00
#define PLAYER_X (SCREEN_CENTER_X)
#define PLAYER_Y (SCREEN_CENTER_Y)
#define PLAYER_HEIGHT (360)
2017-05-14 02:49:55 +08:00
#define PLAYER_Y_STANDARD (PLAYER_Y-((SCREEN_HEIGHT/480)*(PLAYER_HEIGHT/2)))
2011-03-17 01:43:45 -04:00
#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")
2014-12-09 21:59:01 -07:00
#define SET_MOD_SCREEN THEME->GetMetric("ScreenEdit", "SetModScreen")
#define OPTIONS_SCREEN THEME->GetMetric("ScreenEdit", "OptionsScreen")
2011-03-17 01:43:45 -04:00
AutoScreenMessage ( SM_UpdateTextInfo );
AutoScreenMessage ( SM_BackFromMainMenu );
AutoScreenMessage ( SM_BackFromAreaMenu );
2011-06-10 03:04:47 -04:00
AutoScreenMessage ( SM_BackFromAlterMenu );
2014-08-30 13:38:16 -06:00
AutoScreenMessage ( SM_BackFromArbitraryRemap );
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 );
2012-05-21 21:42:06 -04:00
AutoScreenMessage ( SM_BackFromAttackAtTime );
2011-06-24 19:32:46 -04:00
AutoScreenMessage ( SM_BackFromInsertStepAttack );
2012-05-21 21:42:06 -04:00
AutoScreenMessage ( SM_BackFromAddingModToExistingAttack );
AutoScreenMessage ( SM_BackFromEditingModToExistingAttack );
AutoScreenMessage ( SM_BackFromEditingAttackStart );
AutoScreenMessage ( SM_BackFromEditingAttackLength );
AutoScreenMessage ( SM_BackFromAddingAttackToChart );
2011-06-24 19:32:46 -04:00
AutoScreenMessage ( SM_BackFromInsertStepAttackPlayerOptions );
2011-03-17 01:43:45 -04:00
AutoScreenMessage ( SM_BackFromInsertCourseAttack );
AutoScreenMessage ( SM_BackFromInsertCourseAttackPlayerOptions );
AutoScreenMessage ( SM_BackFromCourseModeMenu );
2012-02-10 14:44:48 -05:00
AutoScreenMessage ( SM_BackFromKeysoundTrack );
2012-02-10 19:49:53 -05:00
AutoScreenMessage ( SM_BackFromNewKeysound );
2011-03-17 01:43:45 -04:00
AutoScreenMessage ( SM_DoRevertToLastSave );
AutoScreenMessage ( SM_DoRevertFromDisk );
2015-03-08 00:56:29 -07:00
AutoScreenMessage ( SM_ConfirmClearArea );
2011-03-17 01:43:45 -04:00
AutoScreenMessage ( SM_BackFromTimingDataInformation );
2015-04-04 09:10:00 -06:00
AutoScreenMessage ( SM_BackFromTimingDataChangeInformation );
2011-05-07 19:18:03 -04:00
AutoScreenMessage ( SM_BackFromDifficultyMeterChange );
2013-01-21 23:13:38 -05:00
AutoScreenMessage ( SM_BackFromBeat0Change );
2011-03-17 01:43:45 -04:00
AutoScreenMessage ( SM_BackFromBPMChange );
AutoScreenMessage ( SM_BackFromStopChange );
AutoScreenMessage ( SM_BackFromDelayChange );
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 );
2015-03-02 18:44:01 -07:00
AutoScreenMessage ( SM_BackFromStepMusicChange );
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 );
2015-02-17 15:37:49 -07:00
AutoScreenMessage ( SM_AutoSaveSuccessful );
2011-03-17 01:43:45 -04:00
AutoScreenMessage ( SM_SaveSuccessful );
2015-10-02 16:26:59 -06:00
AutoScreenMessage ( SM_SaveSuccessNoSM );
2011-03-17 01:43:45 -04:00
AutoScreenMessage ( SM_SaveFailed );
static const char * EditStateNames [] = {
"Edit" ,
"Record" ,
"RecordPaused" ,
"Playing"
};
XToString ( EditState );
LuaXType ( EditState );
2022-07-10 18:28:56 +03:00
std :: map < RString , EditButton > name_to_edit_button ;
2014-11-17 04:24:20 -07:00
2011-03-17 01:43:45 -04:00
void ScreenEdit :: InitEditMappings ()
{
2014-11-17 04:24:20 -07:00
// Created courtesy of query replace regex.
name_to_edit_button [ "COLUMN_0" ] = EDIT_BUTTON_COLUMN_0 ;
name_to_edit_button [ "COLUMN_1" ] = EDIT_BUTTON_COLUMN_1 ;
name_to_edit_button [ "COLUMN_2" ] = EDIT_BUTTON_COLUMN_2 ;
name_to_edit_button [ "COLUMN_3" ] = EDIT_BUTTON_COLUMN_3 ;
name_to_edit_button [ "COLUMN_4" ] = EDIT_BUTTON_COLUMN_4 ;
name_to_edit_button [ "COLUMN_5" ] = EDIT_BUTTON_COLUMN_5 ;
name_to_edit_button [ "COLUMN_6" ] = EDIT_BUTTON_COLUMN_6 ;
name_to_edit_button [ "COLUMN_7" ] = EDIT_BUTTON_COLUMN_7 ;
name_to_edit_button [ "COLUMN_8" ] = EDIT_BUTTON_COLUMN_8 ;
name_to_edit_button [ "COLUMN_9" ] = EDIT_BUTTON_COLUMN_9 ;
name_to_edit_button [ "RIGHT_SIDE" ] = EDIT_BUTTON_RIGHT_SIDE ;
name_to_edit_button [ "LAY_ROLL" ] = EDIT_BUTTON_LAY_ROLL ;
name_to_edit_button [ "LAY_TAP_ATTACK" ] = EDIT_BUTTON_LAY_TAP_ATTACK ;
name_to_edit_button [ "REMOVE_NOTE" ] = EDIT_BUTTON_REMOVE_NOTE ;
name_to_edit_button [ "CYCLE_TAP_LEFT" ] = EDIT_BUTTON_CYCLE_TAP_LEFT ;
name_to_edit_button [ "CYCLE_TAP_RIGHT" ] = EDIT_BUTTON_CYCLE_TAP_RIGHT ;
name_to_edit_button [ "CYCLE_SEGMENT_LEFT" ] = EDIT_BUTTON_CYCLE_SEGMENT_LEFT ;
name_to_edit_button [ "CYCLE_SEGMENT_RIGHT" ] = EDIT_BUTTON_CYCLE_SEGMENT_RIGHT ;
name_to_edit_button [ "SCROLL_UP_LINE" ] = EDIT_BUTTON_SCROLL_UP_LINE ;
name_to_edit_button [ "SCROLL_UP_PAGE" ] = EDIT_BUTTON_SCROLL_UP_PAGE ;
name_to_edit_button [ "SCROLL_UP_TS" ] = EDIT_BUTTON_SCROLL_UP_TS ;
name_to_edit_button [ "SCROLL_DOWN_LINE" ] = EDIT_BUTTON_SCROLL_DOWN_LINE ;
name_to_edit_button [ "SCROLL_DOWN_PAGE" ] = EDIT_BUTTON_SCROLL_DOWN_PAGE ;
name_to_edit_button [ "SCROLL_DOWN_TS" ] = EDIT_BUTTON_SCROLL_DOWN_TS ;
name_to_edit_button [ "SCROLL_NEXT_MEASURE" ] = EDIT_BUTTON_SCROLL_NEXT_MEASURE ;
name_to_edit_button [ "SCROLL_PREV_MEASURE" ] = EDIT_BUTTON_SCROLL_PREV_MEASURE ;
name_to_edit_button [ "SCROLL_HOME" ] = EDIT_BUTTON_SCROLL_HOME ;
name_to_edit_button [ "SCROLL_END" ] = EDIT_BUTTON_SCROLL_END ;
name_to_edit_button [ "SCROLL_NEXT" ] = EDIT_BUTTON_SCROLL_NEXT ;
name_to_edit_button [ "SCROLL_PREV" ] = EDIT_BUTTON_SCROLL_PREV ;
name_to_edit_button [ "SEGMENT_NEXT" ] = EDIT_BUTTON_SEGMENT_NEXT ;
name_to_edit_button [ "SEGMENT_PREV" ] = EDIT_BUTTON_SEGMENT_PREV ;
name_to_edit_button [ "SCROLL_SELECT" ] = EDIT_BUTTON_SCROLL_SELECT ;
name_to_edit_button [ "LAY_SELECT" ] = EDIT_BUTTON_LAY_SELECT ;
name_to_edit_button [ "SCROLL_SPEED_UP" ] = EDIT_BUTTON_SCROLL_SPEED_UP ;
name_to_edit_button [ "SCROLL_SPEED_DOWN" ] = EDIT_BUTTON_SCROLL_SPEED_DOWN ;
name_to_edit_button [ "SNAP_NEXT" ] = EDIT_BUTTON_SNAP_NEXT ;
name_to_edit_button [ "SNAP_PREV" ] = EDIT_BUTTON_SNAP_PREV ;
name_to_edit_button [ "OPEN_EDIT_MENU" ] = EDIT_BUTTON_OPEN_EDIT_MENU ;
name_to_edit_button [ "OPEN_TIMING_MENU" ] = EDIT_BUTTON_OPEN_TIMING_MENU ;
name_to_edit_button [ "OPEN_ALTER_MENU" ] = EDIT_BUTTON_OPEN_ALTER_MENU ;
name_to_edit_button [ "OPEN_AREA_MENU" ] = EDIT_BUTTON_OPEN_AREA_MENU ;
name_to_edit_button [ "OPEN_BGCHANGE_LAYER1_MENU" ] = EDIT_BUTTON_OPEN_BGCHANGE_LAYER1_MENU ;
name_to_edit_button [ "OPEN_BGCHANGE_LAYER2_MENU" ] = EDIT_BUTTON_OPEN_BGCHANGE_LAYER2_MENU ;
name_to_edit_button [ "OPEN_COURSE_MENU" ] = EDIT_BUTTON_OPEN_COURSE_MENU ;
name_to_edit_button [ "OPEN_COURSE_ATTACK_MENU" ] = EDIT_BUTTON_OPEN_COURSE_ATTACK_MENU ;
name_to_edit_button [ "OPEN_STEP_ATTACK_MENU" ] = EDIT_BUTTON_OPEN_STEP_ATTACK_MENU ;
name_to_edit_button [ "ADD_STEP_MODS" ] = EDIT_BUTTON_ADD_STEP_MODS ;
name_to_edit_button [ "OPEN_INPUT_HELP" ] = EDIT_BUTTON_OPEN_INPUT_HELP ;
name_to_edit_button [ "BAKE_RANDOM_FROM_SONG_GROUP" ] = EDIT_BUTTON_BAKE_RANDOM_FROM_SONG_GROUP ;
name_to_edit_button [ "BAKE_RANDOM_FROM_SONG_GROUP_AND_GENRE" ] = EDIT_BUTTON_BAKE_RANDOM_FROM_SONG_GROUP_AND_GENRE ;
name_to_edit_button [ "PLAY_FROM_START" ] = EDIT_BUTTON_PLAY_FROM_START ;
name_to_edit_button [ "PLAY_FROM_CURSOR" ] = EDIT_BUTTON_PLAY_FROM_CURSOR ;
name_to_edit_button [ "PLAY_SELECTION" ] = EDIT_BUTTON_PLAY_SELECTION ;
name_to_edit_button [ "RECORD_FROM_CURSOR" ] = EDIT_BUTTON_RECORD_FROM_CURSOR ;
name_to_edit_button [ "RECORD_SELECTION" ] = EDIT_BUTTON_RECORD_SELECTION ;
2015-02-08 18:39:45 -07:00
name_to_edit_button [ "RECORD_HOLD_RESET" ] = EDIT_BUTTON_RECORD_HOLD_RESET ;
name_to_edit_button [ "RECORD_HOLD_OFF" ] = EDIT_BUTTON_RECORD_HOLD_OFF ;
name_to_edit_button [ "RECORD_HOLD_MORE" ] = EDIT_BUTTON_RECORD_HOLD_MORE ;
name_to_edit_button [ "RECORD_HOLD_LESS" ] = EDIT_BUTTON_RECORD_HOLD_LESS ;
2014-11-17 04:24:20 -07:00
name_to_edit_button [ "RETURN_TO_EDIT" ] = EDIT_BUTTON_RETURN_TO_EDIT ;
name_to_edit_button [ "INSERT" ] = EDIT_BUTTON_INSERT ;
name_to_edit_button [ "DELETE" ] = EDIT_BUTTON_DELETE ;
name_to_edit_button [ "INSERT_SHIFT_PAUSES" ] = EDIT_BUTTON_INSERT_SHIFT_PAUSES ;
name_to_edit_button [ "DELETE_SHIFT_PAUSES" ] = EDIT_BUTTON_DELETE_SHIFT_PAUSES ;
name_to_edit_button [ "OPEN_NEXT_STEPS" ] = EDIT_BUTTON_OPEN_NEXT_STEPS ;
name_to_edit_button [ "OPEN_PREV_STEPS" ] = EDIT_BUTTON_OPEN_PREV_STEPS ;
name_to_edit_button [ "PLAY_SAMPLE_MUSIC" ] = EDIT_BUTTON_PLAY_SAMPLE_MUSIC ;
name_to_edit_button [ "BPM_UP" ] = EDIT_BUTTON_BPM_UP ;
name_to_edit_button [ "BPM_DOWN" ] = EDIT_BUTTON_BPM_DOWN ;
name_to_edit_button [ "STOP_UP" ] = EDIT_BUTTON_STOP_UP ;
name_to_edit_button [ "STOP_DOWN" ] = EDIT_BUTTON_STOP_DOWN ;
name_to_edit_button [ "DELAY_UP" ] = EDIT_BUTTON_DELAY_UP ;
name_to_edit_button [ "DELAY_DOWN" ] = EDIT_BUTTON_DELAY_DOWN ;
name_to_edit_button [ "OFFSET_UP" ] = EDIT_BUTTON_OFFSET_UP ;
name_to_edit_button [ "OFFSET_DOWN" ] = EDIT_BUTTON_OFFSET_DOWN ;
name_to_edit_button [ "SAMPLE_START_UP" ] = EDIT_BUTTON_SAMPLE_START_UP ;
name_to_edit_button [ "SAMPLE_START_DOWN" ] = EDIT_BUTTON_SAMPLE_START_DOWN ;
name_to_edit_button [ "SAMPLE_LENGTH_UP" ] = EDIT_BUTTON_SAMPLE_LENGTH_UP ;
name_to_edit_button [ "SAMPLE_LENGTH_DOWN" ] = EDIT_BUTTON_SAMPLE_LENGTH_DOWN ;
name_to_edit_button [ "ADJUST_FINE" ] = EDIT_BUTTON_ADJUST_FINE ;
name_to_edit_button [ "SAVE" ] = EDIT_BUTTON_SAVE ;
name_to_edit_button [ "UNDO" ] = EDIT_BUTTON_UNDO ;
name_to_edit_button [ "ADD_COURSE_MODS" ] = EDIT_BUTTON_ADD_COURSE_MODS ;
name_to_edit_button [ "SWITCH_PLAYERS" ] = EDIT_BUTTON_SWITCH_PLAYERS ;
name_to_edit_button [ "SWITCH_TIMINGS" ] = EDIT_BUTTON_SWITCH_TIMINGS ;
2011-03-17 01:43:45 -04:00
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 );
2020-10-20 02:16:02 +09:00
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 );
2020-10-20 02:16:02 +09:00
2011-06-12 20:34:23 -04:00
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 );
2020-10-20 02:16:02 +09:00
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 );
2020-10-20 02:16:02 +09: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 );
2020-10-20 02:16:02 +09: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 ;
2020-10-20 02:16:02 +09: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 );
2012-03-20 20:45:35 -07:00
// v = course playback menu
// m_EditMappingsDeviceInput.button[EDIT_BUTTON_OPEN_COURSE_ATTACK_MENU][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cv);
2012-01-10 19:14:29 -08:00
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_ADD_COURSE_MODS ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Co );
2012-03-20 20:45:35 -07:00
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_OPEN_COURSE_MENU ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cv );
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 );
2020-10-20 02:16:02 +09:00
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 );
2020-10-20 02:16:02 +09: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 );
2020-10-20 02:16:02 +09:00
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 );
2012-05-21 21:42:06 -04:00
// m_EditMappingsDeviceInput.button[EDIT_BUTTON_ADD_STEP_MODS][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cc);
2012-03-20 20:45:35 -07:00
// 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 );
2015-02-08 18:39:45 -07:00
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_RECORD_HOLD_LESS ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cq );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_RECORD_HOLD_MORE ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cw );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_RECORD_HOLD_RESET ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Ce );
m_EditMappingsDeviceInput . button [ EDIT_BUTTON_RECORD_HOLD_OFF ][ 0 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_Cr );
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
}
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 );
2020-10-20 02:16:02 +09:00
2011-06-26 23:11:57 -04:00
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 );
2020-10-20 02:16:02 +09:00
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 );
2020-10-20 02:16:02 +09:00
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 );
2013-01-02 10:49:20 -06:00
m_RecordMappingsDeviceInput . button [ EDIT_BUTTON_RETURN_TO_EDIT ][ 1 ] = DeviceInput ( DEVICE_KEYBOARD , KEY_ENTER );
2013-01-02 10:38:11 -06:00
m_RecordMappingsMenuButton . button [ EDIT_BUTTON_RETURN_TO_EDIT ][ 0 ] = GAME_BUTTON_BACK ;
2013-01-02 14:09:17 -05:00
m_RecordMappingsMenuButton . button [ EDIT_BUTTON_RETURN_TO_EDIT ][ 1 ] = GAME_BUTTON_START ;
2011-03-17 01:43:45 -04:00
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 );
2014-11-17 04:24:20 -07:00
IniFile mapping_ini ;
// Only use the mappings file if it exists. It's meant to be optional, and
// only used in rare cases like someone having critical keys broken. -Kyz
if ( mapping_ini . ReadFile ( SpecialFiles :: EDIT_MODE_KEYMAPS_PATH ))
{
LoadKeymapSectionIntoMappingsMember ( mapping_ini . GetChild ( "Edit" ),
m_EditMappingsDeviceInput );
LoadKeymapSectionIntoMappingsMember ( mapping_ini . GetChild ( "Play" ),
m_PlayMappingsDeviceInput );
LoadKeymapSectionIntoMappingsMember ( mapping_ini . GetChild ( "Record" ),
m_RecordMappingsDeviceInput );
LoadKeymapSectionIntoMappingsMember ( mapping_ini . GetChild ( "RecordPaused" ),
m_RecordPausedMappingsDeviceInput );
}
2011-03-17 01:43:45 -04:00
}
2014-11-17 04:24:20 -07:00
void ScreenEdit :: LoadKeymapSectionIntoMappingsMember ( XNode const * section , MapEditToDI & mappings )
{
2019-06-22 12:35:38 -07:00
if ( section == nullptr ) { return ;} // Not an error, sections are optional. -Kyz
2014-11-17 04:24:20 -07:00
FOREACH_CONST_Attr ( section , attr )
{
2022-07-10 18:28:56 +03:00
std :: map < RString , EditButton >:: iterator name_entry =
2014-11-17 04:24:20 -07:00
name_to_edit_button . find ( attr -> first );
if ( name_entry != name_to_edit_button . end ())
{
RString joined_names ;
attr -> second -> GetValue ( joined_names );
2022-07-10 18:28:56 +03:00
std :: vector < RString > key_names ;
2014-11-17 04:24:20 -07:00
split ( joined_names , DEVICE_INPUT_SEPARATOR , key_names , false );
2024-10-01 00:43:07 -07:00
for ( size_t k = 0 ; k < key_names . size () && k < NUM_EDIT_TO_DEVICE_SLOTS ; ++ k )
2014-11-17 04:24:20 -07:00
{
DeviceInput devi ;
devi . FromString ( key_names [ k ]);
if ( devi . IsValid ())
{
mappings . button [ name_entry -> second ][ k ] = devi ;
}
}
}
}
}
2011-03-17 01:43:45 -04:00
/* 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 ;
}
}
}
}
2020-10-20 02:16:02 +09:00
/* No shifted keys matched. See if any unshifted inputs are bound to this key. */
2011-03-17 01:43:45 -04:00
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 ;
}
2020-10-20 02:16:02 +09:00
/* No shifted keys matched. */
2011-03-17 01:43:45 -04:00
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 ;
}
}
2015-04-04 22:38:18 -06:00
enum RowCountChoice
{
RCC_4M ,
RCC_2M ,
RCC_1M ,
RCC_2ND ,
RCC_4TH ,
RCC_8TH ,
RCC_12TH ,
RCC_16TH ,
RCC_24TH ,
RCC_32ND ,
RCC_48TH ,
RCC_64TH ,
RCC_192ND ,
};
#define RCC_CHOICES RCC_4TH, "4m", "2m", "1m", "2nd", "4th","8th","12th","16th","24th","32nd","48th","64th","192nd"
2022-07-10 18:28:56 +03:00
int GetRowsFromAnswers ( int choice , const std :: vector < int >& answers );
int GetRowsFromAnswers ( int choice , const std :: vector < int >& answers )
2015-04-04 22:38:18 -06:00
{
if ( answers . empty ())
{
return 192 / 8 ;
}
switch ( answers [ choice ])
{
case RCC_4M :
return 192 * 4 ;
case RCC_2M :
return 192 * 2 ;
case RCC_1M :
return 192 ;
case RCC_2ND :
return 192 / 2 ;
case RCC_4TH :
default :
return 192 / 4 ;
case RCC_8TH :
return 192 / 8 ;
case RCC_12TH :
return 192 / 12 ;
case RCC_16TH :
return 192 / 16 ;
case RCC_24TH :
return 192 / 24 ;
case RCC_32ND :
return 192 / 32 ;
case RCC_48TH :
return 192 / 48 ;
case RCC_64TH :
return 3 ;
case RCC_192ND :
return 1 ;
}
}
2011-03-17 01:43:45 -04:00
static MenuDef g_EditHelp (
"ScreenMiniMenuEditHelp"
// fill this in dynamically
);
2012-05-21 21:42:06 -04:00
static MenuDef g_AttackAtTimeMenu (
"ScreenMiniMenuAttackAtTimeMenu"
// fill this in dynamically
);
static MenuDef g_IndividualAttack (
"ScreenMiniMenuIndividualAttack"
// fill this in dynamically
);
2012-02-10 13:51:29 -05:00
static MenuDef g_KeysoundTrack (
"ScreenMiniMenuKeysoundTrack"
); // fill this in dynamically
2011-03-17 01:43:45 -04:00
static MenuDef g_MainMenu (
"ScreenMiniMenuMainMenu" ,
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: play_whole_song ,
"Play whole song" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: play_current_beat_to_end ,
"Play current beat to end" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: save ,
"Save" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Home , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: play_selection ,
"Play selection" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: set_selection_start ,
"Set selection start" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: set_selection_end ,
"Set selection end" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: revert_to_last_save ,
"Revert to last save" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Home , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: revert_from_disk ,
"Revert from disk" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: options ,
"Editor options" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: edit_song_info ,
"Edit song info" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2020-10-20 02:16:02 +09:00
MenuRowDef ( ScreenEdit :: edit_steps_information ,
2012-02-27 13:31:15 -05:00
"Edit steps information" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: edit_timing_data ,
"Edit Timing Data" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: view_steps_data ,
"View steps data" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: play_preview_music ,
"Play preview music" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: exit ,
"Exit Edit Mode" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr )
2011-03-17 01:43:45 -04:00
);
2011-06-10 03:04:47 -04:00
static MenuDef g_AlterMenu (
"ScreenMiniMenuAlterMenu" ,
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: cut ,
"Cut" ,
2020-10-20 02:16:02 +09:00
true ,
2019-06-22 12:35:38 -07:00
EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: copy ,
"Copy" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2020-10-20 02:16:02 +09:00
MenuRowDef ( ScreenEdit :: clear , "Clear area" , true ,
2019-06-22 12:35:38 -07:00
EditMode_Practice , true , true , 0 , nullptr ),
2020-10-20 02:16:02 +09:00
MenuRowDef ( ScreenEdit :: quantize , "Quantize" , true ,
EditMode_Practice , true , true , 0 ,
2011-06-10 03:04:47 -04:00
"4th" , "8th" , "12th" , "16th" , "24th" , "32nd" , "48th" , "64th" , "192nd" ),
2020-10-20 02:16:02 +09:00
MenuRowDef ( ScreenEdit :: turn , "Turn" , true ,
2024-03-06 13:30:32 -08:00
EditMode_Practice , true , true , 0 , "Left" , "Right" , "Mirror" , "LRMirror" , "UDMirror" , "Backwards" , "Shuffle" , "SuperShuffle" , "HyperShuffle" ),
2020-10-20 02:16:02 +09:00
MenuRowDef ( ScreenEdit :: transform , "Transform" , true ,
2011-06-10 03:04:47 -04:00
EditMode_Practice , true , true , 0 , "NoHolds" , "NoMines" , "Little" , "Wide" ,
"Big" , "Quick" , "Skippy" , "Mines" , "Echo" , "Stomp" , "Planted" , "Floored" ,
"Twister" , "NoJumps" , "NoHands" , "NoQuads" , "NoStretch" ),
2020-10-20 02:16:02 +09:00
MenuRowDef ( ScreenEdit :: alter , "Alter" , true ,
2011-06-10 03:04:47 -04:00
EditMode_Practice , true , true , 0 , "Autogen To Fill Width" , "Backwards" , "Swap Sides" ,
"Copy Left To Right" , "Copy Right To Left" , "Clear Left" , "Clear Right" ,
2014-08-30 13:38:16 -06:00
"Collapse To One" , "Collapse Left" , "Shift Left" , "Shift Right" , "Swap Up/Down" , "Arbitrary Remap Columns" ),
2020-10-20 02:16:02 +09:00
MenuRowDef ( ScreenEdit :: tempo , "Tempo" , true ,
2011-06-10 03:04:47 -04:00
EditMode_Full , true , true , 0 , "Compress 2x" , "Compress 3->2" ,
"Compress 4->3" , "Expand 3->4" , "Expand 2->3" , "Expand 2x" ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: play ,
"Play selection" ,
true ,
2019-06-22 12:35:38 -07:00
EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: record ,
"Record in selection" ,
2020-10-20 02:16:02 +09:00
true ,
2019-06-22 12:35:38 -07:00
EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: preview_designation ,
"Designate as Music Preview" ,
true ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: convert_to_pause ,
"Convert selection to pause" ,
2020-10-20 02:16:02 +09:00
true ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: convert_to_delay ,
2020-10-20 02:16:02 +09:00
"Convert selection to delay" ,
true ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , true , 0 , nullptr ),
2020-10-20 02:16:02 +09:00
MenuRowDef ( ScreenEdit :: convert_to_warp ,
2012-02-27 13:31:15 -05:00
"Convert selection to warp" ,
2020-10-20 02:16:02 +09:00
true ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: convert_to_fake ,
"Convert selection to fake" ,
2020-10-20 02:16:02 +09:00
true ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: convert_to_attack ,
"Convert selection to attack" ,
true ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: routine_invert_notes ,
"Invert notes' player" ,
true ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: routine_mirror_1_to_2 ,
"Mirror Player 1 to 2" ,
true ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: routine_mirror_2_to_1 ,
2020-10-20 02:16:02 +09:00
"Mirror Player 2 to 1" ,
2012-02-27 13:31:15 -05:00
true ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , true , 0 , nullptr )
2011-06-10 03:04:47 -04:00
);
2011-03-17 01:43:45 -04:00
static MenuDef g_AreaMenu (
"ScreenMiniMenuAreaMenu" ,
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: paste_at_current_beat ,
"Paste at current beat" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: paste_at_begin_marker ,
"Paste at begin marker" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: insert_and_shift ,
"Insert beat and shift down" ,
2015-04-04 22:38:18 -06:00
true , EditMode_Practice , true , true , RCC_CHOICES ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: delete_and_shift ,
2020-10-20 02:16:02 +09:00
"Delete beat and shift up" ,
2015-04-04 22:38:18 -06:00
true , EditMode_Practice , true , true , RCC_CHOICES ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: shift_pauses_forward ,
"Shift all timing changes down" ,
2015-04-04 22:38:18 -06:00
true , EditMode_Full , true , true , RCC_CHOICES ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: shift_pauses_backward ,
"Shift all timing changes up" ,
2015-04-04 22:38:18 -06:00
true , EditMode_Full , true , true , RCC_CHOICES ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: convert_pause_to_beat ,
"Convert pause to beats" ,
2020-10-20 02:16:02 +09:00
true ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: convert_delay_to_beat ,
"Convert delay to beats" ,
true ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: last_second_at_beat ,
"Designate last second at current beat" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: undo ,
"Undo" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: clear_clipboard ,
"Clear clipboard" ,
true ,
2019-06-22 12:35:38 -07:00
EditMode_Practice , true , true , 0 , nullptr ),
2012-05-21 21:42:06 -04:00
MenuRowDef ( ScreenEdit :: modify_attacks_at_row ,
"Modify Attacks at current beat" ,
2019-06-22 12:35:38 -07:00
true , EditMode_CourseMods , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: modify_keysounds_at_row ,
"Modify Keysounds at current beat" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr )
2020-10-20 02:16:02 +09:00
2011-03-17 01:43:45 -04:00
);
static MenuDef g_StepsInformation (
"ScreenMiniMenuStepsInformation" ,
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: difficulty ,
"Difficulty" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: meter ,
"Meter" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , false , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: predict_meter ,
"Predicted Meter" ,
2019-06-22 12:35:38 -07:00
false , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: chartname ,
"Chart Name" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: description ,
"Description" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: chartstyle ,
"Chart Style" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2020-10-20 02:16:02 +09:00
MenuRowDef ( ScreenEdit :: step_credit ,
2012-02-27 13:31:15 -05:00
"Step Author" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: step_display_bpm ,
"Display BPM" ,
true , EditMode_Full , true , true , 0 , "Actual" , "Specified" , "Random" ),
MenuRowDef ( ScreenEdit :: step_min_bpm ,
"Min BPM" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: step_max_bpm ,
"Max BPM" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2015-03-02 18:44:01 -07:00
MenuRowDef ( ScreenEdit :: step_music ,
2019-06-22 12:35:38 -07:00
"Music File" , true , EditMode_Full , true , true , 0 , nullptr )
2011-07-07 17:52:30 -04:00
);
static MenuDef g_StepsData (
"ScreenMiniMenuStepsData" ,
2019-06-22 12:35:38 -07:00
MenuRowDef ( ScreenEdit :: tap_notes , "Tap Steps" , false , EditMode_Full , true , true , 0 , nullptr ),
MenuRowDef ( ScreenEdit :: jumps , "Jumps" , false , EditMode_Full , true , true , 0 , nullptr ),
MenuRowDef ( ScreenEdit :: hands , "Hands" , false , EditMode_Full , true , true , 0 , nullptr ),
MenuRowDef ( ScreenEdit :: quads , "Quads" , false , EditMode_Full , true , true , 0 , nullptr ),
MenuRowDef ( ScreenEdit :: holds , "Holds" , false , EditMode_Full , true , true , 0 , nullptr ),
MenuRowDef ( ScreenEdit :: mines , "Mines" , false , EditMode_Full , true , true , 0 , nullptr ),
MenuRowDef ( ScreenEdit :: rolls , "Rolls" , false , EditMode_Full , true , true , 0 , nullptr ),
MenuRowDef ( ScreenEdit :: lifts , "Lifts" , false , EditMode_Full , true , true , 0 , nullptr ),
MenuRowDef ( ScreenEdit :: fakes , "Fakes" , false , EditMode_Full , true , true , 0 , nullptr ),
MenuRowDef ( ScreenEdit :: stream , "Stream" , false , EditMode_Full , true , true , 0 , nullptr ),
MenuRowDef ( ScreenEdit :: voltage , "Voltage" , false , EditMode_Full , true , true , 0 , nullptr ),
MenuRowDef ( ScreenEdit :: air , "Air" , false , EditMode_Full , true , true , 0 , nullptr ),
MenuRowDef ( ScreenEdit :: freeze , "Freeze" , false , EditMode_Full , true , true , 0 , nullptr ),
MenuRowDef ( ScreenEdit :: chaos , "Chaos" , false , EditMode_Full , true , true , 0 , nullptr )
2011-03-17 01:43:45 -04:00
);
static MenuDef g_SongInformation (
"ScreenMiniMenuSongInformation" ,
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: main_title ,
"Main title" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: sub_title ,
"Sub title" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: artist ,
"Artist" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: genre ,
"Genre" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: credit ,
"Credit" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2015-03-04 01:31:02 -07:00
MenuRowDef ( ScreenEdit :: preview ,
"Preview" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2020-10-20 02:16:02 +09:00
MenuRowDef ( ScreenEdit :: main_title_transliteration ,
2012-02-27 13:31:15 -05:00
"Main title transliteration" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: sub_title_transliteration ,
"Sub title transliteration" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: artist_transliteration ,
"Artist transliteration" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Practice , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: last_second_hint ,
"Last second hint" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: preview_start ,
"Preview Start" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: preview_length ,
"Preview Length" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: display_bpm ,
"Display BPM" ,
true , EditMode_Full , true , true , 0 , "Actual" , "Specified" , "Random" ),
MenuRowDef ( ScreenEdit :: min_bpm ,
"Min BPM" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:42:15 -05:00
MenuRowDef ( ScreenEdit :: max_bpm ,
2012-02-27 13:31:15 -05:00
"Max BPM" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr )
2011-03-17 01:43:45 -04:00
);
2016-01-18 11:48:50 -07:00
// Ugh, I don't like making this global pointer to clipboardFullTiming, but
// it's the only way to make it visible to EnabledIfClipboardTimingIsSafe for
// making sure it's safe to paste as the timing data for the Steps/Song. -Kyz
2019-06-22 12:35:38 -07:00
static TimingData * clipboard_full_timing = nullptr ;
2016-01-18 11:48:50 -07:00
static bool EnabledIfClipboardTimingIsSafe ();
static bool EnabledIfClipboardTimingIsSafe ()
{
2019-06-22 12:35:38 -07:00
return clipboard_full_timing != nullptr && clipboard_full_timing -> IsSafeFullTiming ();
2016-01-18 11:48:50 -07:00
}
2011-05-13 00:05:31 -04:00
static MenuDef g_TimingDataInformation (
2011-05-13 16:04:17 -04:00
"ScreenMiniMenuTimingDataInformation" ,
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: beat_0_offset ,
"Beat 0 Offset" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: bpm ,
"Edit BPM change" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: stop ,
"Edit stop" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: delay ,
"Edit delay" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: label ,
"Edit label" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: tickcount ,
"Edit tickcount" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: combo ,
"Edit combo" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: warp ,
"Edit warp" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: speed_percent ,
"Edit speed (percent)" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: speed_wait ,
"Edit speed (wait)" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: speed_mode ,
"Edit speed (mode)" ,
true , EditMode_Full , true , true , 0 , "Beats" , "Seconds" ),
MenuRowDef ( ScreenEdit :: scroll ,
"Edit scrolling factor" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: fake ,
"Edit fake" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2015-04-04 09:10:00 -06:00
MenuRowDef ( ScreenEdit :: shift_timing_in_region_down ,
"Shift timing in region down" ,
2015-04-04 22:38:18 -06:00
true , EditMode_Full , true , true , RCC_CHOICES ),
2015-04-04 09:10:00 -06:00
MenuRowDef ( ScreenEdit :: shift_timing_in_region_up ,
"Shift timing in region up" ,
2015-04-04 22:38:18 -06:00
true , EditMode_Full , true , true , RCC_CHOICES ),
2015-04-04 09:10:00 -06:00
MenuRowDef ( ScreenEdit :: copy_timing_in_region ,
"Copy timing in region" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2016-01-18 11:48:50 -07:00
MenuRowDef ( ScreenEdit :: clear_timing_in_region ,
"Clear timing in region" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2015-04-04 09:10:00 -06:00
MenuRowDef ( ScreenEdit :: paste_timing_from_clip ,
"Paste timing from clipboard" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: copy_full_timing ,
"Copy timing data" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: paste_full_timing ,
"Paste timing data" ,
2019-06-22 12:35:38 -07:00
EnabledIfClipboardTimingIsSafe , EditMode_Full , true , true , 0 , nullptr ),
2012-02-27 13:31:15 -05:00
MenuRowDef ( ScreenEdit :: erase_step_timing ,
"Erase step timing" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr )
2011-03-17 01:43:45 -04:00
);
2015-04-04 09:10:00 -06:00
static MenuDef g_TimingDataChangeInformation (
"ScreenMiniMenuTimingDataChangeInformation" ,
MenuRowDef ( ScreenEdit :: timing_all ,
"All timing" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2015-04-04 09:10:00 -06:00
MenuRowDef ( ScreenEdit :: timing_bpm ,
"BPM changes" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2015-04-04 09:10:00 -06:00
MenuRowDef ( ScreenEdit :: timing_stop ,
"Stops" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2015-04-04 09:10:00 -06:00
MenuRowDef ( ScreenEdit :: timing_delay ,
"Delays" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2015-04-04 09:10:00 -06:00
// Time signatures disabled because they don't fully work. -Kyz
// MenuRowDef(ScreenEdit::timing_time_sig,
// "Time Signatures",
2019-06-22 12:35:38 -07:00
// true, EditMode_Full, true, true, 0, nullptr),
2015-04-04 09:10:00 -06:00
MenuRowDef ( ScreenEdit :: timing_warp ,
"Warps" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2015-04-04 09:10:00 -06:00
MenuRowDef ( ScreenEdit :: timing_label ,
"Labels" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2015-04-04 09:10:00 -06:00
MenuRowDef ( ScreenEdit :: timing_tickcount ,
"Tickcount" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2015-04-04 09:10:00 -06:00
MenuRowDef ( ScreenEdit :: timing_combo ,
"Combo segments" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2015-04-04 09:10:00 -06:00
MenuRowDef ( ScreenEdit :: timing_speed ,
"Speed segments" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2015-04-04 09:10:00 -06:00
MenuRowDef ( ScreenEdit :: timing_scroll ,
"Scroll segments" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr ),
2015-04-04 09:10:00 -06:00
MenuRowDef ( ScreenEdit :: timing_fake ,
"Fakes" ,
2019-06-22 12:35:38 -07:00
true , EditMode_Full , true , true , 0 , nullptr )
2015-04-04 09:10:00 -06:00
);
2012-02-27 13:31:15 -05:00
// XXX: What are these enums used for?
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
};
2011-03-17 01:43:45 -04:00
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" ,
2012-02-27 13:39:35 -05:00
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 ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , false , 0 , nullptr ),
2012-02-27 13:39:35 -05:00
MenuRowDef ( ScreenEdit :: effect ,
"Force Effect" ,
true ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , false , 0 , nullptr ),
2012-02-27 13:39:35 -05:00
MenuRowDef ( ScreenEdit :: color1 ,
"Force Color 1" ,
true ,
EditMode_Full , true , false , 0 , "-" , "#FFFFFF" , "#808080" , "#FFFFFF80" ,
"#000000" , "#FF0000" , "#00FF00" , "#0000FF" , "#FFFF00" , "#00FFFF" , "#FF00FF" ),
MenuRowDef ( ScreenEdit :: color2 ,
"Force Color 2" ,
true ,
EditMode_Full , true , false , 0 , "-" , "#FFFFFF" , "#808080" , "#FFFFFF80" ,
"#000000" , "#FF0000" , "#00FF00" , "#0000FF" , "#FFFF00" , "#00FFFF" , "#FF00FF" ),
MenuRowDef ( ScreenEdit :: file1_type ,
"File1 Type" ,
true ,
2020-10-20 02:16:02 +09:00
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" ,
2012-02-27 13:39:35 -05:00
"Dynamic Random" , "Baked Random" , "None" ),
MenuRowDef ( ScreenEdit :: file1_song_bganimation ,
"File1 Song BGAnimation" ,
EnabledIfSet1SongBGAnimation ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , false , 0 , nullptr ),
2012-02-27 13:39:35 -05:00
MenuRowDef ( ScreenEdit :: file1_song_movie ,
"File1 Song Movie" ,
EnabledIfSet1SongMovie ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , false , 0 , nullptr ),
2012-02-27 13:39:35 -05:00
MenuRowDef ( ScreenEdit :: file1_song_still ,
"File1 Song Still" ,
EnabledIfSet1SongBitmap ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , false , 0 , nullptr ),
2012-02-27 13:39:35 -05:00
MenuRowDef ( ScreenEdit :: file1_global_bganimation ,
"File1 Global BGAnimation" ,
EnabledIfSet1GlobalBGAnimation ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , false , 0 , nullptr ),
2012-02-27 13:39:35 -05:00
MenuRowDef ( ScreenEdit :: file1_global_movie ,
"File1 Global Movie" ,
EnabledIfSet1GlobalMovie ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , false , 0 , nullptr ),
2012-02-27 13:39:35 -05:00
MenuRowDef ( ScreenEdit :: file1_global_movie_song_group ,
"File1 Global Movie (Group)" ,
EnabledIfSet1GlobalMovieSongGroup ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , false , 0 , nullptr ),
2012-02-27 13:39:35 -05:00
MenuRowDef ( ScreenEdit :: file1_global_movie_song_group_and_genre ,
"File1 Global Movie (Group + Genre)" ,
EnabledIfSet1GlobalMovieSongGroupAndGenre ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , false , 0 , nullptr ),
2012-02-27 13:39:35 -05:00
MenuRowDef ( ScreenEdit :: file2_type ,
"File2 Type" ,
true ,
EditMode_Full , true , true , 0 , "Song BGAnimation" , "Song Movie" ,
2020-10-20 02:16:02 +09:00
"Song Bitmap" , "Global BGAnimation" , "Global Movie" ,
"Global Movie from Song Group" , "Global Movie from Song Group and Genre" ,
2012-02-27 13:39:35 -05:00
"Dynamic Random" , "Baked Random" , "None" ),
MenuRowDef ( ScreenEdit :: file2_song_bganimation ,
"File2 Song BGAnimation" ,
EnabledIfSet2SongBGAnimation ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , false , 0 , nullptr ),
2012-02-27 13:39:35 -05:00
MenuRowDef ( ScreenEdit :: file2_song_movie ,
"File2 Song Movie" ,
EnabledIfSet2SongMovie ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , false , 0 , nullptr ),
2012-02-27 13:39:35 -05:00
MenuRowDef ( ScreenEdit :: file2_song_still ,
"File2 Song Still" ,
EnabledIfSet2SongBitmap ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , false , 0 , nullptr ),
2012-02-27 13:39:35 -05:00
MenuRowDef ( ScreenEdit :: file2_global_bganimation ,
"File2 Global BGAnimation" ,
2020-10-20 02:16:02 +09:00
EnabledIfSet2GlobalBGAnimation ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , false , 0 , nullptr ),
2012-02-27 13:39:35 -05:00
MenuRowDef ( ScreenEdit :: file2_global_movie ,
"File2 Global Movie" ,
EnabledIfSet2GlobalMovie ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , false , 0 , nullptr ),
2012-02-27 13:39:35 -05:00
MenuRowDef ( ScreenEdit :: file2_global_movie_song_group ,
"File2 Global Movie (Group)" ,
EnabledIfSet2GlobalMovieSongGroup ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , false , 0 , nullptr ),
2012-02-27 13:39:35 -05:00
MenuRowDef ( ScreenEdit :: file2_global_movie_song_group_and_genre ,
"File2 Global Movie (Group + Genre)" ,
EnabledIfSet2GlobalMovieSongGroupAndGenre ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , false , 0 , nullptr ),
2012-02-27 13:39:35 -05:00
MenuRowDef ( ScreenEdit :: delete_change ,
"Remove Change" ,
true ,
2019-06-22 12:35:38 -07:00
EditMode_Full , true , true , 0 , nullptr )
2011-03-17 01:43:45 -04:00
);
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 )
{
2022-07-10 18:28:56 +03:00
std :: vector < RString > vsPaths ;
std :: vector < RString > vsNames ;
2011-03-17 01:43:45 -04:00
BackgroundUtil :: GetGlobalRandomMovies (
pSong ,
"" ,
2020-10-20 02:16:02 +09:00
vsPaths ,
2012-10-17 11:21:28 -07:00
vsNames ,
2011-03-17 01:43:45 -04:00
bTryGenre );
2012-10-17 11:21:28 -07:00
return vsNames . empty () ? RString () : vsNames [ RandomInt ( vsNames . size ())];
2011-03-17 01:43:45 -04:00
}
static MenuDef g_InsertTapAttack (
"ScreenMiniMenuInsertTapAttack" ,
2012-02-27 13:39:35 -05:00
MenuRowDef ( - 1 ,
"Duration seconds" ,
true , EditMode_Practice , true , false , 3 , "5" , "10" , "15" , "20" , "25" , "30" , "35" , "40" , "45" ), // TODO: Replace
MenuRowDef ( - 1 ,
"Set modifiers" ,
true , EditMode_Practice , true , true , 0 , "Press Start" )
2011-03-17 01:43:45 -04:00
);
static MenuDef g_InsertCourseAttack (
"ScreenMiniMenuInsertCourseAttack" ,
2012-02-27 13:39:35 -05:00
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-03-17 01:43:45 -04:00
);
2012-02-27 13:39:35 -05: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-07-12 21:56:17 -04:00
2011-03-17 01:43:45 -04:00
static MenuDef g_CourseMode (
"ScreenMiniMenuCourseDisplay" ,
2019-06-22 12:35:38 -07:00
MenuRowDef ( - 1 , "Play mods from course" , true , EditMode_Practice , true , false , 0 , nullptr )
2011-03-17 01:43:45 -04:00
);
// 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 ;
2024-10-01 00:43:07 -07:00
static void SetDefaultEditorNoteSkin ( size_t num , RString & sNameOut , RString & defaultValueOut )
2011-03-17 01:43:45 -04:00
{
sNameOut = ssprintf ( "EditorNoteSkinP%d" , int ( num + 1 ) );
// XXX: We need more supported noteskins.
2022-06-04 13:40:45 -07:00
defaultValueOut = "cel" ;
2011-03-17 01:43:45 -04:00
}
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 ()
{
2019-06-22 12:35:38 -07:00
m_pSoundMusic = nullptr ;
2020-10-20 02:16:02 +09: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" );
2024-08-10 12:07:54 -04:00
main_player_ = GAMESTATE -> GetMasterPlayerNumber ();
2011-03-17 01:43:45 -04:00
2019-06-22 12:35:38 -07:00
ASSERT ( GAMESTATE -> m_pCurSong != nullptr );
2024-08-10 12:07:54 -04:00
ASSERT ( GAMESTATE -> m_pCurSteps [ main_player_ ] != nullptr );
2011-03-17 01:43:45 -04:00
EDIT_MODE . Load ( m_sName , "EditMode" );
ScreenWithMenuElements :: Init ();
InitEditMappings ();
2020-10-20 02:16:02 +09: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 ;
2012-10-17 11:21:28 -07:00
m_InputPlayerNumber = PLAYER_INVALID ;
2014-12-07 01:53:17 -07:00
if ( GAMESTATE -> GetCurrentStyle ( GAMESTATE -> GetMasterPlayerNumber ()) -> m_StyleType == StyleType_TwoPlayersSharedSides )
2024-08-10 12:07:54 -04:00
m_InputPlayerNumber = main_player_ ;
2011-03-17 01:43:45 -04:00
m_pSong = GAMESTATE -> m_pCurSong ;
2024-08-10 12:07:54 -04:00
m_pSteps = GAMESTATE -> m_pCurSteps [ main_player_ ];
2020-10-20 02:16:02 +09:00
/* The user will most likely switch into Step Timing after laying down
2012-03-20 19:51:46 -07:00
some initial notes. It also throws off many people at first glance.
2012-04-08 13:47:23 -04:00
*/
2012-04-08 23:56:28 -04:00
if ( m_pSong -> IsStepsUsingDifferentTiming ( m_pSteps ) )
2011-05-25 14:07:53 -04:00
GAMESTATE -> m_bIsUsingStepTiming = true ;
2012-03-20 19:51:46 -07:00
2011-03-17 01:43:45 -04:00
m_bReturnToRecordMenuAfterPlay = false ;
m_fBeatToReturnTo = 0 ;
2020-10-20 02:16:02 +09:00
2011-03-17 01:43:45 -04:00
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 ;
2020-10-20 02:16:02 +09:00
2012-05-21 21:42:06 -04:00
attackInProcess = - 1 ;
modInProcess = - 1 ;
2020-10-20 02:16:02 +09:00
2011-03-17 01:43:45 -04:00
this -> AddChild ( & m_Background );
m_SnapDisplay . SetXY ( EDIT_X , PLAYER_Y_STANDARD );
m_SnapDisplay . Load ();
// xxx: hardcoded command -aj
2017-05-14 02:49:55 +08:00
m_SnapDisplay . SetZoom ( SCREEN_HEIGHT / 480 * 0.5 );
2011-03-17 01:43:45 -04:00
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.
2020-10-20 02:16:02 +09:00
if ( ! GAMESTATE -> m_bDidModeChangeNoteSkin )
2011-03-17 01:43:45 -04:00
{
GAMESTATE -> m_bDidModeChangeNoteSkin = true ;
2020-10-20 02:16:02 +09:00
FOREACH_PlayerNumber ( pn )
2011-03-17 01:43:45 -04:00
{
const RString & sNoteSkin = EDITOR_NOTE_SKINS [ pn ]. Get ();
if ( NOTESKIN -> DoesNoteSkinExist ( sNoteSkin ) )
2020-10-20 02:16:02 +09:00
PO_GROUP_ASSIGN ( GAMESTATE -> m_pPlayerState [ pn ] -> m_PlayerOptions ,
2011-03-17 01:43:45 -04:00
ModsLevel_Preferred , m_sNoteSkin , sNoteSkin );
}
}
2024-08-10 12:07:54 -04:00
m_PlayerStateEdit . SetPlayerNumber ( main_player_ );
2014-12-07 01:53:17 -07:00
m_PlayerStateEdit . m_NotefieldZoom = 1.0f ;
2024-08-10 12:07:54 -04:00
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
2024-08-10 12:07:54 -04:00
if ( NOTESKIN -> DoesNoteSkinExist ( EDITOR_NOTE_SKINS [ main_player_ ]. Get () ) )
2011-03-17 01:43:45 -04:00
{
2024-08-10 12:07:54 -04:00
PO_GROUP_ASSIGN ( m_PlayerStateEdit . m_PlayerOptions , ModsLevel_Stage , m_sNoteSkin , EDITOR_NOTE_SKINS [ main_player_ ]. Get () );
2011-03-17 01:43:45 -04:00
}
else
{
2024-08-10 12:07:54 -04:00
PO_GROUP_ASSIGN ( m_PlayerStateEdit . m_PlayerOptions , ModsLevel_Stage , m_sNoteSkin , GAMESTATE -> m_pPlayerState [ main_player_ ] -> m_PlayerOptions . GetStage (). m_sNoteSkin );
2011-03-17 01:43:45 -04:00
}
m_PlayerStateEdit . m_PlayerOptions . FromString ( ModsLevel_Stage , EDIT_MODIFIERS );
2020-10-20 02:16:02 +09:00
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 );
2017-05-14 02:49:55 +08:00
m_NoteFieldEdit . SetZoom ( SCREEN_HEIGHT / 480 * 0.5 );
2014-12-07 01:53:17 -07:00
m_NoteFieldEdit . Init ( & m_PlayerStateEdit , PLAYER_HEIGHT * 2 , false );
2011-03-17 01:43:45 -04:00
m_NoteFieldEdit . Load ( & m_NoteDataEdit , - 240 , 850 );
this -> AddChild ( & m_NoteFieldEdit );
m_NoteDataRecord . SetNumTracks ( m_NoteDataEdit . GetNumTracks () );
m_NoteFieldRecord . SetXY ( RECORD_X , RECORD_Y );
2024-08-10 12:07:54 -04:00
m_NoteFieldRecord . Init ( GAMESTATE -> m_pPlayerState [ main_player_ ], 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 ;
m_bRemoveNoteButtonDown = false ;
m_Clipboard . SetNumTracks ( m_NoteDataEdit . GetNumTracks () );
2020-10-20 02:16:02 +09:00
2011-07-26 12:21:31 -04:00
clipboardFullTiming = GAMESTATE -> m_pCurSong -> m_SongTiming ; // always have a backup.
2016-01-18 11:48:50 -07:00
clipboard_full_timing = & clipboardFullTiming ;
2011-03-17 01:43:45 -04:00
m_bHasUndo = false ;
m_Undo . SetNumTracks ( m_NoteDataEdit . GetNumTracks () );
2015-02-17 15:37:49 -07:00
SetDirty ( m_NoteDataEdit . IsEmpty ()); // require saving if empty.
if ( GAMESTATE -> m_pCurSong -> WasLoadedFromAutosave ())
{
SetDirty ( true );
}
2011-03-17 01:43:45 -04:00
2024-09-23 16:12:04 -04:00
// There are two conditions for centering the notefield.
// 1. We're in EditMode
// 2. We're in PracticeMode, the preference is enabled,
// sylte is OnePlayerOneSide, and the theme allows it.
//
// If the "center_enabled" check is modified, also modify
// ScreenGameplay::Center1Player().
ThemeMetric < bool > allow_center ;
allow_center . Load ( "ScreenGameplay" , "AllowCenter1Player" );
bool center_enabled = ( Preference < bool >:: GetPreferenceByName ( "Center1Player" ) -> Get ()
&& GAMESTATE -> GetCurrentStyle ( PLAYER_INVALID ) -> m_StyleType
== StyleType_OnePlayerOneSide )
&& GAMESTATE -> m_PlayMode != PLAY_MODE_BATTLE
&& GAMESTATE -> m_PlayMode != PLAY_MODE_RAVE
&& allow_center ;
bool edit_mode_screen = ( m_sName == "ScreenEdit" );
player_manager_ . SetCenter ( edit_mode_screen || center_enabled );
2024-08-10 12:07:54 -04:00
player_manager_ . AddPlayers ( m_NoteDataEdit );
player_manager_ . AddPlayersToActorFrame ( * this );
2024-09-30 16:19:38 -04:00
TransitionEditState ( STATE_EDITING );
2011-03-17 01:43:45 -04:00
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 ();
2020-10-20 02:16:02 +09: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 ;
2024-08-10 12:07:54 -04:00
player_manager_ . PlayTicks ( m_GameplayAssist );
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 ();
2020-10-20 02:16:02 +09:00
SOUND -> PlayMusic (
2015-03-04 01:31:02 -07:00
m_pSong -> GetPreviewMusicPath (),
2019-06-22 12:35:38 -07:00
nullptr ,
2011-03-17 01:43:45 -04:00
false ,
2015-03-04 01:31:02 -07:00
m_pSong -> GetPreviewStartSeconds (),
2011-03-17 01:43:45 -04:00
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 ();
2022-07-10 18:28:56 +03:00
std :: vector < MenuRowDef > aRows ;
2019-06-22 12:35:38 -07:00
for ( MenuRowDef const & r : pDef -> rows )
2011-03-17 01:43:45 -04:00
{
// Don't add rows that aren't applicable to this edit mode.
2019-06-22 12:35:38 -07:00
if ( EDIT_MODE >= r . emShowIn )
menu . rows . push_back ( r );
2011-03-17 01:43:45 -04:00
}
}
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 );
2020-10-20 02:16:02 +09:00
const float fRate = PREFSMAN -> m_bRateModsAffectTweens ? GAMESTATE -> m_SongOptions . GetCurrent (). m_fMusicRate : 1.0f ;
2011-03-17 01:43:45 -04:00
if ( m_pSoundMusic -> IsPlaying () )
{
RageTimer tm ;
2024-09-13 01:58:02 -07:00
const float fSeconds = m_pSoundMusic -> GetPositionSeconds ( & tm );
2014-07-24 19:45:17 -05:00
GAMESTATE -> UpdateSongPosition ( fSeconds , GAMESTATE -> m_pCurSong -> m_SongTiming , tm );
2011-03-17 01:43:45 -04:00
}
2015-02-17 15:37:49 -07:00
if ( m_EditState == STATE_EDITING )
{
2024-09-08 23:13:50 -07:00
if ( IsDirty () && m_next_autosave_time > - 1000000 &&
RageTimer :: GetTimeSinceStartMicroseconds () > m_next_autosave_time )
2015-02-17 15:37:49 -07:00
{
PerformSave ( true );
}
}
2020-10-20 02:16:02 +09:00
if ( m_EditState == STATE_RECORDING )
2011-03-17 01:43:45 -04:00
{
2011-05-13 10:07:41 -04:00
// TODO: Find a way to prevent STATE_RECORDING when in Song Timing.
2020-10-20 02:16:02 +09:00
2014-12-07 01:53:17 -07:00
for ( int t = 0 ; t < GAMESTATE -> GetCurrentStyle ( GAMESTATE -> GetMasterPlayerNumber ()) -> m_iColsPerPlayer ; t ++ ) // for each track
2011-03-17 01:43:45 -04:00
{
2022-07-10 18:28:56 +03:00
std :: vector < GameInput > GameI ;
2015-01-17 21:15:15 -07:00
GAMESTATE -> GetCurrentStyle ( GAMESTATE -> GetMasterPlayerNumber ()) -> StyleInputToGameInput ( t , PLAYER_1 , GameI );
float fSecsHeld = 0.0f ;
2024-10-01 00:43:07 -07:00
for ( size_t i = 0 ; i < GameI . size (); ++ i )
2015-01-17 21:15:15 -07:00
{
2022-07-10 18:28:56 +03:00
fSecsHeld = std :: max ( fSecsHeld , INPUTMAPPER -> GetSecsHeld ( GameI [ i ]));
2015-01-17 21:15:15 -07:00
}
2022-07-10 18:28:56 +03:00
fSecsHeld = std :: min ( fSecsHeld , m_RemoveNoteButtonLastChanged . Ago () );
2011-03-17 01:43:45 -04:00
if ( fSecsHeld == 0 )
continue ;
2013-01-02 10:56:34 -05:00
// TODO: Currently, this will ignore a hold note that's
// held past the end of selection. Ideally the hold
// note should be created, ending right at the end of
// selection (or appropriate quantization).
2011-03-17 01:43:45 -04:00
float fStartPlayingAtBeat = NoteRowToBeat ( m_iStartPlayingAt );
2013-01-02 10:56:34 -05:00
float fStopPlayingAtBeat = NoteRowToBeat ( m_iStopPlayingAt );
if ( GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_Position . m_fSongBeat <= fStartPlayingAtBeat ||
GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_Position . m_fSongBeat >= fStopPlayingAtBeat )
2011-03-17 01:43:45 -04:00
continue ;
float fStartedHoldingSeconds = m_pSoundMusic -> GetPositionSeconds () - fSecsHeld ;
2022-07-10 18:28:56 +03:00
float fStartBeat = std :: max ( fStartPlayingAtBeat , m_pSteps -> GetTimingData () -> GetBeatFromElapsedTime ( fStartedHoldingSeconds ) );
float fEndBeat = std :: max ( fStartBeat , GetBeat () );
fEndBeat = std :: min ( fEndBeat , fStopPlayingAtBeat );
2011-03-17 01:43:45 -04:00
// 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 );
}
2015-02-08 18:39:45 -07:00
else if ( fSecsHeld > record_hold_seconds )
2011-03-17 01:43:45 -04:00
{
// 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 )
{
2015-12-11 00:02:31 -07:00
ArrowEffects :: Update ();
2011-03-17 01:43:45 -04:00
/*
* 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 ;
2014-12-07 01:53:17 -07:00
for ( int t = 0 ; t < GAMESTATE -> GetCurrentStyle ( GAMESTATE -> GetMasterPlayerNumber ()) -> m_iColsPerPlayer ; t ++ ) // for each track
2011-03-17 01:43:45 -04:00
{
2022-07-10 18:28:56 +03:00
std :: vector < GameInput > GameI ;
2015-01-17 21:15:15 -07:00
GAMESTATE -> GetCurrentStyle ( GAMESTATE -> GetMasterPlayerNumber ()) -> StyleInputToGameInput ( t , PLAYER_1 , GameI );
2011-03-17 01:43:45 -04:00
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
{
2013-01-23 14:51:18 -05:00
float fSeconds = m_pSteps -> GetTimingData () -> GetElapsedTimeFromBeat ( fLastBeat );
fLastBeat = m_pSteps -> GetTimingData () -> GetBeatFromElapsedTime ( fSeconds + 0.5f );
2011-03-17 01:43:45 -04:00
}
2013-01-23 14:51:18 -05:00
float fStopAtSeconds = m_pSteps -> GetTimingData () -> 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 );
2020-10-20 02:16:02 +09:00
if ( m_EditState == STATE_PLAYING )
{
ScreenWithMenuElements :: Update ( fDeltaTime * fRate );
}
else
{
ScreenWithMenuElements :: Update ( fDeltaTime );
}
2011-03-17 01:43:45 -04:00
// Update trailing beat
2011-05-13 15:19:42 +07:00
float fDelta = GetBeat () - m_fTrailingBeat ;
2023-04-19 14:22:59 +02:00
if ( std :: abs ( 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 (),
2023-04-19 14:22:59 +02:00
std :: abs ( fDelta ) * fDeltaTime * 5 );
2011-03-17 01:43:45 -04:00
PlayTicks ();
}
2022-07-10 18:28:56 +03:00
static std :: vector < int > FindAllAttacksAtTime ( const AttackArray & attacks , float fStartTime )
2012-05-21 21:42:06 -04:00
{
2022-07-10 18:28:56 +03:00
std :: vector < int > ret ;
2012-05-21 21:42:06 -04:00
for ( unsigned i = 0 ; i < attacks . size (); ++ i )
{
2023-04-19 14:22:59 +02:00
if ( std :: abs ( attacks [ i ]. fStartSecond - fStartTime ) < 0.001f )
2012-05-21 21:42:06 -04:00
{
ret . push_back ( i );
}
}
return ret ;
}
static int FindAttackAtTime ( const AttackArray & attacks , float fStartTime )
{
for ( unsigned i = 0 ; i < attacks . size (); ++ i )
{
2023-04-19 14:22:59 +02:00
if ( std :: abs ( attacks [ i ]. fStartSecond - fStartTime ) < 0.001f )
2012-05-21 21:42:06 -04:00
return i ;
}
return - 1 ;
}
2012-10-17 11:21:28 -07:00
// TODO: Fix this mess. -Colby
2011-03-17 01:43:45 -04:00
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" );
2015-02-08 18:39:45 -07:00
static LocalizedString RECORD_HOLD_TIME ( "ScreenEdit" , "Record Hold Time" );
2011-03-17 01:43:45 -04:00
static ThemeMetric < RString > CURRENT_BEAT_FORMAT ( "ScreenEdit" , "CurrentBeatFormat" );
static ThemeMetric < RString > CURRENT_SECOND_FORMAT ( "ScreenEdit" , "CurrentSecondFormat" );
static ThemeMetric < RString > SNAP_TO_FORMAT ( "ScreenEdit" , "SnapToFormat" );
static ThemeMetric < RString > SELECTION_BEAT_BEGIN_FORMAT ( "ScreenEdit" , "SelectionBeatBeginFormat" );
static ThemeMetric < RString > SELECTION_BEAT_UNFINISHED_FORMAT ( "ScreenEdit" , "SelectionBeatUnfinishedFormat" );
static ThemeMetric < RString > SELECTION_BEAT_END_FORMAT ( "ScreenEdit" , "SelectionBeatEndFormat" );
static ThemeMetric < RString > DIFFICULTY_FORMAT ( "ScreenEdit" , "DifficultyFormat" );
static ThemeMetric < RString > ROUTINE_PLAYER_FORMAT ( "ScreenEdit" , "RoutinePlayerFormat" );
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" );
2015-02-08 18:39:45 -07:00
static ThemeMetric < RString > RECORD_HOLD_TIME_FORMAT ( "ScreenEdit" , "RecordHoldTimeFormat" );
2011-03-17 01:43:45 -04:00
void ScreenEdit :: UpdateTextInfo ()
{
2019-06-22 12:35:38 -07:00
if ( m_pSteps == nullptr )
2011-03-17 01:43:45 -04:00
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 () );
2015-10-10 01:06:32 -06:00
float second = GetAppropriateTiming (). GetElapsedTimeFromBeatNoOffset ( GetBeat ());
sText += ssprintf ( CURRENT_SECOND_FORMAT . GetValue (), CURRENT_SECOND . GetValue (). c_str (), second );
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 ;
}
2012-02-27 13:42:15 -05:00
if ( EDIT_MODE . GetValue () == EditMode_Full )
2011-03-17 01:43:45 -04:00
{
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 () );
2012-04-24 00:11:28 +07:00
const RString tapnoteType = TapNoteTypeToString ( m_selectedTap . type );
sText += ssprintf ( TAP_NOTE_TYPE_FORMAT . GetValue (), TAP_NOTE_TYPE . GetValue (). c_str (), tapnoteType . c_str () );
2020-10-20 02:16:02 +09:00
2012-05-21 21:42:06 -04:00
AttackArray & attacks =
( GAMESTATE -> m_bIsUsingStepTiming ? m_pSteps -> m_Attacks : m_pSong -> m_Attacks );
float beat = GetAppropriateTiming (). GetElapsedTimeFromBeat ( GetBeat ());
sText += ssprintf ( "Attack here?: %s \n " , FindAttackAtTime ( attacks , beat ) > - 1 ? "YES" : "NO" );
2011-03-17 01:43:45 -04:00
}
2020-10-20 02:16:02 +09:00
2013-01-23 14:51:18 -05:00
GAMESTATE -> SetProcessedTimingData ( m_pSteps -> GetTimingData ());
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 )
{
2022-07-10 18:28:56 +03:00
std :: pair < int , int > tmp = m_NoteDataEdit . GetNumTapNotesTwoPlayer ();
2011-07-13 16:07:33 -04:00
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 () ) );
2020-10-20 02:16:02 +09: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 );
2015-02-08 18:39:45 -07:00
if ( record_hold_seconds < record_hold_default - .001f ||
record_hold_seconds > record_hold_default + .001f )
{
sText += ssprintf ( RECORD_HOLD_TIME_FORMAT . GetValue (), RECORD_HOLD_TIME . GetValue (). c_str (), record_hold_seconds );
}
2011-03-17 01:43:45 -04:00
break ;
}
m_textInfo . SetText ( sText );
2020-10-20 02:16:02 +09:00
2019-06-22 12:35:38 -07:00
GAMESTATE -> SetProcessedTimingData ( nullptr );
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 ());
2020-10-20 02:16:02 +09:00
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
2020-10-20 02:16:02 +09:00
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 ;
2020-10-20 02:16:02 +09:00
2011-05-13 14:14:57 +07:00
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
}
2013-01-12 22:48:38 -05:00
bool ScreenEdit :: Input ( const InputEventPlus & input )
2011-03-17 01:43:45 -04:00
{
// LOG->Trace( "ScreenEdit::Input()" );
2020-10-20 02:16:02 +09:00
2011-03-17 01:43:45 -04:00
// invalidate input if cmd/meta is being held.
if ( INPUTFILTER -> IsBeingPressed ( DeviceInput ( DEVICE_KEYBOARD , KEY_LMETA )) ||
INPUTFILTER -> IsBeingPressed ( DeviceInput ( DEVICE_KEYBOARD , KEY_RMETA )) )
2013-01-12 22:48:38 -05:00
return false ;
2011-03-17 01:43:45 -04:00
if ( m_In . IsTransitioning () || m_Out . IsTransitioning () )
2013-01-12 22:48:38 -05:00
return false ;
2011-03-17 01:43:45 -04:00
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 :
m_bTextInfoNeedsUpdate = true ;
2013-01-12 22:48:38 -05:00
return InputEdit ( input , EditB );
2011-03-17 01:43:45 -04:00
case STATE_RECORDING :
2013-01-12 22:48:38 -05:00
return InputRecord ( input , EditB );
2011-03-17 01:43:45 -04:00
case STATE_RECORDING_PAUSED :
2013-01-12 22:48:38 -05:00
return InputRecordPaused ( input , EditB );
2011-03-17 01:43:45 -04:00
case STATE_PLAYING :
2013-01-12 22:48:38 -05:00
return InputPlay ( input , EditB );
2011-03-17 01:43:45 -04:00
}
}
static void ShiftToRightSide ( int & iCol , int iNumTracks )
{
2014-12-07 01:53:17 -07:00
switch ( GAMESTATE -> GetCurrentStyle ( GAMESTATE -> GetMasterPlayerNumber ()) -> m_StyleType )
2011-03-17 01:43:45 -04:00
{
2014-12-07 01:53:17 -07:00
DEFAULT_FAIL ( GAMESTATE -> GetCurrentStyle ( GAMESTATE -> GetMasterPlayerNumber ()) -> m_StyleType );
2011-03-17 01:43:45 -04:00
case StyleType_OnePlayerOneSide :
break ;
case StyleType_TwoPlayersTwoSides :
case StyleType_OnePlayerTwoSides :
case StyleType_TwoPlayersSharedSides :
iCol += iNumTracks / 2 ;
break ;
}
}
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
2013-01-12 22:48:38 -05:00
bool ScreenEdit :: InputEdit ( const InputEventPlus & input , EditButton EditB )
2011-03-17 01:43:45 -04:00
{
if ( input . type == IET_RELEASE )
{
if ( EditPressed ( EDIT_BUTTON_SCROLL_SELECT , input . DeviceI ) )
m_iShiftAnchor = - 1 ;
2013-01-12 22:48:38 -05:00
// XXX Key releases usually don't count as "handled," but what
// does it mean in this case?
return false ;
2011-03-17 01:43:45 -04:00
}
2013-01-21 22:53:12 -05:00
const 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 ();
2020-10-20 02:16:02 +09:00
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 )
2013-01-12 22:48:38 -05:00
return false ; // We only care about first presses
2011-03-17 01:43:45 -04:00
int iCol = EditB - EDIT_BUTTON_COLUMN_0 ;
// Alt + number = input to right half
if ( EditIsBeingPressed ( EDIT_BUTTON_RIGHT_SIDE ) )
ShiftToRightSide ( iCol , m_NoteDataEdit . GetNumTracks () );
2020-10-20 02:16:02 +09:00
2011-10-17 22:58:04 -04:00
if ( iCol >= m_NoteDataEdit . GetNumTracks () )
2013-01-12 22:48:38 -05:00
return false ; // 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 );
2020-10-20 02:16:02 +09: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 ) )
{
2015-02-28 06:25:02 -07:00
m_soundRemoveNote . Play ( true );
2011-03-17 01:43:45 -04:00
SetDirty ( true );
SaveUndo ();
m_NoteDataEdit . SetTapNote ( iCol , iHeadRow , TAP_EMPTY );
// Don't CheckNumberOfNotesAndUndo. We don't want to revert any change that removes notes.
}
2014-07-25 18:45:02 -05:00
else if ( m_NoteDataEdit . GetTapNote ( iCol , iSongIndex ). type != TapNoteType_Empty )
2011-03-17 01:43:45 -04:00
{
2015-02-28 06:25:02 -07:00
m_soundRemoveNote . Play ( true );
2011-03-17 01:43:45 -04:00
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
{
2015-02-28 06:25:02 -07:00
m_soundAddNote . Play ( true );
2011-03-17 01:43:45 -04:00
SetDirty ( true );
SaveUndo ();
TapNote tn = m_selectedTap ;
tn . pn = m_InputPlayerNumber ;
m_NoteDataEdit . SetTapNote ( iCol , iSongIndex , tn );
CheckNumberOfNotesAndUndo ();
}
}
2013-01-12 22:48:38 -05:00
return true ;
2020-10-20 02:16:02 +09:00
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_CYCLE_TAP_LEFT :
{
switch ( m_selectedTap . type )
{
2014-07-25 18:45:02 -05:00
case TapNoteType_Tap : m_selectedTap = TAP_ORIGINAL_FAKE ; break ;
case TapNoteType_Mine : m_selectedTap = TAP_ORIGINAL_TAP ; break ;
case TapNoteType_Lift : m_selectedTap = TAP_ORIGINAL_MINE ; break ;
case TapNoteType_Fake : m_selectedTap = TAP_ORIGINAL_LIFT ; break ;
2011-03-17 01:43:45 -04:00
DEFAULT_FAIL ( m_selectedTap . type );
}
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
}
case EDIT_BUTTON_CYCLE_TAP_RIGHT :
{
switch ( m_selectedTap . type )
{
2014-07-25 18:45:02 -05:00
case TapNoteType_Tap : m_selectedTap = TAP_ORIGINAL_MINE ; break ;
case TapNoteType_Mine : m_selectedTap = TAP_ORIGINAL_LIFT ; break ;
case TapNoteType_Lift : m_selectedTap = TAP_ORIGINAL_FAKE ; break ;
case TapNoteType_Fake : m_selectedTap = TAP_ORIGINAL_TAP ; break ;
2011-03-17 01:43:45 -04:00
DEFAULT_FAIL ( m_selectedTap . type );
}
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
}
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-12-11 19:30:37 -05:00
currentCycleSegment = ( TimingSegmentType ) tmp ;
2013-01-12 22:48:38 -05:00
return true ;
2011-12-11 19:30:37 -05:00
}
2011-06-26 23:11:57 -04:00
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-12-11 19:30:37 -05:00
currentCycleSegment = ( TimingSegmentType ) tmp ;
2013-01-12 22:48:38 -05:00
return true ;
2011-11-26 13:45:29 -05:00
}
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 ;
}
2024-09-03 04:52:20 -07:00
iSpeed = std :: clamp ( iSpeed , 0 , ( int ) ARRAYLEN ( fSpeeds ) - 1 );
2011-03-17 01:43:45 -04:00
if ( fSpeeds [ iSpeed ] != fScrollSpeed )
{
2015-02-28 06:25:02 -07:00
m_soundMarker . Play ( true );
2011-03-17 01:43:45 -04:00
fScrollSpeed = fSpeeds [ iSpeed ];
}
PO_GROUP_ASSIGN ( pPlayerState -> m_PlayerOptions , ModsLevel_Song , m_fScrollSpeed , fScrollSpeed );
}
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_SCROLL_HOME :
ScrollTo ( 0 );
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_SCROLL_END :
ScrollTo ( m_NoteDataEdit . GetLastBeat () );
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
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 );
}
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
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 );
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
}
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 );
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
}
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 ) );
}
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
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 ) );
}
2013-01-12 22:48:38 -05:00
return true ;
2011-06-26 23:11:57 -04:00
case EDIT_BUTTON_SEGMENT_NEXT :
2013-01-12 22:48:38 -05:00
{
// TODO: Work around Stops and Delays. We MAY have to separate them.
2013-01-21 22:53:12 -05:00
const TimingData & timing = GetAppropriateTiming ();
2013-01-12 22:48:38 -05:00
ScrollTo ( timing . GetNextSegmentBeatAtBeat ( this -> currentCycleSegment ,
2011-07-14 23:54:06 -04:00
GetBeat ()));
2013-01-12 22:48:38 -05:00
}
return true ;
case EDIT_BUTTON_SEGMENT_PREV :
{
// TODO: Work around Stops and Delays. We MAY have to separate them.
2013-01-21 22:53:12 -05:00
const TimingData & timing = GetAppropriateTiming ();
2013-01-12 22:48:38 -05:00
ScrollTo ( timing . GetPreviousSegmentBeatAtBeat ( this -> currentCycleSegment ,
GetBeat ()));
}
return true ;
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_SNAP_NEXT :
if ( m_SnapDisplay . PrevSnapMode () )
OnSnapModeChange ();
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_SNAP_PREV :
if ( m_SnapDisplay . NextSnapMode () )
OnSnapModeChange ();
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
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
{
2022-07-10 18:28:56 +03:00
m_NoteFieldEdit . m_iEndMarker = std :: max ( m_NoteFieldEdit . m_iBeginMarker , iCurrentRow );
m_NoteFieldEdit . m_iBeginMarker = std :: min ( m_NoteFieldEdit . m_iBeginMarker , iCurrentRow );
2011-03-17 01:43:45 -04:00
}
}
else // both markers are laid
{
m_NoteFieldEdit . m_iBeginMarker = iCurrentRow ;
m_NoteFieldEdit . m_iEndMarker = - 1 ;
}
2015-02-28 06:25:02 -07:00
m_soundMarker . Play ( true );
2011-03-17 01:43:45 -04:00
}
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
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-03-17 01:43:45 -04:00
g_AreaMenu . rows [ undo ]. bEnabled = m_bHasUndo ;
EditMiniMenu ( & g_AreaMenu , SM_BackFromAreaMenu );
}
2013-01-12 22:48:38 -05:00
return true ;
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 ();
}
2020-10-20 02:16:02 +09:00
else
2011-06-10 03:04:47 -04:00
{
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 );
}
2013-01-12 22:48:38 -05:00
return true ;
2011-06-10 03:04:47 -04:00
}
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_OPEN_EDIT_MENU :
EditMiniMenu ( & g_MainMenu , SM_BackFromMainMenu );
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_OPEN_INPUT_HELP :
DoHelp ();
2013-01-12 22:48:38 -05:00
return true ;
2011-05-12 20:55:45 -04:00
case EDIT_BUTTON_OPEN_TIMING_MENU :
{
DisplayTimingMenu ();
2013-01-12 22:48:38 -05:00
return true ;
2011-05-12 20:55:45 -04:00
}
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 ());
2020-10-20 02:16:02 +09:00
2011-03-17 01:43:45 -04:00
// save current steps
Steps * pSteps = GAMESTATE -> m_pCurSteps [ PLAYER_1 ];
2019-06-22 12:35:38 -07:00
ASSERT ( pSteps != nullptr );
2011-03-17 01:43:45 -04:00
pSteps -> SetNoteData ( m_NoteDataEdit );
// Get all Steps of this StepsType
2012-02-27 13:45:12 -05:00
const StepsType st = pSteps -> m_StepsType ;
2022-07-10 18:28:56 +03:00
std :: vector < Steps *> vSteps ;
2011-03-17 01:43:45 -04:00
SongUtil :: GetSteps ( GAMESTATE -> m_pCurSong , vSteps , st );
// Sort them by difficulty.
StepsUtil :: SortStepsByTypeAndDifficulty ( vSteps );
// Find out what index the current Steps are
2022-07-10 18:28:56 +03:00
std :: vector < Steps *>:: iterator it = find ( vSteps . begin (), vSteps . end (), pSteps );
2011-03-17 01:43:45 -04:00
ASSERT ( it != vSteps . end () );
switch ( EditB )
{
DEFAULT_FAIL ( EditB );
2020-10-20 02:16:02 +09:00
case EDIT_BUTTON_OPEN_PREV_STEPS :
2011-03-17 01:43:45 -04:00
if ( it == vSteps . begin () )
{
SCREENMAN -> PlayInvalidSound ();
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
}
it -- ;
break ;
case EDIT_BUTTON_OPEN_NEXT_STEPS :
it ++ ;
if ( it == vSteps . end () )
{
SCREENMAN -> PlayInvalidSound ();
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
}
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 );
2015-02-28 06:25:02 -07:00
m_soundSwitchSteps . Play ( true );
2015-03-02 18:44:01 -07:00
// Reload the music because it can be different for every steps. -Kyz
m_AutoKeysounds . FinishLoading ();
m_pSoundMusic = m_AutoKeysounds . GetSound ();
2020-10-20 02:16:02 +09:00
2011-06-26 13:36:42 -04:00
ScrollTo ( GetAppropriateTiming (). GetBeatFromElapsedTime ( curSecond ) );
2011-03-17 01:43:45 -04:00
}
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
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 ;
2015-02-16 13:31:21 -07:00
if ( fNewBPM > 0.0f )
{
GetAppropriateTimingForUpdate (). AddSegment ( BPMSegment ( GetRow (), fNewBPM ));
}
2015-02-28 06:25:02 -07:00
( fDelta > 0 ? m_soundValueIncrease : m_soundValueDecrease ). Play ( true );
2011-03-17 01:43:45 -04:00
SetDirty ( true );
}
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
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?
2013-01-21 22:53:12 -05:00
TimingData & timing = GetAppropriateTimingForUpdate ();
2011-11-26 13:33:21 -05:00
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
2013-01-12 22:48:38 -05:00
return false ;
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
{
2022-07-10 18:28:56 +03:00
std :: vector < TimingSegment *> & stops = timing . GetTimingSegments ( SEGMENT_STOP );
2011-11-26 13:33:21 -05:00
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
2015-02-28 06:25:02 -07:00
( fDelta > 0 ? m_soundValueIncrease : m_soundValueDecrease ). Play ( true );
2011-03-17 01:43:45 -04:00
SetDirty ( true );
}
2013-01-12 22:48:38 -05:00
return true ;
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 ;
}
2020-10-20 02:16:02 +09:00
2011-11-26 13:56:27 -05:00
// is there a StopSegment on the current row?
2013-01-21 22:53:12 -05:00
TimingData & timing = GetAppropriateTimingForUpdate ();
2011-11-26 13:56:27 -05:00
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
2013-01-12 22:48:38 -05:00
return false ;
2011-11-26 13:56:27 -05:00
}
else
{
2022-07-10 18:28:56 +03:00
std :: vector < TimingSegment *> & stops = timing . GetTimingSegments ( SEGMENT_DELAY );
2011-11-26 13:56:27 -05:00
seg -> SetPause ( seg -> GetPause () + fDelta );
if ( seg -> GetPause () <= 0 )
stops . erase ( stops . begin () + i , stops . begin () + i + 1 );
}
2020-10-20 02:16:02 +09:00
2015-02-28 06:25:02 -07:00
( fDelta > 0 ? m_soundValueIncrease : m_soundValueDecrease ). Play ( true );
2011-11-26 13:56:27 -05:00
SetDirty ( true );
}
2013-01-12 22:48:38 -05:00
return true ;
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 ;
}
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). m_fBeat0OffsetInSeconds += fDelta ;
2015-02-28 06:25:02 -07:00
( fDelta > 0 ? m_soundValueIncrease : m_soundValueDecrease ). Play ( true );
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 );
}
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
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 ;
}
2020-10-20 02:16:02 +09:00
2011-03-17 01:43:45 -04:00
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 ;
2022-07-10 18:28:56 +03:00
m_pSong -> m_fMusicSampleLengthSeconds = std :: max ( m_pSong -> m_fMusicSampleLengthSeconds , 0.0f );
2011-03-17 01:43:45 -04:00
}
else
{
m_pSong -> m_fMusicSampleStartSeconds += fDelta ;
2022-07-10 18:28:56 +03:00
m_pSong -> m_fMusicSampleStartSeconds = std :: max ( m_pSong -> m_fMusicSampleStartSeconds , 0.0f );
2011-03-17 01:43:45 -04:00
}
2015-02-28 06:25:02 -07:00
( fDelta > 0 ? m_soundValueIncrease : m_soundValueDecrease ). Play ( true );
2011-03-17 01:43:45 -04:00
SetDirty ( true );
}
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_PLAY_SAMPLE_MUSIC :
PlayPreviewMusic ();
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
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
2022-07-10 18:28:56 +03:00
std :: vector < RString > vThrowAway ;
2011-05-12 23:25:50 -04:00
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 );
2019-06-22 12:35:38 -07:00
BackgroundUtil :: GetGlobalBGAnimations ( m_pSong , "" , vThrowAway , menu . rows [ file1_global_bganimation ]. choices ); // nullptr to get all background files
2011-05-12 23:25:50 -04:00
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 ;
2020-10-20 02:16:02 +09:00
BackgroundChange bgChange ;
2019-06-22 12:35:38 -07:00
for ( BackgroundChange & bgc : m_pSong -> GetBackgroundChanges ( g_CurrentBGChangeLayer ))
2011-05-12 23:25:50 -04:00
{
2019-06-22 12:35:38 -07:00
if ( bgc . m_fStartBeat == GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_Position . m_fSongBeat )
2011-05-12 23:25:50 -04:00
{
bAlreadyBGChangeHere = true ;
2019-06-22 12:35:38 -07:00
bgChange = bgc ;
2011-05-12 23:25:50 -04:00
}
}
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
}
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
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 ;
2022-07-10 18:28:56 +03:00
std :: vector < Course *> courses ;
2011-03-17 01:43:45 -04:00
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 );
}
2013-01-12 22:48:38 -05:00
return true ;
2011-06-24 19:32:46 -04:00
case EDIT_BUTTON_OPEN_STEP_ATTACK_MENU :
{
2012-05-21 21:42:06 -04:00
this -> DoStepAttackMenu ();
2013-01-12 22:48:38 -05:00
return true ;
2011-06-24 19:32:46 -04:00
}
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 ;
2019-06-22 12:35:38 -07:00
if ( pCourse == nullptr )
2013-01-12 22:48:38 -05:00
return false ;
2011-03-17 01:43:45 -04:00
CourseEntry & ce = pCourse -> m_vEntries [ GAMESTATE -> m_iEditCourseEntryIndex ];
2013-01-23 14:51:18 -05:00
float fStartTime = m_pSteps -> GetTimingData () -> 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 )
{
2019-06-22 12:35:38 -07:00
const RString sDuration = std :: to_string ( 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 );
}
2013-01-12 22:48:38 -05:00
return true ;
2011-06-24 19:32:46 -04:00
case EDIT_BUTTON_ADD_STEP_MODS :
{
float start = - 1 ;
float end = - 1 ;
PlayerOptions po ;
2020-10-20 02:16:02 +09:00
2011-06-24 19:32:46 -04:00
if ( m_NoteFieldEdit . m_iBeginMarker == - 1 ) // not highlighted
{
po . FromString ( "" );
}
else
{
2013-01-21 22:53:12 -05:00
const TimingData & timing = GetAppropriateTiming ();
2011-06-24 19:32:46 -04:00
start = timing . GetElapsedTimeFromBeat ( NoteRowToBeat ( m_NoteFieldEdit . m_iBeginMarker ));
2020-10-20 02:16:02 +09:00
AttackArray & attacks =
2011-06-24 19:32:46 -04:00
( GAMESTATE -> m_bIsUsingStepTiming ? m_pSteps -> m_Attacks : m_pSong -> m_Attacks );
int index = FindAttackAtTime ( attacks , start );
2020-10-20 02:16:02 +09:00
2011-06-24 19:32:46 -04:00
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 ));
}
2020-10-20 02:16:02 +09:00
2011-06-24 19:32:46 -04:00
}
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 );
2014-12-09 21:59:01 -07:00
SCREENMAN -> AddNewScreenToTop ( SET_MOD_SCREEN , SM_BackFromInsertStepAttackPlayerOptions );
2013-01-12 22:48:38 -05:00
return true ;
2011-06-24 19:32:46 -04:00
}
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 ;
2019-06-22 12:35:38 -07:00
if ( pCourse == nullptr )
2013-01-12 22:48:38 -05:00
return false ;
2011-03-17 01:43:45 -04:00
const CourseEntry & ce = pCourse -> m_vEntries [ GAMESTATE -> m_iEditCourseEntryIndex ];
if ( m_NoteFieldEdit . m_iBeginMarker == - 1 )
{
fStart = - 1 ;
fEnd = - 1 ;
po . FromString ( ce . sModifiers );
}
else
{
2020-10-20 02:16:02 +09:00
// TODO: Give Song/Step Timing switches/functions here?
2013-01-23 14:51:18 -05:00
TimingData * timing = m_pSteps -> GetTimingData ();
fStart = 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
2013-01-23 14:51:18 -05:00
fEnd = 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 );
2014-12-09 21:59:01 -07:00
SCREENMAN -> AddNewScreenToTop ( SET_MOD_SCREEN , SM_BackFromInsertCourseAttackPlayerOptions );
2011-03-17 01:43:45 -04:00
}
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
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
{
BackgroundLayer iLayer = BACKGROUND_LAYER_1 ;
BackgroundChange bgChange ;
2011-05-10 21:21:23 +07:00
bgChange . m_fStartBeat = GAMESTATE -> m_Position . m_fSongBeat ;
2019-06-22 12:35:38 -07:00
auto & changes = m_pSong -> GetBackgroundChanges ( iLayer );
for ( auto bgc = changes . begin (); bgc != changes . end (); ++ bgc )
2011-03-17 01:43:45 -04:00
{
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
{
bgChange = * bgc ;
2019-06-22 12:35:38 -07:00
changes . erase ( bgc );
2011-03-17 01:43:45 -04:00
break ;
}
}
bgChange . m_def . m_sFile1 = sName ;
m_pSong -> AddBackgroundChange ( iLayer , bgChange );
2015-02-28 06:25:02 -07:00
m_soundMarker . Play ( true );
2011-03-17 01:43:45 -04:00
}
}
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_PLAY_FROM_START :
HandleMainMenuChoice ( play_whole_song );
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_PLAY_FROM_CURSOR :
HandleMainMenuChoice ( play_current_beat_to_end );
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_PLAY_SELECTION :
HandleMainMenuChoice ( play_selection );
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
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 );
2022-07-10 18:28:56 +03:00
m_iStopPlayingAt = std :: max ( m_iStartPlayingAt , m_NoteDataEdit . GetLastRow () + 1 );
2011-03-17 01:43:45 -04:00
}
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 () )
2022-07-10 18:28:56 +03:00
m_iStopPlayingAt = std :: min ( m_iStopPlayingAt , BeatToNoteRow ( GetMaximumBeatForNewNote ()) );
2011-03-17 01:43:45 -04:00
if ( m_iStartPlayingAt >= m_iStopPlayingAt )
{
SCREENMAN -> PlayInvalidSound ();
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
}
TransitionEditState ( STATE_RECORDING );
}
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_RECORD_FROM_CURSOR :
2011-06-01 14:01:35 -04:00
m_iStartPlayingAt = BeatToNoteRow ( GetAppropriatePosition (). m_fSongBeat );
2022-07-10 18:28:56 +03:00
m_iStopPlayingAt = std :: max ( m_iStartPlayingAt , m_NoteDataEdit . GetLastRow () );
2011-03-17 01:43:45 -04:00
TransitionEditState ( STATE_RECORDING );
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
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 ();
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_INSERT_SHIFT_PAUSES :
HandleAreaMenuChoice ( shift_pauses_forward );
SCREENMAN -> PlayInvalidSound ();
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
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 ();
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_DELETE_SHIFT_PAUSES :
HandleAreaMenuChoice ( shift_pauses_backward );
SCREENMAN -> PlayInvalidSound ();
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
2015-02-08 18:39:45 -07:00
case EDIT_BUTTON_RECORD_HOLD_LESS :
record_hold_seconds -= .01f ;
if ( record_hold_seconds <= 0.0f )
{
record_hold_seconds = 0.0f ;
}
return true ;
case EDIT_BUTTON_RECORD_HOLD_MORE :
record_hold_seconds += .01f ;
return true ;
case EDIT_BUTTON_RECORD_HOLD_RESET :
record_hold_seconds = record_hold_default ;
return true ;
case EDIT_BUTTON_RECORD_HOLD_OFF :
record_hold_seconds = 120.0f ;
return true ;
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_SAVE :
HandleMainMenuChoice ( ScreenEdit :: save );
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_UNDO :
Undo ();
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_SWITCH_PLAYERS :
2013-01-12 22:48:38 -05:00
if ( m_InputPlayerNumber == PLAYER_INVALID )
return false ;
enum_add ( m_InputPlayerNumber , 1 );
if ( m_InputPlayerNumber == NUM_PLAYERS )
m_InputPlayerNumber = PLAYER_1 ;
2015-02-28 06:25:02 -07:00
m_soundSwitchPlayer . Play ( true );
2013-01-12 22:48:38 -05:00
return true ;
2020-10-20 02:16:02 +09:00
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 ;
2015-02-28 06:25:02 -07:00
m_soundSwitchTiming . Play ( true );
2013-01-12 22:48:38 -05:00
return true ;
default :
return false ;
2011-03-17 01:43:45 -04:00
}
}
2013-01-12 22:48:38 -05:00
bool ScreenEdit :: InputRecord ( const InputEventPlus & input , EditButton EditB )
2011-03-17 01:43:45 -04:00
{
if ( input . type == IET_FIRST_PRESS && EditB == EDIT_BUTTON_RETURN_TO_EDIT )
{
TransitionEditState ( STATE_EDITING );
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
}
if ( input . pn != PLAYER_1 )
2013-01-12 22:48:38 -05:00
return false ; // ignore
2011-03-17 01:43:45 -04:00
2014-12-07 01:53:17 -07:00
const int iCol = GAMESTATE -> GetCurrentStyle ( GAMESTATE -> GetMasterPlayerNumber ()) -> GameInputToColumn ( input . GameI );
2011-03-17 01:43:45 -04:00
2013-01-02 10:38:11 -06:00
//Is this actually a column? If not, ignore the input.
if ( iCol == - 1 )
2013-01-12 22:48:38 -05:00
return false ;
2013-01-02 10:38:11 -06:00
2011-03-17 01:43:45 -04:00
switch ( input . type )
{
DEFAULT_FAIL ( input . type );
case IET_FIRST_PRESS :
{
if ( EditIsBeingPressed ( EDIT_BUTTON_REMOVE_NOTE ) )
{
// Remove notes in Update.
2013-01-12 22:48:38 -05:00
return false ;
2011-03-17 01:43:45 -04:00
}
// 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 )
2013-01-12 22:48:38 -05:00
return false ;
2011-03-17 01:43:45 -04:00
// Don't add outside of the range.
if ( iRow < m_iStartPlayingAt || iRow >= m_iStopPlayingAt )
2013-01-12 22:48:38 -05:00
return false ;
2011-03-17 01:43:45 -04:00
// 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 );
}
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
case IET_REPEAT :
case IET_RELEASE :
// don't add or extend holds here; we do it in Update()
2013-01-12 22:48:38 -05:00
return false ;
2011-03-17 01:43:45 -04:00
}
}
2013-01-12 22:48:38 -05:00
bool ScreenEdit :: InputRecordPaused ( const InputEventPlus & input , EditButton EditB )
2011-03-17 01:43:45 -04:00
{
if ( input . type != IET_FIRST_PRESS )
2013-01-12 22:48:38 -05:00
return false ; // don't care
2011-03-17 01:43:45 -04:00
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 );
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_PLAY_SELECTION :
TransitionEditState ( STATE_PLAYING );
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_RECORD_SELECTION :
2011-05-15 00:09:44 -04:00
TransitionEditState ( STATE_RECORDING );
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
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 ();
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
}
}
// 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 () )
2022-07-10 18:28:56 +03:00
m_iStopPlayingAt = std :: min ( m_iStopPlayingAt , BeatToNoteRow ( GetMaximumBeatForNewNote ()) );
2011-03-17 01:43:45 -04:00
}
TransitionEditState ( STATE_RECORDING );
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
case EDIT_BUTTON_RETURN_TO_EDIT :
TransitionEditState ( STATE_EDITING );
2013-01-12 22:48:38 -05:00
return true ;
default :
return false ;
2011-03-17 01:43:45 -04:00
}
}
2013-01-12 22:48:38 -05:00
bool ScreenEdit :: InputPlay ( const InputEventPlus & input , EditButton EditB )
2011-03-17 01:43:45 -04:00
{
switch ( input . type )
{
case IET_RELEASE :
case IET_FIRST_PRESS :
break ;
default :
2013-01-12 22:48:38 -05:00
return false ;
2011-03-17 01:43:45 -04:00
}
GameButtonType gbt = GAMESTATE -> m_pCurGame -> GetPerButtonInfo ( input . GameI . button ) -> m_gbt ;
2024-08-10 12:07:54 -04:00
if ( player_manager_ . HandleGameplayInput ( input , gbt )) {
return true ;
};
2011-03-17 01:43:45 -04:00
2015-12-05 20:02:00 -06:00
if ( gbt == GameButtonType_Menu && input . type == IET_FIRST_PRESS )
2011-03-17 01:43:45 -04:00
{
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 );
2013-01-12 22:48:38 -05:00
return true ;
2011-03-17 01:43:45 -04:00
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 ;
}
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). 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
}
2013-01-12 22:48:38 -05:00
return true ;
2011-06-06 18:27:52 -04:00
default : break ;
2011-03-17 01:43:45 -04:00
}
}
2013-01-12 22:48:38 -05:00
return false ;
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;
}
2020-10-20 02:16:02 +09:00
2011-03-17 01:43:45 -04:00
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 )
2024-08-10 12:07:54 -04:00
GAMESTATE -> m_pCurSteps [ main_player_ ] -> 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.
2024-08-10 12:07:54 -04:00
FOREACH_EnabledPlayer ( pn ) {
GAMESTATE -> m_pPlayerState [ pn ] -> RemoveActiveAttacks ();
// Load the player's default PlayerOptions.
GAMESTATE -> m_pPlayerState [ pn ] -> RebuildPlayerOptionsFromActiveAttacks ();
2011-03-17 01:43:45 -04:00
2024-08-10 12:07:54 -04:00
// Snap to current options.
GAMESTATE -> m_pPlayerState [ pn ] -> m_PlayerOptions . SetCurrentToLevel ( ModsLevel_Stage );
}
2011-03-17 01:43:45 -04:00
}
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
2022-07-10 18:28:56 +03:00
SetBeat ( std :: max ( 0.0f , 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 :
{
2022-07-10 18:28:56 +03:00
m_NoteDataEdit . RevalidateATIs ( std :: vector < int > (), false );
2011-03-17 01:43:45 -04:00
if ( bStateChanging )
AdjustSync :: ResetOriginalSyncData ();
2015-01-31 14:03:30 -07:00
/* Give a lead-in. If we're loading Player, this must be done first.
2011-05-13 10:07:41 -04:00
* Also be sure to get the right timing. */
2015-01-31 14:03:30 -07:00
float fSeconds = GetAppropriateTiming (). GetElapsedTimeFromBeat ( NoteRowToBeat ( m_iStartPlayingAt ) ) - PREFSMAN -> m_EditRecordModeLeadIn ;
2014-07-24 19:45:17 -05:00
GAMESTATE -> UpdateSongPosition ( fSeconds , GetAppropriateTiming (), RageZeroTimer );
2011-03-17 01:43:45 -04:00
GAMESTATE -> m_bGameplayLeadIn . Set ( false );
2020-10-20 02:16:02 +09:00
2011-06-01 15:27:14 -04:00
if ( ! GAMESTATE -> m_bIsUsingStepTiming )
{
2013-01-23 14:51:18 -05:00
// Substitute the song timing for the step timing during
2015-07-11 00:43:37 -06:00
// preview if we're in song mode
2024-08-10 12:07:54 -04:00
backupStepTiming = GAMESTATE -> m_pCurSteps [ main_player_ ] -> m_Timing ;
GAMESTATE -> m_pCurSteps [ main_player_ ] -> m_Timing . Clear ();
2011-06-01 15:27:14 -04:00
}
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 ();
2024-08-10 12:07:54 -04:00
player_manager_ . SetupAutoplay ();
player_manager_ . ReloadNoteData ( m_NoteDataEdit );
2011-03-17 01:43:45 -04:00
2024-08-10 12:07:54 -04:00
if ( g_bEditorShowBGChangesPlay )
2011-03-17 01:43:45 -04:00
{
/* FirstBeat affects backgrounds, so commit changes to memory (not to disk)
* and recalc it. */
2024-08-10 12:07:54 -04:00
Steps * pSteps = GAMESTATE -> m_pCurSteps [ main_player_ ];
ASSERT ( pSteps != nullptr );
pSteps -> SetNoteData ( m_NoteDataEdit );
2011-07-05 15:04:24 -04:00
m_pSong -> ReCalculateRadarValuesAndLastSecond ();
2011-03-17 01:43:45 -04:00
2024-08-10 12:07:54 -04:00
// TODO: Background videos don't support seeking, when they do, make sure
// to load the appropriate part of the video.
2011-03-17 01:43:45 -04:00
m_Background . Unload ();
2024-08-10 12:07:54 -04:00
m_Background . LoadFromSong ( m_pSong );
2011-03-17 01:43:45 -04:00
m_Foreground . Unload ();
2024-08-10 12:07:54 -04:00
m_Foreground . LoadFromSong ( m_pSong );
2011-03-17 01:43:45 -04:00
}
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 );
2024-08-10 12:07:54 -04:00
player_manager_ . SetVisible ( em == STATE_PLAYING );
2011-03-17 01:43:45 -04:00
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 );
2015-02-28 06:25:02 -07:00
m_pSoundMusic -> Play ( false , & p );
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
}
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
2022-07-10 18:28:56 +03:00
int iStartRow = BeatToNoteRow ( std :: min ( fOriginalBeat , fDestinationBeat ) );
int iEndRow = BeatToNoteRow ( std :: 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 )
2022-07-10 18:28:56 +03:00
std :: swap ( m_NoteFieldEdit . m_iBeginMarker , m_NoteFieldEdit . m_iEndMarker );
2011-03-17 01:43:45 -04:00
}
}
2015-02-28 06:25:02 -07:00
m_soundChangeLine . Play ( true );
2011-03-17 01:43:45 -04:00
}
2012-02-10 19:49:53 -05:00
static LocalizedString NEW_KEYSOUND_FILE ( "ScreenEdit" , "Enter New Keysound File" );
2011-03-17 01:43:45 -04:00
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 );
2019-06-22 12:35:38 -07:00
if ( pSoundReader == nullptr )
2011-03-17 01:43:45 -04:00
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." );
2015-02-17 15:37:49 -07:00
static LocalizedString AUTOSAVE_SUCCESSFUL ( "ScreenEdit" , "Autosave successful." );
2015-10-02 16:26:59 -06:00
static LocalizedString SAVE_SUCCESS_NO_SM_SPLIT_TIMING ( "ScreenEdit" , "save_success_no_sm_split_timing" );
2011-03-17 01:43:45 -04:00
2012-05-21 21:42:06 -04:00
static LocalizedString ADD_NEW_MOD ( "ScreenEdit" , "Adding New Mod" );
static LocalizedString ADD_NEW_ATTACK ( "ScreenEdit" , "Adding New Attack" );
static LocalizedString EDIT_EXISTING_MOD ( "ScreenEdit" , "Edit Existing Mod" );
static LocalizedString EDIT_ATTACK_START ( "ScreenEdit" , "Edit Attack Start" );
static LocalizedString EDIT_ATTACK_LENGTH ( "ScreenEdit" , "Edit Attack Length" );
2011-03-17 01:43:45 -04:00
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 );
2022-07-10 18:28:56 +03:00
const std :: vector < int > & answers = ScreenMiniMenu :: s_viLastAnswers ;
2011-07-26 16:05:14 -04:00
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 );
}
2014-08-30 13:38:16 -06:00
else if ( SM == SM_BackFromArbitraryRemap )
{
HandleArbitraryRemapping ( ScreenTextEntry :: s_sLastAnswer );
}
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 );
}
2020-10-20 02:16:02 +09:00
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 );
}
2015-04-04 09:10:00 -06:00
else if ( SM == SM_BackFromTimingDataChangeInformation )
{
HandleTimingDataChangeChoice (( TimingDataChangeChoice ) ScreenMiniMenu :: s_iLastRowCode , ScreenMiniMenu :: s_viLastAnswers );
}
2011-05-07 19:18:03 -04:00
else if ( SM == SM_BackFromDifficultyMeterChange )
{
2021-02-15 20:36:51 +00:00
int i = StringToInt ( ScreenTextEntry :: s_sLastAnswer );
2011-05-07 19:18:03 -04:00
GAMESTATE -> m_pCurSteps [ PLAYER_1 ] -> SetMeter ( i );
SetDirty ( true );
}
2013-01-21 23:13:38 -05:00
else if ( SM == SM_BackFromBeat0Change && ! ScreenTextEntry :: s_bCancelledLast )
{
float fBeat0 = StringToFloat ( ScreenTextEntry :: s_sLastAnswer );
TimingData & timing = GetAppropriateTimingForUpdate ();
float old = timing . m_fBeat0OffsetInSeconds ;
timing . m_fBeat0OffsetInSeconds = fBeat0 ;
float delta = timing . m_fBeat0OffsetInSeconds - old ;
if ( GAMESTATE -> m_bIsUsingStepTiming )
{
GAMESTATE -> m_pCurSteps [ PLAYER_1 ] -> m_Attacks . UpdateStartTimes ( delta );
}
else
{
GAMESTATE -> m_pCurSong -> m_Attacks . UpdateStartTimes ( delta );
GAMESTATE -> m_pCurSong -> m_fMusicSampleStartSeconds += delta ;
}
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 )
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). AddSegment ( BPMSegment ( GetRow (), fBPM ) );
2011-09-15 03:28:58 +00:00
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 )
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). AddSegment ( StopSegment ( GetRow (), fStop ) );
2011-09-15 03:28:58 +00:00
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 )
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). AddSegment ( DelaySegment ( GetRow (), fDelay ) );
2011-09-15 03:28:58 +00:00
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
{
2021-02-15 20:36:51 +00: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 )
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). AddSegment ( TickcountSegment ( GetRow (), iTick ) );
2011-09-15 03:28:58 +00:00
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 )
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). AddSegment ( ComboSegment ( GetRow (), iCombo , iMiss ) );
2011-09-15 03:28:58 +00:00
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 ( "," , "_" );
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). 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
{
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). SetWarpAtBeat ( GetBeat (), fWarp );
2011-05-16 10:56:00 -04:00
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 );
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). SetSpeedPercentAtBeat ( GetBeat (), fNum );
2011-05-15 15:53:20 -04:00
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 )
{
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). SetSpeedWaitAtBeat ( GetBeat (), fDen );
2011-05-15 15:53:20 -04:00
}
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
{
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). 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
{
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). SetSpeedModeAtBeat ( GetBeat (), SpeedSegment :: UNIT_SECONDS );
2011-05-15 23:48:03 -04:00
}
2011-05-16 22:44:56 +07:00
else
{
2021-02-15 20:36:51 +00:00
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 ;
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). 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 );
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). SetScrollAtBeat ( GetBeat (), fNum );
2011-05-25 22:44:41 +07:00
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 );
2012-02-27 13:46:12 -05:00
if ( fFake >= 0 ) // allow 0 to kill a fake.
2011-05-16 11:30:39 -04:00
{
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). AddSegment ( FakeSegment ( GetRow (), fFake ) );
2011-05-16 11:30:39 -04:00
SetDirty ( true );
}
}
2015-03-02 18:44:01 -07:00
else if ( SM == SM_BackFromStepMusicChange && ! ScreenTextEntry :: s_bCancelledLast )
{
// Reload the music because it just changed. -Kyz
m_AutoKeysounds . FinishLoading ();
m_pSoundMusic = m_AutoKeysounds . GetSound ();
}
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 ];
2019-06-22 12:35:38 -07:00
GAMESTATE -> m_pCurCourse . Set ( nullptr );
2011-03-17 01:43:45 -04:00
if ( num != 0 )
{
const RString name = g_CourseMode . rows [ 0 ]. choices [ num ];
Course * pCourse = SONGMAN -> FindCourse ( name );
int iCourseEntryIndex = - 1 ;
2019-06-22 12:35:38 -07:00
int index = 0 ;
for ( CourseEntry const & i : pCourse -> m_vEntries )
2011-03-17 01:43:45 -04:00
{
2019-06-22 12:35:38 -07:00
if ( i . songID . ToSong () == GAMESTATE -> m_pCurSong . Get () )
iCourseEntryIndex = index ;
++ index ;
2011-03-17 01:43:45 -04:00
}
ASSERT ( iCourseEntryIndex != - 1 );
GAMESTATE -> m_pCurCourse . Set ( pCourse );
GAMESTATE -> m_iEditCourseEntryIndex . Set ( iCourseEntryIndex );
2019-06-22 12:35:38 -07:00
ASSERT ( GAMESTATE -> m_pCurCourse != nullptr );
2011-03-17 01:43:45 -04:00
}
}
2012-02-10 14:44:48 -05:00
else if ( SM == SM_BackFromKeysoundTrack )
{
2012-02-10 19:07:13 -05:00
const int track = ScreenMiniMenu :: s_iLastRowCode ;
2012-02-11 15:11:44 -05:00
const int tracks = m_NoteDataEdit . GetNumTracks ();
2012-02-10 19:07:13 -05:00
const int row = this -> GetRow ();
2012-02-11 15:11:44 -05:00
unsigned int sound = ScreenMiniMenu :: s_viLastAnswers [ track ];
2022-07-10 18:28:56 +03:00
std :: vector < RString > & kses = m_pSong -> m_vsKeysoundFile ;
2020-10-20 02:16:02 +09:00
2012-02-11 15:11:44 -05:00
if ( track < tracks )
2012-02-10 14:44:48 -05:00
{
2012-02-10 19:49:53 -05:00
if ( sound == kses . size ())
{
// create a new sound (filename), point it.
// if it's empty, make it an auto keysound.
ScreenTextEntry :: TextEntry ( SM_BackFromNewKeysound , NEW_KEYSOUND_FILE , "" , 64 );
return ;
}
2012-02-10 19:17:00 -05:00
const TapNote & oldNote = m_NoteDataEdit . GetTapNote ( track , row );
2012-02-10 19:49:53 -05:00
TapNote newNote = oldNote ; // need to lose the const. not feeling like casting.
2012-02-10 14:44:48 -05:00
if ( sound < kses . size ())
{
// set note at this row to use this keysound file.
// if it's empty, make it an auto keysound.
2012-02-10 19:17:00 -05:00
newNote . iKeysoundIndex = sound ;
2014-07-25 18:45:02 -05:00
if ( newNote . type == TapNoteType_Empty )
2012-02-10 19:49:53 -05:00
{
2014-07-25 18:45:02 -05:00
newNote . type = TapNoteType_AutoKeysound ; // keysounds need something non empty.
2012-02-10 19:49:53 -05:00
}
2012-02-10 14:44:48 -05:00
}
else // sound > kses.size()
{
// remove the sound. if it's an auto keysound, make it empty.
2012-02-10 19:07:13 -05:00
newNote . iKeysoundIndex = - 1 ;
2014-07-25 18:45:02 -05:00
if ( newNote . type == TapNoteType_AutoKeysound )
2012-02-10 19:49:53 -05:00
{
2014-07-25 18:45:02 -05:00
newNote . type = TapNoteType_Empty ; // autoKeysound with no sound is pointless.
2012-02-10 19:49:53 -05:00
}
2012-02-10 19:17:00 -05:00
}
m_NoteDataEdit . SetTapNote ( track , row , newNote );
2012-02-10 14:44:48 -05:00
}
2012-02-11 15:11:44 -05:00
else if ( track == tracks )
2012-02-10 14:44:48 -05:00
{
2012-02-11 15:11:44 -05:00
kses . erase ( kses . begin () + sound );
// TODO: Make the following a part of NoteData?
for ( int t = 0 ; t < tracks ; ++ t )
{
FOREACH_NONEMPTY_ROW_IN_TRACK ( m_NoteDataEdit , t , r )
{
const TapNote & oldNote = m_NoteDataEdit . GetTapNote ( t , r );
TapNote newNote = oldNote ; // need to lose the const. not feeling like casting.
if ( newNote . iKeysoundIndex == static_cast < int > ( sound ))
{
newNote . iKeysoundIndex = - 1 ;
2014-07-25 18:45:02 -05:00
if ( newNote . type == TapNoteType_AutoKeysound )
newNote . type = TapNoteType_Empty ;
2012-02-11 15:11:44 -05:00
}
else if ( newNote . iKeysoundIndex > static_cast < int > ( sound ))
newNote . iKeysoundIndex -- ;
2020-10-20 02:16:02 +09:00
2012-02-11 15:11:44 -05:00
m_NoteDataEdit . SetTapNote ( t , r , newNote );
}
}
2012-02-10 14:44:48 -05:00
}
SetDirty ( true );
}
2012-02-10 19:49:53 -05:00
else if ( SM == SM_BackFromNewKeysound && ! ScreenTextEntry :: s_bCancelledLast )
{
RString answer = ScreenTextEntry :: s_sLastAnswer ;
const int track = ScreenMiniMenu :: s_iLastRowCode ; // still keeps the same value.
const int row = this -> GetRow ();
const TapNote & oldNote = m_NoteDataEdit . GetTapNote ( track , row );
TapNote newNote = oldNote ; // need to lose the const. not feeling like casting.
2022-07-10 18:28:56 +03:00
std :: vector < RString > & kses = m_pSong -> m_vsKeysoundFile ;
2012-02-11 14:52:41 -05:00
unsigned pos = find ( kses . begin (), kses . end (), answer ) - kses . begin ();
if ( pos == kses . size ())
{
newNote . iKeysoundIndex = kses . size ();
kses . push_back ( answer );
}
else
{
newNote . iKeysoundIndex = pos ;
}
2014-07-25 18:45:02 -05:00
if ( newNote . type == TapNoteType_Empty )
newNote . type = TapNoteType_AutoKeysound ; // keysounds need something non empty.
2012-02-10 19:49:53 -05:00
m_NoteDataEdit . SetTapNote ( track , row , newNote );
SetDirty ( true );
}
2011-03-17 01:43:45 -04:00
else if ( SM == SM_BackFromOptions )
{
// The options may have changed the note skin.
m_NoteFieldRecord . CacheAllUsedNoteSkins ();
2024-08-10 12:07:54 -04:00
player_manager_ . CacheAllUsedNoteSkins ();
2011-03-17 01:43:45 -04:00
// 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 ] );
2014-12-09 21:59:01 -07:00
SCREENMAN -> AddNewScreenToTop ( SET_MOD_SCREEN , SM_BackFromInsertTapAttackPlayerOptions );
2011-03-17 01:43:45 -04:00
}
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 (
2020-10-20 02:16:02 +09:00
TapNoteType_Attack ,
2014-07-25 18:45:02 -05:00
TapNoteSubType_Invalid ,
2020-10-20 02:16:02 +09:00
TapNoteSource_Original ,
2011-03-17 01:43:45 -04:00
sMods ,
2020-10-20 02:16:02 +09:00
g_fLastInsertAttackDurationSeconds ,
2011-03-17 01:43:45 -04:00
- 1 );
tn . pn = m_InputPlayerNumber ;
SetDirty ( true );
SaveUndo ();
m_NoteDataEdit . SetTapNote ( g_iLastInsertTapAttackTrack , row , tn );
CheckNumberOfNotesAndUndo ();
}
2012-05-21 21:42:06 -04:00
else if ( SM == SM_BackFromEditingAttackStart && ! ScreenTextEntry :: s_bCancelledLast )
{
float time = StringToFloat ( ScreenTextEntry :: s_sLastAnswer );
2020-10-20 02:16:02 +09:00
AttackArray & attacks =
2012-05-21 21:42:06 -04:00
( GAMESTATE -> m_bIsUsingStepTiming ? m_pSteps -> m_Attacks : m_pSong -> m_Attacks );
Attack & attack = attacks [ attackInProcess ];
attack . fStartSecond = time ;
SetDirty ( true );
}
else if ( SM == SM_BackFromEditingAttackLength && ! ScreenTextEntry :: s_bCancelledLast )
{
float time = StringToFloat ( ScreenTextEntry :: s_sLastAnswer );
2020-10-20 02:16:02 +09:00
AttackArray & attacks =
2012-05-21 21:42:06 -04:00
( GAMESTATE -> m_bIsUsingStepTiming ? m_pSteps -> m_Attacks : m_pSong -> m_Attacks );
Attack & attack = attacks [ attackInProcess ];
attack . fSecsRemaining = time ;
SetDirty ( true );
}
else if ( SM == SM_BackFromAddingModToExistingAttack && ! ScreenTextEntry :: s_bCancelledLast )
{
RString mod = ScreenTextEntry :: s_sLastAnswer ;
Trim ( mod );
if ( mod . length () > 0 )
{
2020-10-20 02:16:02 +09:00
AttackArray & attacks =
2012-05-21 21:42:06 -04:00
( GAMESTATE -> m_bIsUsingStepTiming ? m_pSteps -> m_Attacks : m_pSong -> m_Attacks );
Attack & attack = attacks [ attackInProcess ];
attack . sModifiers += "," + mod ;
SetDirty ( true );
}
2020-10-20 02:16:02 +09:00
2012-05-21 21:42:06 -04:00
}
else if ( SM == SM_BackFromEditingModToExistingAttack && ! ScreenTextEntry :: s_bCancelledLast )
{
2020-10-20 02:16:02 +09:00
AttackArray & attacks =
2012-05-21 21:42:06 -04:00
( GAMESTATE -> m_bIsUsingStepTiming ? m_pSteps -> m_Attacks : m_pSong -> m_Attacks );
Attack & attack = attacks [ attackInProcess ];
2022-07-10 18:28:56 +03:00
std :: vector < RString > mods ;
2020-10-20 02:16:02 +09:00
split ( attack . sModifiers , "," , mods );
2012-05-21 21:42:06 -04:00
RString mod = ScreenTextEntry :: s_sLastAnswer ;
Trim ( mod );
if ( mod . length () > 0 )
{
mods [ modInProcess - 2 ] = mod ;
}
else
{
mods . erase ( mods . begin () + ( modInProcess - 2 ));
}
if ( mods . size () > 0 )
{
attack . sModifiers = join ( "," , mods );
}
else
{
attacks . erase ( attacks . begin () + attackInProcess );
}
SetDirty ( true );
}
else if ( SM == SM_BackFromInsertStepAttack )
{
unsigned option = ScreenMiniMenu :: s_iLastRowCode ;
2020-10-20 02:16:02 +09:00
AttackArray & attacks =
2012-05-21 21:42:06 -04:00
( GAMESTATE -> m_bIsUsingStepTiming ? m_pSteps -> m_Attacks : m_pSong -> m_Attacks );
Attack & attack = attacks [ attackInProcess ];
2022-07-10 18:28:56 +03:00
std :: vector < RString > mods ;
2012-05-21 21:42:06 -04:00
split ( attack . sModifiers , "," , mods );
modInProcess = option ;
if ( option == 0 ) // adjusting the starting time
{
ScreenTextEntry :: TextEntry ( SM_BackFromEditingAttackStart ,
EDIT_ATTACK_START ,
2019-06-22 12:35:38 -07:00
std :: to_string ( attack . fStartSecond ),
2012-05-21 21:42:06 -04:00
10 );
}
else if ( option == 1 ) // adjusting the length of the attack
{
ScreenTextEntry :: TextEntry ( SM_BackFromEditingAttackLength ,
EDIT_ATTACK_LENGTH ,
2019-06-22 12:35:38 -07:00
std :: to_string ( attack . fSecsRemaining ),
2012-05-21 21:42:06 -04:00
10 );
}
else if ( option >= 2 + mods . size ()) // adding a new mod
{
ScreenTextEntry :: TextEntry ( SM_BackFromAddingModToExistingAttack ,
ADD_NEW_MOD ,
"" ,
64 );
}
else // modifying existing mod.
{
ScreenTextEntry :: TextEntry ( SM_BackFromEditingModToExistingAttack ,
EDIT_EXISTING_MOD ,
mods [ option - 2 ],
64 );
}
}
else if ( SM == SM_BackFromAddingAttackToChart && ! ScreenTextEntry :: s_bCancelledLast )
{
RString mod = ScreenTextEntry :: s_sLastAnswer ;
Trim ( mod );
if ( mod . length () > 0 )
{
2020-10-20 02:16:02 +09:00
AttackArray & attacks =
2012-05-21 21:42:06 -04:00
( GAMESTATE -> m_bIsUsingStepTiming ? m_pSteps -> m_Attacks : m_pSong -> m_Attacks );
Attack attack ;
attack . fStartSecond = GetAppropriateTiming (). GetElapsedTimeFromBeat ( GetBeat ());
attack . fSecsRemaining = 5 ; // Users can change later.
attack . sModifiers = mod ;
attacks . push_back ( attack );
SetDirty ( true );
}
}
else if ( SM == SM_BackFromAttackAtTime )
{
int attackChoice = ScreenMiniMenu :: s_iLastRowCode ;
int attackDecision = ScreenMiniMenu :: s_viLastAnswers [ attackChoice ];
2013-01-21 22:53:12 -05:00
const TimingData & timing = GetAppropriateTiming ();
2012-05-21 21:42:06 -04:00
float startTime = timing . GetElapsedTimeFromBeat ( GetBeat ());
2020-10-20 02:16:02 +09:00
AttackArray & attacks =
2012-05-21 21:42:06 -04:00
( GAMESTATE -> m_bIsUsingStepTiming ? m_pSteps -> m_Attacks : m_pSong -> m_Attacks );
2022-07-10 18:28:56 +03:00
std :: vector < int > points = FindAllAttacksAtTime ( attacks , startTime );
2012-05-21 21:42:06 -04:00
if ( attackChoice == ( int ) points . size ())
{
// TODO: Add attack code.
ScreenTextEntry :: TextEntry ( SM_BackFromAddingAttackToChart ,
ADD_NEW_ATTACK ,
"" ,
64 );
}
else
{
attackInProcess = points [ attackChoice ];
if ( attackDecision == 1 ) // remove
{
attacks . erase ( attacks . begin () + attackInProcess );
SetDirty ( true );
}
else
{
Attack & attack = attacks [ attackInProcess ];
g_IndividualAttack . rows . clear ();
2020-10-20 02:16:02 +09:00
2012-05-21 21:42:06 -04:00
g_IndividualAttack . rows . push_back ( MenuRowDef ( 0 ,
"Starting Time" ,
true ,
EditMode_CourseMods ,
true ,
true ,
0 ,
2019-06-22 12:35:38 -07:00
nullptr ));
g_IndividualAttack . rows [ 0 ]. SetOneUnthemedChoice ( std :: to_string ( attack . fStartSecond ));
2012-05-21 21:42:06 -04:00
g_IndividualAttack . rows . push_back ( MenuRowDef ( 1 ,
"Secs Remaining" ,
true ,
EditMode_CourseMods ,
true ,
true ,
0 ,
2019-06-22 12:35:38 -07:00
nullptr ));
g_IndividualAttack . rows [ 1 ]. SetOneUnthemedChoice ( std :: to_string ( attack . fSecsRemaining ));
2022-07-10 18:28:56 +03:00
std :: vector < RString > mods ;
2012-05-21 21:42:06 -04:00
split ( attack . sModifiers , "," , mods );
for ( unsigned i = 0 ; i < mods . size (); ++ i )
{
unsigned col = i + 2 ;
g_IndividualAttack . rows . push_back ( MenuRowDef ( col ,
ssprintf ( "Attack %d" , i + 1 ),
true ,
EditMode_CourseMods ,
false ,
true ,
0 ,
2019-06-22 12:35:38 -07:00
nullptr ));
2012-05-21 21:42:06 -04:00
g_IndividualAttack . rows [ col ]. SetOneUnthemedChoice ( mods [ i ]. c_str ());
}
2020-10-20 02:16:02 +09:00
2012-05-21 21:42:06 -04:00
g_IndividualAttack . rows . push_back ( MenuRowDef ( mods . size () + 2 ,
"Add Mod" ,
true ,
EditMode_CourseMods ,
true ,
true ,
0 ,
2019-06-22 12:35:38 -07:00
nullptr ));
2020-10-20 02:16:02 +09:00
2012-05-21 21:42:06 -04:00
EditMiniMenu ( & g_IndividualAttack , SM_BackFromInsertStepAttack );
}
}
}
2011-06-24 19:32:46 -04:00
else if ( SM == SM_BackFromInsertStepAttack )
{
int iDurationChoice = ScreenMiniMenu :: s_viLastAnswers [ 0 ];
2013-01-21 22:53:12 -05:00
const TimingData & timing = GetAppropriateTiming ();
2011-06-24 19:32:46 -04:00
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 );
2020-10-20 02:16:02 +09:00
2011-06-24 19:32:46 -04:00
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 );
2020-10-20 02:16:02 +09:00
2011-07-12 22:27:14 -04:00
toEdit . Assign ( ModsLevel_Preferred , po );
2014-12-09 21:59:01 -07:00
SCREENMAN -> AddNewScreenToTop ( SET_MOD_SCREEN , SM_BackFromInsertStepAttackPlayerOptions );
2011-06-24 19:32:46 -04:00
}
2011-12-18 11:31:49 -05:00
SetDirty ( true );
2011-06-24 19:32:46 -04:00
}
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 ;
2020-10-20 02:16:02 +09:00
2011-05-13 10:07:41 -04:00
// TODO: Handle Song/Step Timing functions/switches here?
2011-03-17 01:43:45 -04:00
2013-01-23 14:51:18 -05:00
g_fLastInsertAttackPositionSeconds = m_pSteps -> GetTimingData () -> 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 );
2014-12-09 21:59:01 -07:00
SCREENMAN -> AddNewScreenToTop ( SET_MOD_SCREEN , SM_BackFromInsertCourseAttackPlayerOptions );
2011-03-17 01:43:45 -04:00
}
}
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 ();
2020-10-20 02:16:02 +09:00
2011-06-24 19:32:46 -04:00
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 );
}
}
2015-03-08 00:56:29 -07:00
else if ( SM == SM_ConfirmClearArea )
{
if ( ScreenPrompt :: s_LastAnswer == ANSWER_YES )
{
m_NoteDataEdit . ClearRange (
m_NoteFieldEdit . m_iBeginMarker , m_NoteFieldEdit . m_iEndMarker );
}
}
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 ();
2013-01-23 14:51:18 -05:00
m_pSteps -> m_Timing . Clear ();
2011-05-14 00:43:06 -05:00
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.
2015-02-27 10:36:17 -07:00
m_pSong -> RemoveAutosave ();
2011-03-17 01:43:45 -04:00
SCREENMAN -> SendMessageToTopScreen ( SM_DoExit );
return ;
case ANSWER_CANCEL :
break ; // do nothing
}
}
2015-10-02 16:26:59 -06:00
else if ( SM == SM_SaveSuccessful || SM == SM_SaveSuccessNoSM )
2011-03-17 01:43:45 -04:00
{
LOG -> Trace ( "Save successful." );
CopyToLastSave ();
SetDirty ( false );
SONGMAN -> Invalidate ( GAMESTATE -> m_pCurSong );
2015-10-02 16:26:59 -06:00
LocalizedString const * message = & SAVE_SUCCESSFUL ;
if ( SM == SM_SaveSuccessNoSM )
{
message = & SAVE_SUCCESS_NO_SM_SPLIT_TIMING ;
}
2011-03-17 01:43:45 -04:00
if ( m_CurrentAction == save_on_exit )
2015-10-02 16:26:59 -06:00
{
ScreenPrompt :: Prompt ( SM_DoExit , * message );
}
2011-03-17 01:43:45 -04:00
else
2015-10-02 16:26:59 -06:00
{
SCREENMAN -> SystemMessage ( * message );
}
2011-03-17 01:43:45 -04:00
}
2015-02-17 15:37:49 -07:00
else if ( SM == SM_AutoSaveSuccessful )
{
2015-02-27 10:36:17 -07:00
LOG -> Trace ( "AutoSave successful." );
2024-09-08 23:13:50 -07:00
m_next_autosave_time = RageTimer :: GetTimeSinceStartMicroseconds () + time_between_autosave ;
2015-02-17 15:37:49 -07:00
SCREENMAN -> SystemMessage ( AUTOSAVE_SUCCESSFUL );
}
2011-03-17 01:43:45 -04:00
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 */
2020-10-20 02:16:02 +09:00
2011-03-17 01:43:45 -04:00
// At this point, the last good song copy is in use.
Song * pSong = GAMESTATE -> m_pCurSong ;
2022-07-10 18:28:56 +03:00
const std :: vector < Steps *> & apSteps = pSong -> GetAllSteps ();
std :: vector < Steps *> apToDelete ;
2019-06-22 12:35:38 -07:00
for ( Steps * s : apSteps )
2011-03-17 01:43:45 -04:00
{
// If we're not on the same style, let it go.
2024-08-10 12:07:54 -04:00
if ( GAMESTATE -> m_pCurSteps [ main_player_ ] -> m_StepsType != s -> m_StepsType )
2011-03-17 01:43:45 -04:00
continue ;
// If autogenned, it isn't being saved.
2019-06-22 12:35:38 -07:00
if ( s -> IsAutogen () )
2011-03-17 01:43:45 -04:00
continue ;
// If the notedata has content, let it go.
2019-06-22 12:35:38 -07: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.
/*
2019-06-22 12:35:38 -07:00
if( !(s->GetSavedToDisk() )
2011-03-17 01:43:45 -04:00
continue;
*/
2019-06-22 12:35:38 -07:00
apToDelete . push_back ( s );
2011-03-17 01:43:45 -04:00
}
2019-06-22 12:35:38 -07:00
for ( Steps * pSteps : apToDelete )
2011-03-17 01:43:45 -04:00
{
pSong -> DeleteSteps ( pSteps );
if ( m_pSteps == pSteps )
2019-06-22 12:35:38 -07:00
m_pSteps = nullptr ;
2024-08-10 12:07:54 -04:00
if ( GAMESTATE -> m_pCurSteps [ main_player_ ]. Get () == pSteps )
GAMESTATE -> m_pCurSteps [ main_player_ ]. Set ( nullptr );
2011-03-17 01:43:45 -04:00
}
2020-10-20 02:16:02 +09:00
2011-03-17 01:43:45 -04:00
m_Out . StartTransitioning ( SM_GoToNextScreen );
}
else if ( SM == SM_GainFocus )
{
/* When another screen comes up, RageSounds takes over the sound timer. When we come
* back, put the timer back to where it was. */
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 );
}
2015-02-17 15:37:49 -07:00
void ScreenEdit :: SetDirty ( bool dirty )
{
2016-03-04 11:24:23 -07:00
if ( EDIT_MODE . GetValue () != EditMode_Full )
{
m_dirty = false ;
2024-09-08 23:13:50 -07:00
m_next_autosave_time = - 1000000 ;
2016-03-04 11:24:23 -07:00
return ;
}
2015-02-17 15:37:49 -07:00
if ( dirty )
{
if ( ! m_dirty )
{
2024-09-08 23:13:50 -07:00
m_next_autosave_time = RageTimer :: GetTimeSinceStartMicroseconds () + time_between_autosave ;
2015-02-17 15:37:49 -07:00
}
}
else
{
2024-09-08 23:13:50 -07:00
m_next_autosave_time = - 1000000 ;
2015-02-17 15:37:49 -07:00
}
m_dirty = dirty ;
}
void ScreenEdit :: PerformSave ( bool autosave )
{
// copy edit into current Steps
m_pSteps -> SetNoteData ( m_NoteDataEdit );
// 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 ();
2015-10-02 16:26:59 -06:00
// If one of the charts uses split timing, then it cannot be accurately
// saved in the .sm format. So saving the .sm is disabled.
bool uses_split = m_pSong -> AnyChartUsesSplitTiming ();
2015-02-17 15:37:49 -07:00
const ScreenMessage save_message = autosave ? SM_AutoSaveSuccessful
2015-10-02 16:26:59 -06:00
: ( uses_split ? SM_SaveSuccessNoSM : SM_SaveSuccessful );
2015-02-17 15:37:49 -07: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 ( save_message );
/* FIXME
RString s;
switch( c )
{
case save: s = "ScreenMemcardSaveEditsAfterSave"; break;
case save_on_exit: s = "ScreenMemcardSaveEditsAfterExit"; break;
default: FAIL_M(ssprintf("Invalid menu choice: %i", c));
}
SCREENMAN->AddNewScreenToTop( s );
*/
}
break ;
case EditMode_Full :
{
// This will recalculate radar values.
m_pSong -> Save ( autosave );
SCREENMAN -> ZeroNextUpdate ();
HandleScreenMessage ( save_message );
}
break ;
case EditMode_CourseMods :
case EditMode_Practice :
break ;
}
m_soundSave . Play ( true );
}
2011-03-17 01:43:45 -04:00
void ScreenEdit :: OnSnapModeChange ()
{
2015-02-28 06:25:02 -07:00
m_soundChangeSnap . Play ( true );
2011-03-17 01:43:45 -04:00
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 );
}
2012-10-16 21:05:27 -04:00
static void ChangeStepMeter ( const RString & sNew )
{
2021-02-15 20:36:51 +00:00
int diff = StringToInt ( sNew );
2022-07-10 18:28:56 +03:00
GAMESTATE -> m_pCurSteps [ PLAYER_1 ] -> SetMeter ( std :: max ( diff , 1 ));
2012-10-16 21:05:27 -04:00
}
2015-03-02 18:44:01 -07:00
static void ChangeStepMusic ( const RString & sNew )
{
Steps * pSteps = GAMESTATE -> m_pCurSteps [ PLAYER_1 ];
pSteps -> SetMusicFile ( sNew );
}
2011-03-17 01:43:45 -04:00
static void ChangeMainTitle ( const RString & sNew )
{
Song * pSong = GAMESTATE -> m_pCurSong ;
pSong -> m_sMainTitle = sNew ;
}
static void ChangeSubTitle ( const RString & sNew )
{
Song * pSong = GAMESTATE -> m_pCurSong ;
pSong -> m_sSubTitle = sNew ;
}
static void ChangeArtist ( const RString & sNew )
{
Song * pSong = GAMESTATE -> m_pCurSong ;
pSong -> m_sArtist = sNew ;
}
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 ;
}
2015-03-04 01:31:02 -07:00
static void ChangePreview ( const RString & sNew )
{
Song * pSong = GAMESTATE -> m_pCurSong ;
2015-03-11 18:55:06 -06:00
if ( ! sNew . empty ())
{
RString error ;
RageSoundReader * sample = RageSoundReader_FileReader :: OpenFile ( pSong -> GetPreviewMusicPath (), error );
2019-06-22 12:35:38 -07:00
if ( sample == nullptr )
2015-03-11 18:55:06 -06:00
{
LOG -> UserLog ( "Preview file" , pSong -> GetPreviewMusicPath (), "couldn't be opened: %s" , error . c_str () );
}
else
{
pSong -> m_fMusicSampleLengthSeconds = sample -> GetLength () / 1000.0f ;
pSong -> m_PreviewFile = sNew ;
delete sample ;
}
}
else
{
pSong -> m_PreviewFile = sNew ;
}
2015-03-04 01:31:02 -07:00
}
2011-03-17 01:43:45 -04:00
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-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 ));
}
2013-01-21 22:53:12 -05:00
const TimingData & ScreenEdit :: GetAppropriateTiming () const
2011-05-12 23:01:19 -04:00
{
2011-05-17 00:07:43 -04:00
if ( GAMESTATE -> m_bIsUsingStepTiming )
2011-05-12 23:01:19 -04:00
{
2013-01-23 14:51:18 -05:00
return * m_pSteps -> GetTimingData ();
2011-05-12 23:01:19 -04:00
}
return m_pSong -> m_SongTiming ;
}
2013-01-21 22:53:12 -05:00
TimingData & ScreenEdit :: GetAppropriateTimingForUpdate ()
{
if ( GAMESTATE -> m_bIsUsingStepTiming )
{
// Copy from song if there is no step timing
if ( m_pSteps -> m_Timing . empty () )
m_pSteps -> m_Timing = m_pSong -> m_SongTiming ;
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 ;
2013-01-23 14:51:18 -05:00
GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_Position . m_fSongBeat = m_pSteps -> GetTimingData () -> GetBeatFromElapsedTime ( m_pSong -> m_SongTiming . GetElapsedTimeFromBeat ( fBeat ));
2011-05-13 14:14:57 +07:00
}
else
{
GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> m_Position . m_fSongBeat = fBeat ;
2013-01-23 14:51:18 -05:00
GAMESTATE -> m_Position . m_fSongBeat = m_pSong -> m_SongTiming . GetBeatFromElapsedTime ( m_pSteps -> GetTimingData () -> GetElapsedTimeFromBeat ( fBeat ));
2011-05-13 14:14:57 +07:00
}
}
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 ()
{
2012-01-11 22:50:55 -05:00
int row = GetRow ();
2013-01-21 22:53:12 -05:00
const TimingData & pTime = GetAppropriateTiming ();
2012-01-11 22:50:55 -05:00
bool bHasSpeedOnThisRow = pTime . GetSpeedSegmentAtRow ( row ) -> GetRow () == row ;
2011-12-30 15:17:28 -08:00
// bool bIsSelecting = ( (m_NoteFieldEdit.m_iEndMarker != -1) && (m_NoteFieldEdit.m_iBeginMarker != -1) );
2011-12-21 13:48:31 -08:00
2011-09-15 03:28:58 +00:00
2019-06-22 12:35:38 -07:00
g_TimingDataInformation . rows [ beat_0_offset ]. SetOneUnthemedChoice ( std :: to_string ( pTime . m_fBeat0OffsetInSeconds ) );
g_TimingDataInformation . rows [ bpm ]. SetOneUnthemedChoice ( std :: to_string ( pTime . GetBPMAtRow ( row ) ) );
g_TimingDataInformation . rows [ stop ]. SetOneUnthemedChoice ( std :: to_string ( pTime . GetStopAtRow ( row ) ) ) ;
g_TimingDataInformation . rows [ delay ]. SetOneUnthemedChoice ( std :: to_string ( pTime . GetDelayAtRow ( row ) ) );
2011-09-15 03:28:58 +00:00
2012-01-11 22:50:55 -05:00
g_TimingDataInformation . rows [ label ]. SetOneUnthemedChoice ( pTime . GetLabelAtRow ( row ). c_str () );
g_TimingDataInformation . rows [ tickcount ]. SetOneUnthemedChoice ( ssprintf ( "%d" , pTime . GetTickcountAtRow ( row ) ) );
2011-07-09 02:28:15 -04:00
g_TimingDataInformation . rows [ combo ]. SetOneUnthemedChoice ( ssprintf ( "%d / %d" ,
2012-01-11 22:50:55 -05:00
pTime . GetComboAtRow ( row ),
pTime . GetMissComboAtRow ( row ) ) );
2019-06-22 12:35:38 -07:00
g_TimingDataInformation . rows [ warp ]. SetOneUnthemedChoice ( std :: to_string ( pTime . GetWarpAtRow ( row ) ) );
g_TimingDataInformation . rows [ speed_percent ]. SetOneUnthemedChoice ( bHasSpeedOnThisRow ? std :: to_string ( pTime . GetSpeedPercentAtRow ( row ) ) : "---" );
g_TimingDataInformation . rows [ speed_wait ]. SetOneUnthemedChoice ( bHasSpeedOnThisRow ? std :: to_string ( pTime . GetSpeedWaitAtRow ( row ) ) : "---" );
2011-09-15 03:28:58 +00:00
2012-01-11 22:50:55 -05:00
RString starting = ( pTime . GetSpeedModeAtRow ( row ) == 1 ? "Seconds" : "Beats" );
2011-05-15 23:48:03 -04:00
g_TimingDataInformation . rows [ speed_mode ]. SetOneUnthemedChoice ( starting . c_str () );
2011-09-15 03:28:58 +00:00
2019-06-22 12:35:38 -07:00
g_TimingDataInformation . rows [ scroll ]. SetOneUnthemedChoice ( std :: to_string ( pTime . GetScrollAtRow ( row ) ) );
g_TimingDataInformation . rows [ fake ]. SetOneUnthemedChoice ( std :: to_string ( pTime . GetFakeAtRow ( row ) ) );
2011-09-15 03:28:58 +00:00
2011-12-30 15:17:28 -08:00
// g_TimingDataInformation.rows[speed_percent].bEnabled = !bIsSelecting;
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 );
}
2015-04-04 09:10:00 -06:00
void ScreenEdit :: DisplayTimingChangeMenu ()
{
int row = GetRow ();
EditMiniMenu ( & g_TimingDataChangeInformation , SM_BackFromTimingDataChangeInformation );
}
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?" );
2014-12-09 15:37:06 -07:00
int ScreenEdit :: GetSongOrNotesEnd ()
{
2022-07-10 18:28:56 +03:00
return std :: max ( m_iStartPlayingAt , std :: max ( m_NoteDataEdit . GetLastRow (),
2014-12-09 15:37:06 -07:00
BeatToNoteRow ( m_pSteps -> GetTimingData () -> GetBeatFromElapsedTime (
GAMESTATE -> m_pCurSong -> m_fMusicLengthSeconds ))));
}
2022-07-10 18:28:56 +03:00
void ScreenEdit :: HandleMainMenuChoice ( MainMenuChoice c , const std :: vector < int > & iAnswers )
2011-03-17 01:43:45 -04:00
{
2013-01-23 14:51:18 -05:00
GAMESTATE -> SetProcessedTimingData ( m_pSteps -> GetTimingData ());
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 ;
2014-12-09 15:37:06 -07:00
m_iStopPlayingAt = GetSongOrNotesEnd ();
2011-03-17 01:43:45 -04:00
TransitionEditState ( STATE_PLAYING );
}
break ;
case play_selection_start_to_end :
{
m_iStartPlayingAt = m_NoteFieldEdit . m_iBeginMarker ;
2022-07-10 18:28:56 +03:00
m_iStopPlayingAt = std :: max ( m_iStartPlayingAt , m_NoteDataEdit . GetLastRow () );
2011-03-17 01:43:45 -04:00
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 );
2014-12-09 15:37:06 -07:00
m_iStopPlayingAt = GetSongOrNotesEnd ();
2011-03-17 01:43:45 -04:00
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 ;
2015-02-28 06:25:02 -07:00
m_soundMarker . Play ( true );
2011-03-17 01:43:45 -04:00
}
}
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 ;
2015-02-28 06:25:02 -07:00
m_soundMarker . Play ( true );
2011-03-17 01:43:45 -04:00
}
}
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 ();
2019-06-22 12:35:38 -07:00
g_StepsInformation . rows [ step_min_bpm ]. SetOneUnthemedChoice ( std :: to_string ( pSteps -> GetMinBPM ()));
g_StepsInformation . rows [ step_max_bpm ]. SetOneUnthemedChoice ( std :: to_string ( pSteps -> GetMaxBPM ()));
2015-03-02 18:44:01 -07:00
g_StepsInformation . rows [ step_music ]. bEnabled = ( EDIT_MODE . GetValue () >= EditMode_Full );
g_StepsInformation . rows [ step_music ]. SetOneUnthemedChoice ( pSteps -> GetMusicFile () );
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 )
{
2022-07-10 18:28:56 +03:00
std :: pair < int , int > tmp = m_NoteDataEdit . GetNumTapNotesTwoPlayer ();
2011-07-13 16:07:33 -04:00
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 ()) );
}
2015-03-23 11:35:30 -06:00
RadarValues radar ;
radar . Zero ();
NoteDataUtil :: CalculateRadarValues ( m_NoteDataEdit , fMusicSeconds , radar );
g_StepsData . rows [ stream ]. SetOneUnthemedChoice ( ssprintf ( "%.2f" , radar [ RadarCategory_Stream ]));
g_StepsData . rows [ voltage ]. SetOneUnthemedChoice ( ssprintf ( "%.2f" , radar [ RadarCategory_Voltage ]));
g_StepsData . rows [ air ]. SetOneUnthemedChoice ( ssprintf ( "%.2f" , radar [ RadarCategory_Air ]));
g_StepsData . rows [ freeze ]. SetOneUnthemedChoice ( ssprintf ( "%.2f" , radar [ RadarCategory_Freeze ]));
g_StepsData . rows [ chaos ]. SetOneUnthemedChoice ( ssprintf ( "%.2f" , radar [ RadarCategory_Chaos ]));
2011-07-07 17:52:30 -04:00
EditMiniMenu ( & g_StepsData , SM_BackFromStepsData , SM_None );
break ;
}
2011-03-17 01:43:45 -04:00
case save :
case save_on_exit :
2015-02-17 15:37:49 -07:00
m_CurrentAction = c ;
PerformSave ( false );
2011-03-17 01:43:45 -04:00
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 :
2014-12-09 21:59:01 -07:00
SCREENMAN -> AddNewScreenToTop ( OPTIONS_SCREEN , SM_BackFromOptions );
2011-03-17 01:43:45 -04:00
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 );
2015-03-04 01:31:02 -07:00
g_SongInformation . rows [ preview ]. SetOneUnthemedChoice ( pSong -> m_PreviewFile );
2011-03-17 01:43:45 -04:00
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 );
2019-06-22 12:35:38 -07:00
g_SongInformation . rows [ last_second_hint ]. SetOneUnthemedChoice ( std :: to_string ( pSong -> GetSpecifiedLastSecond ()) );
g_SongInformation . rows [ preview_start ]. SetOneUnthemedChoice ( std :: to_string ( pSong -> m_fMusicSampleStartSeconds ) );
g_SongInformation . rows [ preview_length ]. SetOneUnthemedChoice ( std :: to_string ( pSong -> m_fMusicSampleLengthSeconds ) );
2011-04-05 22:40:33 -04:00
g_SongInformation . rows [ display_bpm ]. iDefaultChoice = pSong -> m_DisplayBPMType ;
2019-06-22 12:35:38 -07:00
g_SongInformation . rows [ min_bpm ]. SetOneUnthemedChoice ( std :: to_string ( pSong -> m_fSpecifiedBPMMin ) );
g_SongInformation . rows [ max_bpm ]. SetOneUnthemedChoice ( std :: to_string ( 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 ;
2020-10-20 02:16:02 +09:00
2011-03-17 01:43:45 -04:00
case play_preview_music :
PlayPreviewMusic ();
break ;
case exit :
switch ( EDIT_MODE . GetValue () )
{
DEFAULT_FAIL ( EDIT_MODE . GetValue () );
case EditMode_Full :
case EditMode_Home :
if ( IsDirty () )
ScreenPrompt :: Prompt ( SM_DoSaveAndExit , SAVE_CHANGES_BEFORE_EXITING , PROMPT_YES_NO_CANCEL , ANSWER_CANCEL );
else
SCREENMAN -> SendMessageToTopScreen ( SM_DoExit );
break ;
case EditMode_Practice :
case EditMode_CourseMods :
SCREENMAN -> SendMessageToTopScreen ( SM_DoExit );
break ;
}
break ;
};
2019-06-22 12:35:38 -07:00
GAMESTATE -> SetProcessedTimingData ( nullptr );
2011-03-17 01:43:45 -04:00
}
2014-08-30 13:38:16 -06:00
static LocalizedString ENTER_ARBITRARY_MAPPING ( "ScreenEdit" , "Enter the new track mapping." );
2014-08-31 19:46:29 -06:00
static LocalizedString TOO_MANY_TRACKS ( "ScreenEdit" , "Too many tracks specified." );
static LocalizedString NOT_A_TRACK ( "ScreenEdit" , "'%s' is not a track id." );
static LocalizedString OUT_OF_RANGE_ID ( "ScreenEdit" , "Entry %d, '%d', is out of range 1 to %d." );
2015-03-08 00:56:29 -07:00
static LocalizedString CONFIRM_CLEAR ( "ScreenEdit" , "Are you sure you want to clear %d notes?" );
2014-08-31 19:46:29 -06:00
2014-08-30 13:38:16 -06:00
static bool ConvertMappingInputToMapping ( RString const & mapstr , int * mapping , RString & error )
{
2022-07-10 18:28:56 +03:00
std :: vector < RString > mapping_input ;
2014-08-30 13:38:16 -06:00
split ( mapstr , "," , mapping_input );
2024-10-01 00:43:07 -07:00
size_t tracks_for_type = GAMEMAN -> GetStepsTypeInfo ( GAMESTATE -> m_pCurSteps [ 0 ] -> m_StepsType ). iNumTracks ;
2014-08-30 13:38:16 -06:00
if ( mapping_input . size () > tracks_for_type )
{
2014-08-31 19:46:29 -06:00
error = TOO_MANY_TRACKS ;
2014-08-30 13:38:16 -06:00
return false ;
}
// mapping_input.size() < tracks_for_type is not checked because
// unspecified tracks are mapped directly. -Kyz
2024-10-01 00:43:07 -07:00
size_t track = 0 ;
2014-08-30 13:38:16 -06:00
// track will be used for filling in the unspecified part of the mapping.
for (; track < mapping_input . size (); ++ track )
{
2014-08-31 19:46:29 -06:00
if ( mapping_input [ track ]. empty () || mapping_input [ track ] == " " )
2014-08-30 13:38:16 -06:00
{
2014-08-31 19:46:29 -06:00
// This allows blank entries to mean "pass through".
mapping [ track ] = track + 1 ;
2014-08-30 13:38:16 -06:00
}
else if ( ! ( mapping_input [ track ] >> mapping [ track ]))
{
2014-08-31 19:46:29 -06:00
error = ssprintf ( NOT_A_TRACK . GetValue (), mapping_input [ track ]. c_str ());
2014-08-30 13:38:16 -06:00
return false ;
}
2014-09-07 22:56:50 -06:00
if ( mapping [ track ] < 1 || mapping [ track ] > static_cast < int > ( tracks_for_type ))
2014-08-30 13:38:16 -06:00
{
2014-08-31 19:46:29 -06:00
error = ssprintf ( OUT_OF_RANGE_ID . GetValue (), track + 1 , mapping [ track ], tracks_for_type );
2014-08-30 13:38:16 -06:00
return false ;
}
2014-08-31 19:46:29 -06:00
// Simpler for the user if they input track ids starting at 1.
-- mapping [ track ];
2014-08-30 13:38:16 -06:00
}
for (; track < tracks_for_type ; ++ track )
{
mapping [ track ] = track ;
}
return true ;
}
static bool ArbitraryRemapValidate ( const RString & answer , RString & error_out )
{
int mapping [ MAX_NOTE_TRACKS ];
return ConvertMappingInputToMapping ( answer , mapping , error_out );
}
void ScreenEdit :: HandleArbitraryRemapping ( RString const & mapstr )
{
const NoteData OldClipboard ( m_Clipboard );
HandleAlterMenuChoice ( cut , false );
int mapping [ MAX_NOTE_TRACKS ];
RString error ;
// error is actually reported by the validate function, and unused here.
if ( ConvertMappingInputToMapping ( mapstr , mapping , error ))
{
NoteDataUtil :: ArbitraryRemap ( m_Clipboard , mapping );
}
HandleAreaMenuChoice ( paste_at_begin_marker , false );
m_Clipboard = OldClipboard ;
}
2022-07-10 18:28:56 +03:00
void ScreenEdit :: HandleAlterMenuChoice ( AlterMenuChoice c , const std :: vector < int > & answers , bool allow_undo , bool prompt_clear )
2011-06-10 03:04:47 -04:00
{
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!" );
2020-10-20 02:16:02 +09:00
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 ;
}
2020-10-20 02:16:02 +09:00
2011-06-10 03:04:47 -04:00
if ( bSaveUndo )
SetDirty ( true );
2020-10-20 02:16:02 +09:00
2011-06-10 03:04:47 -04:00
/* 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 */
2015-04-20 07:47:26 -06:00
if ( ! allow_undo )
2011-06-10 03:04:47 -04:00
bSaveUndo = false ;
2020-10-20 02:16:02 +09:00
2011-06-10 03:04:47 -04:00
if ( bSaveUndo )
SaveUndo ();
2020-10-20 02:16:02 +09:00
2011-06-10 03:04:47 -04:00
switch ( c )
{
case cut :
{
2015-04-20 07:47:26 -06:00
HandleAlterMenuChoice ( copy , false , false );
HandleAlterMenuChoice ( clear , false , false );
2011-06-10 03:04:47 -04:00
}
break ;
case copy :
{
2020-10-20 02:16:02 +09: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 ;
case clear :
{
2015-03-08 00:56:29 -07:00
int note_count = m_NoteDataEdit . GetNumTapNotesNoTiming (
m_NoteFieldEdit . m_iBeginMarker , m_NoteFieldEdit . m_iEndMarker );
2015-04-20 07:47:26 -06:00
if ( note_count >= PREFSMAN -> m_EditClearPromptThreshold && prompt_clear )
2015-03-08 00:56:29 -07:00
{
ScreenPrompt :: Prompt ( SM_ConfirmClearArea , ssprintf ( CONFIRM_CLEAR . GetValue (), note_count ), PROMPT_YES_NO );
}
else
{
m_NoteDataEdit . ClearRange (
m_NoteFieldEdit . m_iBeginMarker , m_NoteFieldEdit . m_iEndMarker );
}
2011-06-10 03:04:47 -04:00
}
break ;
case quantize :
{
2015-04-20 07:47:26 -06:00
NoteType nt = ( NoteType ) answers [ c ];
2011-06-10 03:04:47 -04:00
NoteDataUtil :: SnapToNearestNoteType ( m_NoteDataEdit , nt , nt ,
m_NoteFieldEdit . m_iBeginMarker ,
m_NoteFieldEdit . m_iEndMarker );
break ;
}
case turn :
{
const NoteData OldClipboard ( m_Clipboard );
2013-08-12 20:47:07 -04:00
HandleAlterMenuChoice ( cut , false );
2020-10-20 02:16:02 +09:00
2014-12-07 01:53:17 -07:00
StepsType st = GAMESTATE -> GetCurrentStyle ( GAMESTATE -> GetMasterPlayerNumber ()) -> m_StepsType ;
2015-04-20 07:47:26 -06:00
TurnType tt = ( TurnType ) answers [ c ];
2011-06-10 03:04:47 -04:00
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 ;
2024-03-06 13:30:32 -08:00
case lrmirror : NoteDataUtil :: Turn ( m_Clipboard , st , NoteDataUtil :: lrmirror ); break ;
case udmirror : NoteDataUtil :: Turn ( m_Clipboard , st , NoteDataUtil :: udmirror ); 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 ;
2022-06-13 18:20:52 -05:00
case hyper_shuffle : NoteDataUtil :: Turn ( m_Clipboard , st , NoteDataUtil :: hyper_shuffle ); break ;
2011-06-10 03:04:47 -04:00
}
2020-10-20 02:16:02 +09:00
2013-08-12 20:47:07 -04:00
HandleAreaMenuChoice ( paste_at_begin_marker , false );
2011-06-10 03:04:47 -04:00
m_Clipboard = OldClipboard ;
}
break ;
case transform :
{
int iBeginRow = m_NoteFieldEdit . m_iBeginMarker ;
int iEndRow = m_NoteFieldEdit . m_iEndMarker ;
2015-04-20 07:47:26 -06:00
TransformType tt = ( TransformType ) answers [ c ];
2014-12-07 01:53:17 -07:00
StepsType st = GAMESTATE -> GetCurrentStyle ( GAMESTATE -> GetMasterPlayerNumber ()) -> m_StepsType ;
2020-10-20 02:16:02 +09:00
2011-06-10 03:04:47 -04:00
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 ;
}
2020-10-20 02:16:02 +09:00
2011-06-10 03:04:47 -04:00
// bake in the additions
NoteDataUtil :: ConvertAdditionsToRegular ( m_NoteDataEdit );
break ;
}
case alter :
{
const NoteData OldClipboard ( m_Clipboard );
2013-08-12 20:47:07 -04:00
HandleAlterMenuChoice ( cut , false );
2020-10-20 02:16:02 +09:00
2015-04-20 07:47:26 -06:00
AlterType at = ( AlterType ) answers [ c ];
2011-06-10 03:04:47 -04:00
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 ;
2014-08-30 00:47:07 -06:00
case swap_up_down : NoteDataUtil :: SwapUpDown ( m_Clipboard , GAMESTATE -> m_pCurSteps [ 0 ] -> m_StepsType ); break ;
2014-08-30 13:38:16 -06:00
case arbitrary_remap :
ScreenTextEntry :: TextEntry (
SM_BackFromArbitraryRemap , ENTER_ARBITRARY_MAPPING ,
2014-08-31 19:46:29 -06:00
"1, 2, 3, 4" , MAX_NOTE_TRACKS * 4 ,
2014-08-30 13:38:16 -06:00
// 2 chars for digit, one for comma, one for space.
ArbitraryRemapValidate
);
break ;
2011-06-10 03:04:47 -04:00
}
2020-10-20 02:16:02 +09:00
2013-08-12 20:47:07 -04:00
HandleAreaMenuChoice ( paste_at_begin_marker , false );
2011-06-10 03:04:47 -04:00
m_Clipboard = OldClipboard ;
break ;
}
case tempo :
{
// This affects all steps.
2022-12-23 12:34:02 -07:00
const TempoType tt = static_cast < TempoType > ( answers [ c ]);
2011-06-10 03:04:47 -04:00
float fScale = - 1 ;
2020-10-20 02:16:02 +09:00
2022-11-08 06:59:56 -07:00
switch ( tt )
2011-06-10 03:04:47 -04:00
{
2022-11-08 06:59:56 -07:00
DEFAULT_FAIL ( tt );
2011-06-10 03:04:47 -04:00
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 ;
}
2020-10-20 02:16:02 +09:00
2011-06-10 03:04:47 -04:00
int iStartIndex = m_NoteFieldEdit . m_iBeginMarker ;
int iEndIndex = m_NoteFieldEdit . m_iEndMarker ;
2023-04-19 14:22:59 +02:00
int iNewEndIndex = iEndIndex + std :: lrint ( ( iEndIndex - iStartIndex ) * ( fScale - 1 ) );
2020-10-20 02:16:02 +09:00
2011-06-10 03:04:47 -04:00
// scale currently editing notes
NoteDataUtil :: ScaleRegion ( m_NoteDataEdit , fScale , iStartIndex , iEndIndex );
2020-10-20 02:16:02 +09:00
2011-06-10 03:04:47 -04:00
// scale timing data
2020-10-20 02:16:02 +09:00
GetAppropriateTimingForUpdate (). ScaleRegion ( fScale ,
m_NoteFieldEdit . m_iBeginMarker ,
2011-06-10 03:04:47 -04:00
m_NoteFieldEdit . m_iEndMarker , true );
2020-10-20 02:16:02 +09:00
2011-06-10 03:04:47 -04:00
m_NoteFieldEdit . m_iEndMarker = iNewEndIndex ;
break ;
2020-10-20 02:16:02 +09:00
2011-06-10 03:04:47 -04:00
}
2020-10-20 02:16:02 +09:00
2011-06-10 03:04:47 -04:00
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 ) );
2020-10-20 02:16:02 +09:00
2011-06-10 16:43:38 -04:00
// 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 ;
2020-10-20 02:16:02 +09:00
2011-06-10 16:43:38 -04:00
// be sure not to clobber the row at the start - a row at the end
// can be dropped safely, though
2020-10-20 02:16:02 +09:00
NoteDataUtil :: DeleteRows ( m_NoteDataEdit ,
2011-06-10 16:43:38 -04:00
m_NoteFieldEdit . m_iBeginMarker + 1 ,
m_NoteFieldEdit . m_iEndMarker - m_NoteFieldEdit . m_iBeginMarker
);
2013-08-30 14:43:14 -04:00
// For TimingData, it makes more sense not to offset by a row
GetAppropriateTimingForUpdate (). DeleteRows ( m_NoteFieldEdit . m_iBeginMarker ,
2011-06-10 16:43:38 -04:00
m_NoteFieldEdit . m_iEndMarker - m_NoteFieldEdit . m_iBeginMarker );
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). SetStopAtRow ( m_NoteFieldEdit . m_iBeginMarker , fStopLength );
2011-06-10 16:43:38 -04:00
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 ) );
2020-10-20 02:16:02 +09:00
2011-06-10 17:03:53 -04:00
// 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 ;
2020-10-20 02:16:02 +09:00
NoteDataUtil :: DeleteRows ( m_NoteDataEdit ,
2011-06-10 17:03:53 -04:00
m_NoteFieldEdit . m_iBeginMarker ,
m_NoteFieldEdit . m_iEndMarker - m_NoteFieldEdit . m_iBeginMarker
);
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). DeleteRows ( m_NoteFieldEdit . m_iBeginMarker ,
2011-06-10 17:03:53 -04:00
m_NoteFieldEdit . m_iEndMarker - m_NoteFieldEdit . m_iBeginMarker );
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). SetDelayAtRow ( m_NoteFieldEdit . m_iBeginMarker , fStopLength );
2011-06-10 17:03:53 -04:00
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 ;
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). SetWarpAtBeat ( startBeat , lengthBeat );
2011-06-10 16:43:38 -04:00
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 );
2013-01-21 22:53:12 -05:00
const TimingData & timing = GetAppropriateTiming ();
2011-07-07 21:41:08 -04:00
float & start = g_fLastInsertAttackPositionSeconds ;
float & length = g_fLastInsertAttackDurationSeconds ;
start = timing . GetElapsedTimeFromBeat ( startBeat );
length = timing . GetElapsedTimeFromBeat ( endBeat ) - start ;
2020-10-20 02:16:02 +09:00
2011-07-07 21:41:08 -04:00
AttackArray & attacks = GAMESTATE -> m_bIsUsingStepTiming ?
m_pSteps -> m_Attacks : m_pSong -> m_Attacks ;
int iAttack = FindAttackAtTime ( attacks , start );
2020-10-20 02:16:02 +09:00
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 );
2020-10-20 02:16:02 +09:00
2011-07-12 22:27:14 -04:00
toEdit . Assign ( ModsLevel_Preferred , po );
2014-12-09 21:59:01 -07:00
SCREENMAN -> AddNewScreenToTop ( SET_MOD_SCREEN , SM_BackFromInsertStepAttackPlayerOptions );
2011-07-07 21:41:08 -04:00
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 );
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). 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 );
2014-07-25 18:45:02 -05:00
if ( tn . type != TapNoteType_Empty )
2011-07-04 17:30:36 -04:00
{
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 );
2014-07-25 18:45:02 -05:00
if ( tn . type != TapNoteType_Empty && tn . pn == oPN )
2011-07-04 18:15:21 -04:00
{
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
}
2020-10-20 02:16:02 +09:00
2011-03-17 01:43:45 -04:00
}
2022-07-10 18:28:56 +03:00
void ScreenEdit :: HandleAreaMenuChoice ( AreaMenuChoice c , const std :: vector < int > & iAnswers , bool bAllowUndo )
2011-03-17 01:43:45 -04:00
{
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 ;
2020-10-20 02:16:02 +09: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 (),
2015-04-04 09:10:00 -06:00
GetRowsFromAnswers ( c , iAnswers ));
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 (),
2015-04-04 09:10:00 -06:00
GetRowsFromAnswers ( c , iAnswers ));
2011-03-17 01:43:45 -04:00
break ;
case shift_pauses_forward :
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). InsertRows ( GetRow (),
2015-04-04 09:10:00 -06:00
GetRowsFromAnswers ( c , iAnswers ));
2011-03-17 01:43:45 -04:00
break ;
case shift_pauses_backward :
2013-08-30 14:43:14 -04:00
GetAppropriateTimingForUpdate (). DeleteRows ( GetRow (),
2015-04-04 09:10:00 -06:00
GetRowsFromAnswers ( c , iAnswers ));
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 ());
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). 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 ) );
2013-01-21 22:53:12 -05:00
GetAppropriateTimingForUpdate (). InsertRows ( GetRow () + 1 , BeatToNoteRow ( fStopBeats ) );
2011-06-24 00:50:32 -04:00
}
break ;
case convert_delay_to_beat :
{
2013-01-21 22:53:12 -05:00
TimingData & timing = GetAppropriateTimingForUpdate ();
2011-06-24 00:50:32 -04:00
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 :
{
2013-01-21 22:53:12 -05:00
const TimingData & timing = GetAppropriateTiming ();
2011-06-30 01:23:59 -04:00
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 ;
}
2012-05-21 21:42:06 -04:00
case modify_attacks_at_row :
{
this -> DoStepAttackMenu ();
break ;
}
2012-02-10 13:41:40 -05:00
case modify_keysounds_at_row :
{
2012-02-10 14:29:11 -05:00
this -> DoKeyboardTrackMenu ();
2012-02-10 13:41:40 -05:00
break ;
}
2011-03-17 01:43:45 -04:00
};
if ( bSaveUndo )
CheckNumberOfNotesAndUndo ();
}
2022-07-10 18:28:56 +03:00
void ScreenEdit :: HandleStepsDataChoice ( StepsDataChoice c , const std :: vector < int > & iAnswers )
2011-07-07 17:52:30 -04:00
{
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." );
2015-03-02 18:44:01 -07:00
static LocalizedString ENTER_NEW_STEP_MUSIC ( "ScreenEdit" , "Enter the music file for this chart." );
2022-07-10 18:28:56 +03:00
void ScreenEdit :: HandleStepsInformationChoice ( StepsInformationChoice c , const std :: vector < int > & iAnswers )
2011-03-17 01:43:45 -04:00
{
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 ]));
2020-10-20 02:16:02 +09:00
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 ,
2019-06-22 12:35:38 -07:00
nullptr );
2011-07-07 14:20:21 -04:00
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 ,
2019-06-22 12:35:38 -07:00
nullptr );
2011-07-07 21:06:05 -04:00
break ;
}
case chartstyle :
{
2020-10-20 02:16:02 +09:00
ScreenTextEntry :: TextEntry ( SM_None ,
2011-07-07 21:06:05 -04:00
ENTER_NEW_CHART_STYLE ,
2020-10-20 02:16:02 +09:00
m_pSteps -> GetChartStyle (),
2011-07-07 21:06:05 -04:00
255 ,
2019-06-22 12:35:38 -07:00
nullptr ,
2020-10-20 02:16:02 +09:00
ChangeChartStyle ,
2019-06-22 12:35:38 -07:00
nullptr );
2011-07-07 21:06:05 -04:00
break ;
}
case step_credit :
{
ScreenTextEntry :: TextEntry ( SM_None ,
ENTER_NEW_STEP_AUTHOR ,
m_pSteps -> GetCredit (),
255 ,
SongUtil :: ValidateCurrentStepsCredit ,
ChangeStepCredit ,
2019-06-22 12:35:38 -07:00
nullptr );
2011-07-07 21:06:05 -04:00
break ;
}
case meter :
{
ScreenTextEntry :: TextEntry ( SM_BackFromDifficultyMeterChange ,
ENTER_NEW_METER ,
ssprintf ( "%d" , m_pSteps -> GetMeter ()),
2012-10-16 21:05:27 -04:00
4 ,
2015-04-04 09:10:00 -06:00
ScreenTextEntry :: IntValidate ,
2012-10-16 21:05:27 -04:00
ChangeStepMeter ,
2019-06-22 12:35:38 -07:00
nullptr );
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 ,
2019-06-22 12:35:38 -07:00
std :: to_string ( pSteps -> GetMinBPM ()), 20 ,
2011-07-07 18:10:59 -04:00
ScreenTextEntry :: FloatValidate ,
2019-06-22 12:35:38 -07:00
ChangeStepsMinBPM , nullptr );
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 ,
2019-06-22 12:35:38 -07:00
std :: to_string ( pSteps -> GetMaxBPM ()), 20 ,
2011-07-07 18:10:59 -04:00
ScreenTextEntry :: FloatValidate ,
2019-06-22 12:35:38 -07:00
ChangeStepsMaxBPM , nullptr );
2011-07-07 18:10:59 -04:00
break ;
2011-07-07 21:06:05 -04:00
}
2015-03-02 18:44:01 -07:00
case step_music :
{
ScreenTextEntry :: TextEntry ( SM_BackFromStepMusicChange ,
ENTER_NEW_STEP_MUSIC ,
m_pSteps -> GetMusicFile (),
255 ,
SongUtil :: ValidateCurrentStepsMusic ,
ChangeStepMusic ,
2019-06-22 12:35:38 -07:00
nullptr );
2015-03-02 18:44:01 -07:00
break ;
}
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." );
2019-06-22 12:35:38 -07:00
static LocalizedString ENTER_PREVIEW ( "ScreenEdit" , "Enter a preview file." );
2011-03-17 01:43:45 -04:00
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." );
2022-07-10 18:28:56 +03:00
void ScreenEdit :: HandleSongInformationChoice ( SongInformationChoice c , const std :: vector < int > & iAnswers )
2011-03-17 01:43:45 -04:00
{
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 :
2019-06-22 12:35:38 -07:00
ScreenTextEntry :: TextEntry ( SM_None , ENTER_MAIN_TITLE , pSong -> m_sMainTitle , 100 , nullptr , ChangeMainTitle , nullptr );
2011-03-17 01:43:45 -04:00
break ;
case sub_title :
2019-06-22 12:35:38 -07:00
ScreenTextEntry :: TextEntry ( SM_None , ENTER_SUB_TITLE , pSong -> m_sSubTitle , 100 , nullptr , ChangeSubTitle , nullptr );
2011-03-17 01:43:45 -04:00
break ;
case artist :
2019-06-22 12:35:38 -07:00
ScreenTextEntry :: TextEntry ( SM_None , ENTER_ARTIST , pSong -> m_sArtist , 100 , nullptr , ChangeArtist , nullptr );
2011-03-17 01:43:45 -04:00
break ;
case genre :
2019-06-22 12:35:38 -07:00
ScreenTextEntry :: TextEntry ( SM_None , ENTER_GENRE , pSong -> m_sGenre , 100 , nullptr , ChangeGenre , nullptr );
2011-03-17 01:43:45 -04:00
break ;
case credit :
2019-06-22 12:35:38 -07:00
ScreenTextEntry :: TextEntry ( SM_None , ENTER_CREDIT , pSong -> m_sCredit , 100 , nullptr , ChangeCredit , nullptr );
2011-03-17 01:43:45 -04:00
break ;
2015-03-04 01:31:02 -07:00
case preview :
2019-06-22 12:35:38 -07:00
ScreenTextEntry :: TextEntry ( SM_None , ENTER_PREVIEW , pSong -> m_PreviewFile , 100 , SongUtil :: ValidateCurrentSongPreview , ChangePreview , nullptr );
2015-03-04 01:31:02 -07:00
break ;
2011-03-17 01:43:45 -04:00
case main_title_transliteration :
2019-06-22 12:35:38 -07:00
ScreenTextEntry :: TextEntry ( SM_None , ENTER_MAIN_TITLE_TRANSLIT , pSong -> m_sMainTitleTranslit , 100 , nullptr , ChangeMainTitleTranslit , nullptr );
2011-03-17 01:43:45 -04:00
break ;
case sub_title_transliteration :
2019-06-22 12:35:38 -07:00
ScreenTextEntry :: TextEntry ( SM_None , ENTER_SUB_TITLE_TRANSLIT , pSong -> m_sSubTitleTranslit , 100 , nullptr , ChangeSubTitleTranslit , nullptr );
2011-03-17 01:43:45 -04:00
break ;
case artist_transliteration :
2019-06-22 12:35:38 -07:00
ScreenTextEntry :: TextEntry ( SM_None , ENTER_ARTIST_TRANSLIT , pSong -> m_sArtistTranslit , 100 , nullptr , ChangeArtistTranslit , nullptr );
2011-03-17 01:43:45 -04:00
break ;
2011-06-30 01:11:38 -04:00
case last_second_hint :
2020-10-20 02:16:02 +09:00
ScreenTextEntry :: TextEntry ( SM_None , ENTER_LAST_SECOND_HINT ,
std :: to_string ( pSong -> GetSpecifiedLastSecond ()), 20 ,
2019-06-22 12:35:38 -07:00
ScreenTextEntry :: FloatValidate , ChangeLastSecondHint , nullptr );
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 ,
2019-06-22 12:35:38 -07:00
std :: to_string ( pSong -> m_fMusicSampleStartSeconds ), 20 ,
ScreenTextEntry :: FloatValidate , ChangePreviewStart , nullptr );
2011-05-03 09:18:31 -04:00
break ;
case preview_length :
ScreenTextEntry :: TextEntry ( SM_None , ENTER_PREVIEW_LENGTH ,
2019-06-22 12:35:38 -07:00
std :: to_string ( pSong -> m_fMusicSampleLengthSeconds ), 20 ,
ScreenTextEntry :: FloatValidate , ChangePreviewLength , nullptr );
2011-05-03 09:18:31 -04:00
break ;
2011-04-05 22:40:33 -04:00
case min_bpm :
ScreenTextEntry :: TextEntry ( SM_None , ENTER_MIN_BPM ,
2019-06-22 12:35:38 -07:00
std :: to_string ( pSong -> m_fSpecifiedBPMMin ), 20 ,
ScreenTextEntry :: FloatValidate , ChangeMinBPM , nullptr );
2011-04-05 22:40:33 -04:00
break ;
case max_bpm :
ScreenTextEntry :: TextEntry ( SM_None , ENTER_MAX_BPM ,
2019-06-22 12:35:38 -07:00
std :: to_string ( pSong -> m_fSpecifiedBPMMax ), 20 ,
ScreenTextEntry :: FloatValidate , ChangeMaxBPM , nullptr );
2011-04-05 22:40:33 -04:00
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." );
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." );
2019-06-22 12:35:38 -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?" );
2022-07-10 18:28:56 +03:00
void ScreenEdit :: HandleTimingDataInformationChoice ( TimingDataInformationChoice c , const std :: vector < int > & iAnswers )
2011-03-17 01:43:45 -04:00
{
switch ( c )
{
DEFAULT_FAIL ( c );
2011-05-12 21:23:48 -04:00
case beat_0_offset :
2013-01-21 23:13:38 -05:00
ScreenTextEntry :: TextEntry (
SM_BackFromBeat0Change ,
ENTER_BEAT_0_OFFSET ,
2019-06-22 12:35:38 -07:00
std :: to_string ( GetAppropriateTiming (). m_fBeat0OffsetInSeconds ),
2013-01-21 23:13:38 -05:00
20
);
2011-05-12 21:23:48 -04:00
break ;
2013-01-21 23:13:38 -05:00
case bpm :
2020-10-20 02:16:02 +09:00
ScreenTextEntry :: TextEntry (
SM_BackFromBPMChange ,
ENTER_BPM_VALUE ,
2019-06-22 12:35:38 -07:00
std :: to_string ( GetAppropriateTiming (). GetBPMAtBeat ( GetBeat () ) ),
2011-03-17 01:43:45 -04:00
10
);
break ;
case stop :
2020-10-20 02:16:02 +09:00
ScreenTextEntry :: TextEntry (
SM_BackFromStopChange ,
ENTER_STOP_VALUE ,
2019-06-22 12:35:38 -07:00
std :: to_string ( GetAppropriateTiming (). GetStopAtBeat ( GetBeat () ) ),
2011-03-17 01:43:45 -04:00
10
);
break ;
case delay :
2020-10-20 02:16:02 +09:00
ScreenTextEntry :: TextEntry (
SM_BackFromDelayChange ,
ENTER_DELAY_VALUE ,
2019-06-22 12:35:38 -07:00
std :: to_string ( GetAppropriateTiming (). GetDelayAtBeat ( GetBeat () ) ),
2011-03-17 01:43:45 -04:00
10
);
break ;
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 :
2020-10-20 02:16:02 +09:00
ScreenTextEntry :: TextEntry (
SM_BackFromWarpChange ,
ENTER_WARP_VALUE ,
2019-06-22 12:35:38 -07:00
std :: to_string ( 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 ,
2019-06-22 12:35:38 -07:00
std :: to_string ( 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 ,
2019-06-22 12:35:38 -07:00
std :: to_string ( 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 ,
2019-06-22 12:35:38 -07:00
std :: to_string ( GetAppropriateTiming (). GetSpeedSegmentAtBeat ( GetBeat () ) -> GetDelay () ),
2011-05-15 15:53:20 -04:00
10
);
break ;
2020-10-20 02:16:02 +09:00
case speed_mode :
2011-05-15 23:48:03 -04:00
{
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
);
2020-10-20 02:16:02 +09:00
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 ,
2019-06-22 12:35:38 -07:00
std :: to_string ( 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
}
2015-04-04 09:10:00 -06:00
case shift_timing_in_region_down :
2016-01-18 11:48:50 -07:00
m_timing_change_menu_purpose = menu_is_for_shifting ;
2015-04-04 09:10:00 -06:00
m_timing_rows_being_shitted = GetRowsFromAnswers ( c , iAnswers );
DisplayTimingChangeMenu ();
break ;
case shift_timing_in_region_up :
2016-01-18 11:48:50 -07:00
m_timing_change_menu_purpose = menu_is_for_shifting ;
2015-04-04 09:10:00 -06:00
m_timing_rows_being_shitted = - GetRowsFromAnswers ( c , iAnswers );
DisplayTimingChangeMenu ();
break ;
case copy_timing_in_region :
2016-01-18 11:48:50 -07:00
m_timing_change_menu_purpose = menu_is_for_copying ;
DisplayTimingChangeMenu ();
break ;
case clear_timing_in_region :
m_timing_change_menu_purpose = menu_is_for_clearing ;
2015-04-04 09:10:00 -06:00
DisplayTimingChangeMenu ();
break ;
case paste_timing_from_clip :
clipboardFullTiming . CopyRange ( 0 , MAX_NOTE_ROW , TimingSegmentType_Invalid , GetRow (), GetAppropriateTimingForUpdate ());
break ;
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
{
2016-01-18 11:48:50 -07:00
if ( GAMESTATE -> m_bIsUsingStepTiming )
2011-06-28 12:25:32 -04:00
{
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 ;
2020-10-20 02:16:02 +09:00
2011-03-17 01:43:45 -04:00
}
}
2015-04-04 09:10:00 -06:00
void ScreenEdit :: HandleTimingDataChangeChoice ( TimingDataChangeChoice choice ,
2022-07-10 18:28:56 +03:00
const std :: vector < int >& answers )
2015-04-04 09:10:00 -06:00
{
TimingSegmentType change_type = TimingSegmentType_Invalid ;
switch ( choice )
{
case timing_all :
change_type = TimingSegmentType_Invalid ;
break ;
case timing_bpm :
change_type = SEGMENT_BPM ;
break ;
case timing_stop :
change_type = SEGMENT_STOP ;
break ;
case timing_delay :
change_type = SEGMENT_DELAY ;
break ;
case timing_time_sig :
change_type = SEGMENT_TIME_SIG ;
break ;
case timing_warp :
change_type = SEGMENT_WARP ;
break ;
case timing_label :
change_type = SEGMENT_LABEL ;
break ;
case timing_tickcount :
change_type = SEGMENT_TICKCOUNT ;
break ;
case timing_combo :
change_type = SEGMENT_COMBO ;
break ;
case timing_speed :
change_type = SEGMENT_SPEED ;
break ;
case timing_scroll :
change_type = SEGMENT_SCROLL ;
break ;
case timing_fake :
change_type = SEGMENT_FAKE ;
break ;
default : break ;
}
int begin = m_NoteFieldEdit . m_iBeginMarker ;
int end = m_NoteFieldEdit . m_iEndMarker ;
if ( begin < 0 )
{
begin = GetRow ();
}
if ( end < 0 )
{
end = MAX_NOTE_ROW ;
}
2016-01-18 11:48:50 -07:00
switch ( m_timing_change_menu_purpose )
2015-04-04 09:10:00 -06:00
{
2016-01-18 11:48:50 -07:00
case menu_is_for_copying :
clipboardFullTiming . Clear ();
GetAppropriateTiming (). CopyRange ( begin , end , change_type , 0 , clipboardFullTiming );
break ;
case menu_is_for_shifting :
GetAppropriateTimingForUpdate (). ShiftRange ( begin , end , change_type , m_timing_rows_being_shitted );
break ;
case menu_is_for_clearing :
GetAppropriateTimingForUpdate (). ClearRange ( begin , end , change_type );
break ;
default : break ;
2015-04-04 09:10:00 -06:00
}
}
2022-07-10 18:28:56 +03:00
void ScreenEdit :: HandleBGChangeChoice ( BGChangeChoice c , const std :: vector < int > & iAnswers )
2011-03-17 01:43:45 -04:00
{
BackgroundChange newChange ;
2019-06-22 12:35:38 -07:00
auto & changes = m_pSong -> GetBackgroundChanges ( g_CurrentBGChangeLayer );
for ( auto iter = changes . begin (); iter != changes . end (); ++ iter )
2011-03-17 01:43:45 -04:00
{
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.
2019-06-22 12:35:38 -07:00
changes . erase ( iter );
2011-03-17 01:43:45 -04:00
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 ]);
2022-08-09 17:09:30 -06:00
newChange . m_def . m_sFile1 = g_BackgroundChange . rows [ row1 ]. choices . empty () ? RString ( "" ) : g_BackgroundChange . rows [ row1 ]. choices [ iAnswers [ row1 ]];
2011-03-17 01:43:45 -04:00
}
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 ]);
2022-08-09 07:08:24 -06:00
newChange . m_def . m_sFile2 = g_BackgroundChange . rows [ row2 ]. choices . empty () ? RString ( "" ) : g_BackgroundChange . rows [ row2 ]. choices [ iAnswers [ row2 ]];
2011-03-17 01:43:45 -04:00
}
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 ;
2020-10-20 02:16:02 +09:00
2011-03-17 01:43:45 -04:00
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 ;
}
}
2019-06-22 12:35:38 -07:00
for ( Attack & attack : Attacks )
GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> LaunchAttack ( attack );
2011-03-17 01:43:45 -04:00
}
2020-10-20 02:16:02 +09: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 ;
2020-10-20 02:16:02 +09:00
2011-06-26 23:58:24 -04:00
if ( attacks . size () > 0 )
2011-06-24 17:29:34 -04:00
{
2019-06-22 12:35:38 -07:00
for ( Attack & attack : attacks )
2011-06-26 23:58:24 -04:00
{
2015-07-11 00:43:37 -06:00
// LaunchAttack is actually a misnomer. The function actually adds
// the attack to a list in the PlayerState which is checked and
// updated every tick to see which ones to actually activate. -Kyz
2019-06-22 12:35:38 -07:00
GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> LaunchAttack ( attack );
2011-06-26 23:58:24 -04:00
}
2011-06-24 17:29:34 -04:00
}
}
}
2020-10-20 02:16:02 +09:00
2011-03-17 01:43:45 -04:00
GAMESTATE -> m_pPlayerState [ PLAYER_1 ] -> RebuildPlayerOptionsFromActiveAttacks ();
}
void ScreenEdit :: CopyToLastSave ()
{
2024-08-10 12:07:54 -04:00
ASSERT ( GAMESTATE -> m_pCurSteps [ main_player_ ] != nullptr );
2011-03-17 01:43:45 -04:00
m_SongLastSave = * GAMESTATE -> m_pCurSong ;
m_vStepsLastSave . clear ();
2024-08-10 12:07:54 -04:00
const std :: vector < Steps *>& vSteps = GAMESTATE -> m_pCurSong -> GetStepsByStepsType ( GAMESTATE -> m_pCurSteps [ main_player_ ] -> m_StepsType );
for ( Steps * it : vSteps ) {
m_vStepsLastSave . push_back ( * it );
}
2011-03-17 01:43:45 -04:00
}
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 ;
2024-08-10 12:07:54 -04:00
const std :: vector < Steps *>& vSteps = GAMESTATE -> m_pCurSong -> GetStepsByStepsType ( GAMESTATE -> m_pCurSteps [ main_player_ ] -> 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 ) {
2011-03-17 01:43:45 -04:00
* vSteps [ i ] = m_vStepsLastSave [ i ];
2024-08-10 12:07:54 -04:00
}
2011-03-17 01:43:45 -04:00
}
void ScreenEdit :: RevertFromDisk ()
{
2019-06-22 12:35:38 -07:00
ASSERT ( GAMESTATE -> m_pCurSteps [ PLAYER_1 ] != nullptr );
2011-03-17 01:43:45 -04:00
StepsID id ;
id . FromSteps ( GAMESTATE -> m_pCurSteps [ PLAYER_1 ] );
ASSERT ( id . IsValid () );
2015-04-13 10:33:09 -06:00
// If m_bInStepEditor is true while the song is reloaded, it screws up
// loading and results in the steps being cleared. -Kyz
GAMESTATE -> m_bInStepEditor = false ;
GAMESTATE -> m_pCurSong -> ReloadFromSongDir ();
GAMESTATE -> m_bInStepEditor = true ;
2011-03-17 01:43:45 -04:00
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
2020-10-20 02:16:02 +09:00
// work of someone maliciously changing the simfile; it could happen to
2011-03-17 01:43:45 -04:00
// 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 )
{
2022-07-10 18:28:56 +03:00
std :: swap ( m_Undo , m_NoteDataEdit );
2011-03-17 01:43:45 -04:00
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
2020-10-20 02:16:02 +09:00
/* Round up to the next measure end. Some songs end on weird beats
2011-03-17 01:43:45 -04:00
* 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
2020-10-20 02:16:02 +09: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
2011-03-17 01:43:45 -04:00
* GetLastBeat() and move off of that beat, they won't be able to return. */
2022-07-10 18:28:56 +03:00
fEndBeat = std :: max ( fEndBeat , m_NoteDataEdit . GetLastBeat () );
2011-03-17 01:43:45 -04:00
return fEndBeat ;
}
struct EditHelpLine
{
const char * szEnglishDescription ;
2022-07-10 18:28:56 +03:00
std :: vector < EditButton > veb ;
2011-03-17 01:43:45 -04:00
2020-10-20 02:16:02 +09:00
EditHelpLine (
2011-03-17 01:43:45 -04:00
const char * _szEnglishDescription ,
2020-10-20 02:16:02 +09:00
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 ,
2011-03-17 01:43:45 -04:00
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 );
2020-10-20 02:16:02 +09:00
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 );
2011-03-17 01:43:45 -04:00
#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 ),
2019-06-22 12:35:38 -07:00
EditHelpLine ( "Next/prev steps of same StepsType" , EDIT_BUTTON_OPEN_PREV_STEPS , EDIT_BUTTON_OPEN_NEXT_STEPS ),
2011-03-17 01:43:45 -04:00
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_" , "" );
}
2022-07-10 18:28:56 +03:00
static void ProcessKeyNames ( std :: vector < RString > & vs , bool doSort )
2011-03-17 01:43:45 -04:00
{
2019-06-22 12:35:38 -07:00
for ( RString & s : vs )
ProcessKeyName ( s );
2011-03-17 01:43:45 -04:00
2013-08-30 14:09:03 -04:00
if ( doSort )
sort ( vs . begin (), vs . end () );
2022-07-10 18:28:56 +03:00
std :: vector < RString >:: iterator toDelete = unique ( vs . begin (), vs . end () );
2011-03-17 01:43:45 -04:00
vs . erase ( toDelete , vs . end ());
}
2022-07-10 18:28:56 +03:00
static RString GetDeviceButtonsLocalized ( const std :: vector < EditButton > & veb , const MapEditToDI & editmap )
2011-03-17 01:43:45 -04:00
{
2022-07-10 18:28:56 +03:00
std :: vector < RString > vsPress ;
std :: vector < RString > vsHold ;
2019-06-22 12:35:38 -07:00
for ( EditButton const & eb : veb )
2011-03-17 01:43:45 -04:00
{
2019-06-22 12:35:38 -07:00
if ( ! IsMapped ( eb , editmap ) )
2011-03-17 01:43:45 -04:00
continue ;
for ( int s = 0 ; s < NUM_EDIT_TO_DEVICE_SLOTS ; s ++ )
{
2019-06-22 12:35:38 -07:00
DeviceInput diPress = editmap . button [ eb ][ s ];
DeviceInput diHold = editmap . hold [ eb ][ s ];
2011-03-17 01:43:45 -04:00
if ( diPress . IsValid () )
vsPress . push_back ( Capitalize ( INPUTMAN -> GetLocalizedInputString ( diPress )) );
if ( diHold . IsValid () )
vsHold . push_back ( Capitalize ( INPUTMAN -> GetLocalizedInputString ( diHold )) );
}
}
2013-08-30 14:09:03 -04:00
ProcessKeyNames ( vsPress , false );
ProcessKeyNames ( vsHold , true );
2011-03-17 01:43:45 -04:00
RString s = join ( "/" , vsPress );
if ( ! vsHold . empty () )
s = join ( "/" , vsHold ) + " + " + s ;
return s ;
}
2012-05-21 21:42:06 -04:00
void ScreenEdit :: DoStepAttackMenu ()
{
2013-01-21 22:53:12 -05:00
const TimingData & timing = GetAppropriateTiming ();
2012-05-21 21:42:06 -04:00
float startTime = timing . GetElapsedTimeFromBeat ( GetBeat ());
2020-10-20 02:16:02 +09:00
AttackArray & attacks =
2012-05-21 21:42:06 -04:00
( GAMESTATE -> m_bIsUsingStepTiming ? m_pSteps -> m_Attacks : m_pSong -> m_Attacks );
2022-07-10 18:28:56 +03:00
std :: vector < int > points = FindAllAttacksAtTime ( attacks , startTime );
2020-10-20 02:16:02 +09:00
2012-05-21 21:42:06 -04:00
g_AttackAtTimeMenu . rows . clear ();
unsigned index = 0 ;
2020-10-20 02:16:02 +09:00
2019-06-22 12:35:38 -07:00
for ( int & i : points )
2012-05-21 21:42:06 -04:00
{
2019-06-22 12:35:38 -07:00
const Attack & attack = attacks [ i ];
2012-12-28 16:18:21 -05:00
RString desc = ssprintf ( "%g -> %g (%d mod[s])" ,
2012-05-21 21:42:06 -04:00
startTime , startTime + attack . fSecsRemaining ,
attack . GetNumAttacks ());
2020-10-20 02:16:02 +09:00
2012-05-21 21:42:06 -04:00
g_AttackAtTimeMenu . rows . push_back ( MenuRowDef ( index ++ ,
desc ,
true ,
EditMode_CourseMods ,
false ,
false ,
0 ,
"Modify" ,
"Delete" ));
}
g_AttackAtTimeMenu . rows . push_back ( MenuRowDef ( index ,
"Add Attack" ,
true ,
EditMode_CourseMods ,
true ,
true ,
0 ,
2019-06-22 12:35:38 -07:00
nullptr ));
2020-10-20 02:16:02 +09:00
2012-05-21 21:42:06 -04:00
EditMiniMenu ( & g_AttackAtTimeMenu , SM_BackFromAttackAtTime );
}
2012-02-10 14:09:12 -05:00
static LocalizedString TRACK_NUM ( "ScreenEdit" , "Track %d" );
2012-02-10 14:29:11 -05:00
static LocalizedString NO_KEYSND ( "ScreenEdit" , "None" );
static LocalizedString NEWKEYSND ( "ScreenEdit" , "New Sound" );
2012-02-10 14:09:12 -05:00
void ScreenEdit :: DoKeyboardTrackMenu ()
{
g_KeysoundTrack . rows . clear ();
2022-07-10 18:28:56 +03:00
std :: vector < RString > & kses = m_pSong -> m_vsKeysoundFile ;
2020-10-20 02:16:02 +09:00
2022-07-10 18:28:56 +03:00
std :: vector < RString > choices ;
2019-06-22 12:35:38 -07:00
for ( RString const & ks : kses )
2012-02-10 14:29:11 -05:00
{
2019-06-22 12:35:38 -07:00
choices . push_back ( ks );
2012-02-10 14:29:11 -05:00
}
choices . push_back ( NEWKEYSND );
choices . push_back ( NO_KEYSND );
int numKeysounds = kses . size ();
2013-06-09 09:08:53 -04:00
int foundKeysounds = 0 ;
2012-02-10 14:09:12 -05:00
for ( int i = 0 ; i < m_NoteDataEdit . GetNumTracks (); ++ i )
{
const TapNote & tn = m_NoteDataEdit . GetTapNote ( i , this -> GetRow ());
2012-02-10 14:29:11 -05:00
int keyIndex = tn . iKeysoundIndex ;
if ( keyIndex == - 1 )
{
keyIndex = numKeysounds ;
}
2013-06-09 09:08:53 -04:00
else
{
++ foundKeysounds ;
}
2020-10-20 02:16:02 +09:00
2012-02-10 14:29:11 -05:00
g_KeysoundTrack . rows . push_back ( MenuRowDef ( i , ssprintf ( TRACK_NUM . GetValue (), i + 1 ),
true , EditMode_Full , false , false , keyIndex , choices ));
2012-02-10 14:09:12 -05:00
}
2012-02-11 15:11:44 -05:00
g_KeysoundTrack . rows . push_back ( MenuRowDef ( m_NoteDataEdit . GetNumTracks (), "Remove Keysound" ,
2013-06-09 09:08:53 -04:00
foundKeysounds > 0 , EditMode_Full , false , false , 0 , kses ));
2020-10-20 02:16:02 +09:00
2012-02-10 14:44:48 -05:00
EditMiniMenu ( & g_KeysoundTrack , SM_BackFromKeysoundTrack );
2012-02-10 14:09:12 -05:00
}
2011-03-17 01:43:45 -04:00
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 );
2020-10-20 02:16:02 +09:00
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 ;
}
2020-10-20 02:16:02 +09:00
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"
2020-10-20 02:16:02 +09:00
/** @brief Allow Lua to have access to ScreenEdit. */
2011-03-17 01:43:45 -04:00
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.
2020-10-20 02:16:02 +09:00
*
2011-03-17 01:43:45 -04:00
* 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.
2020-10-20 02:16:02 +09:00
*
2011-03-17 01:43:45 -04:00
* 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.
*/