Files
itgmania212121/stepmania/src/ScreenEdit.cpp
T

2723 lines
100 KiB
C++
Raw Normal View History

2003-02-16 04:01:45 +00:00
#include "global.h"
2002-05-20 08:59:37 +00:00
#include "ScreenEdit.h"
#include "PrefsManager.h"
#include "SongManager.h"
#include "ScreenManager.h"
#include "GameConstantsAndTypes.h"
2002-07-23 01:41:40 +00:00
#include "PrefsManager.h"
2002-05-20 08:59:37 +00:00
#include "GameManager.h"
#include "GameConstantsAndTypes.h"
#include "RageLog.h"
2004-07-08 00:10:34 +00:00
#include "GameSoundManager.h"
2002-07-23 01:41:40 +00:00
#include "GameState.h"
2002-10-18 19:01:32 +00:00
#include "InputMapper.h"
#include "RageLog.h"
#include "ThemeManager.h"
2003-02-18 23:15:38 +00:00
#include "ScreenMiniMenu.h"
2003-02-19 06:27:20 +00:00
#include "NoteSkinManager.h"
2003-08-03 00:13:55 +00:00
#include "Steps.h"
#include <utility>
#include "NoteFieldPositioning.h"
2003-08-07 06:36:34 +00:00
#include "NoteDataUtil.h"
#include "SongUtil.h"
#include "StepsUtil.h"
#include "Foreach.h"
#include "ScreenDimensions.h"
#include "ThemeMetric.h"
#include "PlayerState.h"
#include "ScreenTextEntry.h"
2005-01-15 02:01:26 +00:00
#include "Style.h"
2005-02-09 05:27:51 +00:00
#include "ActorUtil.h"
#include "ScreenPrompt.h"
#include "CommonMetrics.h"
#include "ScreenPlayerOptions.h" // for SM_BackFromPlayerOptions
#include "ScreenSongOptions.h" // for SM_BackFromSongOptions
#include <float.h>
2002-05-20 08:59:37 +00:00
//
2005-01-05 04:35:15 +00:00
// Defines specific to ScreenEdit
2002-05-20 08:59:37 +00:00
//
2005-03-20 09:52:48 +00:00
const float RECORD_HOLD_SECONDS = 0.3f;
2002-05-20 08:59:37 +00:00
2004-11-05 06:35:10 +00:00
#define PLAYER_X (SCREEN_CENTER_X)
#define PLAYER_Y (SCREEN_CENTER_Y)
2003-09-21 23:16:44 +00:00
#define PLAYER_HEIGHT (360)
#define PLAYER_Y_STANDARD (PLAYER_Y-PLAYER_HEIGHT/2)
2002-08-17 06:44:04 +00:00
2005-04-07 19:27:53 +00: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->GetMetric(m_sName,"PlayRecordHelpText")
2003-02-18 23:15:38 +00:00
2005-04-01 08:34:23 +00:00
AutoScreenMessage( SM_UpdateTextInfo )
AutoScreenMessage( SM_BackFromMainMenu )
AutoScreenMessage( SM_BackFromAreaMenu )
AutoScreenMessage( SM_BackFromStepsInformation )
AutoScreenMessage( SM_BackFromEditOptions )
AutoScreenMessage( SM_BackFromSongInformation )
AutoScreenMessage( SM_BackFromBGChange )
AutoScreenMessage( SM_BackFromInsertAttack )
AutoScreenMessage( SM_BackFromInsertAttackPlayerOptions )
AutoScreenMessage( SM_BackFromPrefs )
AutoScreenMessage( SM_BackFromCourseModeMenu )
AutoScreenMessage( SM_DoRevertToLastSave )
AutoScreenMessage( SM_BackFromBPMChange )
AutoScreenMessage( SM_BackFromStopChange )
AutoScreenMessage( SM_DoSaveAndExit )
AutoScreenMessage( SM_DoExit )
2002-06-29 11:59:09 +00:00
2005-03-20 07:11:23 +00:00
const CString INPUT_TIPS_TEXT =
2005-03-25 03:14:28 +00:00
#if defined(XBOX)
2004-10-28 07:56:13 +00:00
"Up/Down:\n change beat\n"
"Left/Right:\n change snap\n"
"A/B/X/Y:\n add/remove\n tap note\n"
"Create hold note:\n Hold a button\n while moving\n Up or Down\n"
"White:\n Set area\n marker\n"
"Start:\n Area Menu\n"
"Select:\n Main Menu\n"
"Black:\n Show\n shortcuts\n";
2005-03-25 03:14:28 +00:00
#else
"Up/Down:\n change beat\n"
"Left/Right:\n change snap\n"
"Number keys:\n add/remove\n tap note\n"
"Create hold note:\n Hold a number\n while moving\n Up or Down\n"
"Space bar:\n Set area\n marker\n"
"Enter:\n Area Menu\n"
"Escape:\n Main Menu\n"
"F1:\n Show help\n";
2004-10-28 07:56:13 +00:00
#endif
2003-02-18 23:15:38 +00:00
#if defined(XBOX)
2005-01-15 13:14:36 +00:00
void ScreenEdit::InitEditMappings()
{
/* XXX: fill this in */
}
#else
2005-01-15 13:14:36 +00:00
void ScreenEdit::InitEditMappings()
{
g_EditMappings.Clear();
g_EditMappings.button[EDIT_BUTTON_COLUMN_0][0] = DeviceInput(DEVICE_KEYBOARD, KEY_C1);
g_EditMappings.button[EDIT_BUTTON_COLUMN_1][0] = DeviceInput(DEVICE_KEYBOARD, KEY_C2);
g_EditMappings.button[EDIT_BUTTON_COLUMN_2][0] = DeviceInput(DEVICE_KEYBOARD, KEY_C3);
g_EditMappings.button[EDIT_BUTTON_COLUMN_3][0] = DeviceInput(DEVICE_KEYBOARD, KEY_C4);
g_EditMappings.button[EDIT_BUTTON_COLUMN_4][0] = DeviceInput(DEVICE_KEYBOARD, KEY_C5);
g_EditMappings.button[EDIT_BUTTON_COLUMN_5][0] = DeviceInput(DEVICE_KEYBOARD, KEY_C6);
g_EditMappings.button[EDIT_BUTTON_COLUMN_6][0] = DeviceInput(DEVICE_KEYBOARD, KEY_C7);
g_EditMappings.button[EDIT_BUTTON_COLUMN_7][0] = DeviceInput(DEVICE_KEYBOARD, KEY_C8);
g_EditMappings.button[EDIT_BUTTON_COLUMN_8][0] = DeviceInput(DEVICE_KEYBOARD, KEY_C9);
g_EditMappings.button[EDIT_BUTTON_COLUMN_9][0] = DeviceInput(DEVICE_KEYBOARD, KEY_C0);
g_EditMappings.button[EDIT_BUTTON_RIGHT_SIDE][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LALT);
g_EditMappings.button[EDIT_BUTTON_RIGHT_SIDE][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RALT);
g_EditMappings.button[EDIT_BUTTON_LAY_MINE][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LSHIFT);
g_EditMappings.button[EDIT_BUTTON_LAY_ATTACK][0] = DeviceInput(DEVICE_KEYBOARD, KEY_RSHIFT);
g_EditMappings.button[EDIT_BUTTON_SCROLL_UP_LINE][0] = DeviceInput(DEVICE_KEYBOARD, KEY_UP);
g_EditMappings.button[EDIT_BUTTON_SCROLL_UP_PAGE][0] = DeviceInput(DEVICE_KEYBOARD, KEY_PGUP);
g_EditMappings.button[EDIT_BUTTON_SCROLL_DOWN_LINE][0] = DeviceInput(DEVICE_KEYBOARD, KEY_DOWN);
g_EditMappings.button[EDIT_BUTTON_SCROLL_DOWN_PAGE][0] = DeviceInput(DEVICE_KEYBOARD, KEY_PGDN);
g_EditMappings.button[EDIT_BUTTON_SCROLL_HOME][0] = DeviceInput(DEVICE_KEYBOARD, KEY_HOME);
g_EditMappings.button[EDIT_BUTTON_SCROLL_END][0] = DeviceInput(DEVICE_KEYBOARD, KEY_END);
g_EditMappings.button [EDIT_BUTTON_SCROLL_SPEED_UP][0] = DeviceInput(DEVICE_KEYBOARD, KEY_UP);
g_EditMappings.hold[EDIT_BUTTON_SCROLL_SPEED_UP][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL);
g_EditMappings.hold[EDIT_BUTTON_SCROLL_SPEED_UP][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL);
g_EditMappings.button [EDIT_BUTTON_SCROLL_SPEED_DOWN][0] = DeviceInput(DEVICE_KEYBOARD, KEY_DOWN);
g_EditMappings.hold[EDIT_BUTTON_SCROLL_SPEED_DOWN][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL);
g_EditMappings.hold[EDIT_BUTTON_SCROLL_SPEED_DOWN][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL);
g_EditMappings.button[EDIT_BUTTON_SCROLL_SELECT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LSHIFT);
g_EditMappings.button[EDIT_BUTTON_SCROLL_SELECT][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RSHIFT);
g_EditMappings.button[EDIT_BUTTON_LAY_SELECT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_SPACE);
g_EditMappings.button[EDIT_BUTTON_SNAP_NEXT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LEFT);
g_EditMappings.button[EDIT_BUTTON_SNAP_PREV][0] = DeviceInput(DEVICE_KEYBOARD, KEY_RIGHT);
g_EditMappings.button[EDIT_BUTTON_OPEN_EDIT_MENU][0] = DeviceInput(DEVICE_KEYBOARD, KEY_ESC);
g_EditMappings.button[EDIT_BUTTON_OPEN_AREA_MENU][0] = DeviceInput(DEVICE_KEYBOARD, KEY_ENTER);
g_EditMappings.button[EDIT_BUTTON_OPEN_AREA_MENU][1] = DeviceInput(DEVICE_KEYBOARD, KEY_KP_ENTER);
g_EditMappings.button[EDIT_BUTTON_OPEN_BGA_MENU][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cb);
g_EditMappings.button[EDIT_BUTTON_OPEN_COURSE_MENU][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cc);
g_EditMappings.button[EDIT_BUTTON_OPEN_INPUT_HELP][0] = DeviceInput(DEVICE_KEYBOARD, KEY_F1);
g_EditMappings.button[EDIT_BUTTON_PLAY_FROM_START][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cp);
g_EditMappings.hold[EDIT_BUTTON_PLAY_FROM_START][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL);
g_EditMappings.hold[EDIT_BUTTON_PLAY_FROM_START][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL);
g_EditMappings.button[EDIT_BUTTON_PLAY_FROM_CURSOR][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cp);
g_EditMappings.hold[EDIT_BUTTON_PLAY_FROM_CURSOR][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LSHIFT);
g_EditMappings.hold[EDIT_BUTTON_PLAY_FROM_CURSOR][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RSHIFT);
g_EditMappings.button[EDIT_BUTTON_PLAY_SELECTION][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cp);
g_EditMappings.button[EDIT_BUTTON_RECORD][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cr);
g_EditMappings.hold[EDIT_BUTTON_RECORD][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL);
g_EditMappings.hold[EDIT_BUTTON_RECORD][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL);
g_EditMappings.button[EDIT_BUTTON_INSERT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_INSERT);
g_EditMappings.button[EDIT_BUTTON_DELETE][0] = DeviceInput(DEVICE_KEYBOARD, KEY_DEL);
g_EditMappings.button[EDIT_BUTTON_INSERT_SHIFT_PAUSES][0] = DeviceInput(DEVICE_KEYBOARD, KEY_INSERT);
g_EditMappings.hold[EDIT_BUTTON_INSERT_SHIFT_PAUSES][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL);
g_EditMappings.hold[EDIT_BUTTON_INSERT_SHIFT_PAUSES][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL);
g_EditMappings.button[EDIT_BUTTON_DELETE_SHIFT_PAUSES][0] = DeviceInput(DEVICE_KEYBOARD, KEY_DEL);
g_EditMappings.hold[EDIT_BUTTON_DELETE_SHIFT_PAUSES][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL);
g_EditMappings.hold[EDIT_BUTTON_DELETE_SHIFT_PAUSES][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL);
g_EditMappings.button[EDIT_BUTTON_TOGGLE_ASSIST_TICK][0] = DeviceInput(DEVICE_KEYBOARD, KEY_F4);
g_EditMappings.button[EDIT_BUTTON_PLAY_SAMPLE_MUSIC][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cm);
g_EditMappings.button[EDIT_BUTTON_OPEN_NEXT_STEPS][0] = DeviceInput(DEVICE_KEYBOARD, KEY_F6);
g_EditMappings.button[EDIT_BUTTON_OPEN_PREV_STEPS][0] = DeviceInput(DEVICE_KEYBOARD, KEY_F5);
g_EditMappings.button[EDIT_BUTTON_BPM_UP][0] = DeviceInput(DEVICE_KEYBOARD, KEY_F8);
g_EditMappings.button[EDIT_BUTTON_BPM_DOWN][0] = DeviceInput(DEVICE_KEYBOARD, KEY_F7);
g_EditMappings.button[EDIT_BUTTON_STOP_UP][0] = DeviceInput(DEVICE_KEYBOARD, KEY_F10);
g_EditMappings.button[EDIT_BUTTON_STOP_DOWN][0] = DeviceInput(DEVICE_KEYBOARD, KEY_F9);
g_EditMappings.button[EDIT_BUTTON_OFFSET_UP][0] = DeviceInput(DEVICE_KEYBOARD, KEY_F12);
g_EditMappings.button[EDIT_BUTTON_OFFSET_DOWN][0] = DeviceInput(DEVICE_KEYBOARD, KEY_F11);
g_EditMappings.button[EDIT_BUTTON_SAMPLE_START_UP][0] = DeviceInput(DEVICE_KEYBOARD, KEY_RBRACKET);
g_EditMappings.button[EDIT_BUTTON_SAMPLE_START_DOWN][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LBRACKET);
g_EditMappings.button[EDIT_BUTTON_SAMPLE_LENGTH_UP][0] = DeviceInput(DEVICE_KEYBOARD, KEY_RBRACKET);
g_EditMappings.hold[EDIT_BUTTON_SAMPLE_LENGTH_UP][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LSHIFT);
g_EditMappings.hold[EDIT_BUTTON_SAMPLE_LENGTH_UP][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RSHIFT);
g_EditMappings.button[EDIT_BUTTON_SAMPLE_LENGTH_DOWN][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LBRACKET);
g_EditMappings.hold[EDIT_BUTTON_SAMPLE_LENGTH_DOWN][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LSHIFT);
g_EditMappings.hold[EDIT_BUTTON_SAMPLE_LENGTH_DOWN][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RSHIFT);
g_EditMappings.button[EDIT_BUTTON_ADJUST_FINE][0] = DeviceInput(DEVICE_KEYBOARD, KEY_RALT);
g_EditMappings.button[EDIT_BUTTON_ADJUST_FINE][1] = DeviceInput(DEVICE_KEYBOARD, KEY_LALT);
g_PlayMappings.button[EDIT_BUTTON_RETURN_TO_EDIT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_ESC);
g_PlayMappings.button[EDIT_BUTTON_TOGGLE_ASSIST_TICK][0] = DeviceInput(DEVICE_KEYBOARD, KEY_F4);
g_PlayMappings.button[EDIT_BUTTON_TOGGLE_AUTOPLAY][0] = DeviceInput(DEVICE_KEYBOARD, KEY_F8);
g_PlayMappings.button[EDIT_BUTTON_OFFSET_UP][0] = DeviceInput(DEVICE_KEYBOARD, KEY_F12);
g_PlayMappings.button[EDIT_BUTTON_OFFSET_DOWN][0] = DeviceInput(DEVICE_KEYBOARD, KEY_F11);
g_RecordMappings.button[EDIT_BUTTON_RETURN_TO_EDIT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_ESC);
}
#endif
/* Given a DeviceInput that was just depressed, return an active edit function. */
2005-01-15 18:33:09 +00:00
bool ScreenEdit::DeviceToEdit( DeviceInput DeviceI, EditButton &button ) const
{
ASSERT( DeviceI.IsValid() );
2005-01-15 13:14:36 +00:00
const MapEditToDI *pCurrentMap = GetCurrentMap();
/* 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 )
{
2005-01-15 13:14:36 +00:00
if( pCurrentMap->button[e][slot] == DeviceI && pCurrentMap->hold[e][0].IsValid() )
{
/* The button maps to this function. */
button = e;
/* This function has one or more shift modifier attached. */
for( int holdslot = 0; holdslot < NUM_EDIT_TO_DEVICE_SLOTS; ++holdslot )
{
2005-01-15 13:14:36 +00:00
DeviceInput hDI = pCurrentMap->hold[e][holdslot];
2005-03-27 00:33:31 +00:00
if( hDI.IsValid() && INPUTFILTER->IsBeingPressed(hDI) )
return true;
}
}
}
}
/* No shifted keys matched. See if any unshifted inputs are bound to this key. */
FOREACH_EditButton(e)
{
for( int slot = 0; slot < NUM_EDIT_TO_DEVICE_SLOTS; ++slot )
{
2005-01-15 13:14:36 +00:00
if( pCurrentMap->button[e][slot] == DeviceI && !pCurrentMap->hold[e][0].IsValid() )
{
/* The button maps to this function. */
button = e;
return true;
}
}
}
2005-01-15 13:05:33 +00:00
button = EDIT_BUTTON_INVALID;
return false;
}
2005-01-23 23:49:19 +00:00
/* 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 = GetCurrentMap();
/* First, search to see if a key that requires a modifier is pressed. */
bool bPrimaryButtonPressed = false;
for( int slot = 0; slot < NUM_EDIT_TO_DEVICE_SLOTS; ++slot )
{
if( pCurrentMap->button[button][slot] == DeviceI )
bPrimaryButtonPressed = true;
}
if( !bPrimaryButtonPressed )
return false;
/* The button maps to this function. Does the function has one or more shift modifiers attached? */
if( !pCurrentMap->hold[button][0].IsValid() )
return true;
for( int holdslot = 0; holdslot < NUM_EDIT_TO_DEVICE_SLOTS; ++holdslot )
{
DeviceInput hDI = pCurrentMap->hold[button][holdslot];
if( INPUTFILTER->IsBeingPressed(hDI) )
return true;
}
/* No shifted keys matched. */
return false;
}
2005-01-15 18:33:09 +00:00
bool ScreenEdit::EditToDevice( EditButton button, int iSlotNum, DeviceInput &DeviceI ) const
{
ASSERT( iSlotNum < NUM_EDIT_TO_DEVICE_SLOTS );
2005-01-15 13:14:36 +00:00
const MapEditToDI *pCurrentMap = GetCurrentMap();
2005-03-12 00:51:09 +00:00
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();
}
2005-01-15 18:33:09 +00:00
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;
}
2005-01-15 13:14:36 +00:00
const MapEditToDI *ScreenEdit::GetCurrentMap() const
{
2005-04-14 06:34:17 +00:00
switch( m_EditState )
2005-01-15 13:14:36 +00:00
{
2005-04-14 06:34:17 +00:00
case STATE_EDITING: return &g_EditMappings;
case STATE_PLAYING: return &g_PlayMappings;
case STATE_RECORDING: return &g_RecordMappings;
default: FAIL_M( ssprintf("%i",m_EditState) );
2005-01-15 13:14:36 +00:00
}
}
2003-02-18 23:15:38 +00:00
static Menu g_EditHelp(
"ScreenMiniMenuEditHelp",
2005-03-25 03:14:28 +00:00
#if defined(XBOX)
2005-04-14 06:34:17 +00:00
MenuRow( -1, "L + Up/Down: Change zoom", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "R + Up/Down: Drag area marker", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "L + Select: Play selection", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "R + Start: Play whole song", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "R + Select: Record", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "L + Black: Toggle assist tick", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "R + White: Insert beat and shift down", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "R + Black: Delete beat and shift up", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "R + button: Lay mine", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "L + button: Add to/remove from right half", false, EDIT_MODE_PRACTICE, 0, NULL )
2005-03-25 03:14:28 +00:00
#else
2005-04-14 06:34:17 +00:00
MenuRow( -1, "PgUp/PgDn: jump measure", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "Home/End: jump to first/last beat", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "Ctrl + Up/Down: Change zoom", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "Shift + Up/Down: Drag area marker", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "P: Play selection", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "Ctrl + P: Play whole song", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "Shift + P: Play current beat to end", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "Ctrl + R: Record", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "F4: Toggle assist tick", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "F5/F6: Next/prev steps of same StepsType", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "F7/F8: Decrease/increase BPM at cur beat", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "F9/F10: Decrease/increase stop at cur beat", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "F11/F12: Decrease/increase music offset", false, EDIT_MODE_PRACTICE, 0, NULL ),
2005-03-20 06:41:56 +00:00
/* XXX: This would be better as a single submenu, to let people tweak
* and play the sample several times (without having to re-enter the
* menu each time), so it doesn't use a whole bunch of hotkeys. */
2005-04-14 06:34:17 +00:00
MenuRow( -1, "[ and ]: Decrease/increase sample music start", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "{ and }: Decrease/increase sample music length", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "M: Play sample music", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "B: Add/Edit Background Change", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "Insert: Insert beat and shift down", false, EDIT_MODE_PRACTICE, 0, NULL ),
2005-03-20 06:41:56 +00:00
MenuRow( -1, "Ctrl + Insert: Shift BPM changes and stops down one beat",
2005-04-14 06:34:17 +00:00
false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "Delete: Delete beat and shift up", false, EDIT_MODE_PRACTICE, 0, NULL ),
2005-03-20 06:41:56 +00:00
MenuRow( -1, "Ctrl + Delete: Shift BPM changes and stops up one beat",
2005-04-14 06:34:17 +00:00
false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "Shift + number: Lay mine", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( -1, "Alt + number: Add to/remove from right half", false, EDIT_MODE_PRACTICE, 0, NULL )
2004-10-28 07:56:13 +00:00
#endif
2005-03-20 06:41:56 +00:00
);
static Menu g_MainMenu(
"ScreenMiniMenuMainMenu",
2005-04-14 06:34:17 +00:00
MenuRow( ScreenEdit::edit_steps_information, "Edit Steps Information", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::play_whole_song, "Play Whole Song", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::play_current_beat_to_end, "Play Current Beat to End", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::save, "Save", true, EDIT_MODE_HOME, 0, NULL ),
MenuRow( ScreenEdit::revert_to_last_save, "Revert to Last Save", true, EDIT_MODE_HOME, 0, NULL ),
MenuRow( ScreenEdit::player_options, "Player Options", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::song_options, "Song Options", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::edit_song_info, "Edit Song Info", true, EDIT_MODE_FULL, 0, NULL ),
MenuRow( ScreenEdit::edit_bpm, "Edit BPM Change", true, EDIT_MODE_FULL, 0, NULL ),
MenuRow( ScreenEdit::edit_stop, "Edit Stop", true, EDIT_MODE_FULL, 0, NULL ),
MenuRow( ScreenEdit::edit_bg_change, "Add/Edit Background Change", true, EDIT_MODE_FULL, 0, NULL ),
MenuRow( ScreenEdit::play_preview_music, "Play Preview Music", true, EDIT_MODE_FULL, 0, NULL ),
MenuRow( ScreenEdit::preferences, "Preferences", true, EDIT_MODE_FULL, 0, NULL ),
MenuRow( ScreenEdit::exit, "Exit", true, EDIT_MODE_PRACTICE, 0, NULL )
2005-03-20 06:41:56 +00:00
);
static Menu g_AreaMenu(
"ScreenMiniMenuAreaMenu",
2005-04-14 06:34:17 +00:00
MenuRow( ScreenEdit::cut, "Cut", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::copy, "Copy", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::paste_at_current_beat, "Paste at current beat", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::paste_at_begin_marker, "Paste at begin marker", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::clear, "Clear area", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::quantize, "Quantize", true, EDIT_MODE_PRACTICE, 0, "4th","8th","12th","16th","24th","32nd","48th","64th","192nd"),
MenuRow( ScreenEdit::turn, "Turn", true, EDIT_MODE_PRACTICE, 0, "Left","Right","Mirror","Shuffle","SuperShuffle" ),
MenuRow( ScreenEdit::transform, "Transform", true, EDIT_MODE_PRACTICE, 0, "NoHolds","NoMines","Little","Wide","Big","Quick","Skippy","Mines","Echo","Stomp","Planted","Floored","Twister","NoJumps","NoHands","NoQuads" ),
MenuRow( ScreenEdit::alter, "Alter", true, EDIT_MODE_PRACTICE, 0, "Autogen To Fill Width","Backwards","Swap Sides","Copy Left To Right","Copy Right To Left","Clear Left","Clear Right","Collapse To One","Collapse Left","Shift Left","Shift Right" ),
MenuRow( ScreenEdit::tempo, "Tempo", true, EDIT_MODE_FULL, 0, "Compress 2x","Compress 3->2","Compress 4->3","Expand 3->4","Expand 2->3","Expand 2x" ),
MenuRow( ScreenEdit::play, "Play selection", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::record, "Record in selection", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::insert_and_shift, "Insert beat and shift down", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::delete_and_shift, "Delete beat and shift up", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::shift_pauses_forward, "Shift pauses and BPM changes down",true, EDIT_MODE_FULL, 0, NULL ),
MenuRow( ScreenEdit::shift_pauses_backward, "Shift pauses and BPM changes up", true, EDIT_MODE_FULL, 0, NULL ),
MenuRow( ScreenEdit::convert_beat_to_pause, "Convert beats to pause", true, EDIT_MODE_FULL, 0, NULL ),
MenuRow( ScreenEdit::convert_pause_to_beat, "Convert pause to beats", true, EDIT_MODE_FULL, 0, NULL ),
MenuRow( ScreenEdit::undo, "Undo", true, EDIT_MODE_PRACTICE, 0, NULL )
2005-03-20 06:41:56 +00:00
);
2005-03-20 20:13:27 +00:00
static Menu g_StepsInformation(
"ScreenMiniMenuStepsInformation",
2005-04-16 04:55:50 +00:00
MenuRow( ScreenEdit::difficulty, "Difficulty", true, EDIT_MODE_PRACTICE, 0, NULL ),
2005-04-14 06:34:17 +00:00
MenuRow( ScreenEdit::meter, "Meter", true, EDIT_MODE_PRACTICE, 0, "1","2","3","4","5","6","7","8","9","10","11","12","13" ),
MenuRow( ScreenEdit::description, "Description", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::predict_meter, "Predicted Meter", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::tap_notes, "Tap Steps", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::jumps, "Jumps", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::hands, "Hands", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::quads, "Quads", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::holds, "Holds", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::mines, "Mines", false, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::stream, "Stream", false, EDIT_MODE_FULL, 0, NULL ),
MenuRow( ScreenEdit::voltage, "Voltage", false, EDIT_MODE_FULL, 0, NULL ),
MenuRow( ScreenEdit::air, "Air", false, EDIT_MODE_FULL, 0, NULL ),
MenuRow( ScreenEdit::freeze, "Freeze", false, EDIT_MODE_FULL, 0, NULL ),
MenuRow( ScreenEdit::chaos, "Chaos", false, EDIT_MODE_FULL, 0, NULL )
2005-03-20 06:41:56 +00:00
);
2005-03-20 20:13:27 +00:00
static Menu g_SongInformation(
"ScreenMiniMenuSongInfomation",
2005-04-14 06:34:17 +00:00
MenuRow( ScreenEdit::main_title, "Main title", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::sub_title, "Sub title", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::artist, "Artist", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::credit, "Credit", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::main_title_transliteration, "Main title transliteration", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::sub_title_transliteration, "Sub title transliteration", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::artist_transliteration, "Artist transliteration", true, EDIT_MODE_PRACTICE, 0, NULL )
2005-03-20 06:41:56 +00:00
);
static Menu g_BackgroundChange(
"ScreenMiniMenuBackgroundChange",
2005-04-14 06:34:17 +00:00
MenuRow( ScreenEdit::rate, "Rate (applies to new adds)", true, EDIT_MODE_PRACTICE, 10, "0%","10%","20%","30%","40%","50%","60%","70%","80%","90%","100%","120%","140%","160%","180%","200%" ),
MenuRow( ScreenEdit::fade_last, "Fade Last (applies to new adds)", true, EDIT_MODE_PRACTICE, 0, "NO","YES" ),
MenuRow( ScreenEdit::rewind_movie, "Rewind Movie (applies to new adds)", true, EDIT_MODE_PRACTICE, 0, "NO","YES" ),
MenuRow( ScreenEdit::loop, "Loop (applies to new adds)", true, EDIT_MODE_PRACTICE, 1, "NO","YES" ),
MenuRow( ScreenEdit::add_random, "Add Change to random", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::add_song_bganimation, "Add Change to song BGAnimation", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::add_song_movie, "Add Change to song Movie", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::add_song_still, "Add Change to song Still", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::add_global_random_movie, "Add Change to global Random Movie", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::add_global_bganimation, "Add Change to global BGAnimation", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::add_global_visualization, "Add Change to global Visualization", true, EDIT_MODE_PRACTICE, 0, NULL ),
MenuRow( ScreenEdit::delete_change, "Remove Change", true, EDIT_MODE_PRACTICE, 0, NULL )
2005-03-20 06:41:56 +00:00
);
static Menu g_Prefs(
"ScreenMiniMenuPreferences",
2005-04-14 06:34:17 +00:00
MenuRow( ScreenEdit::pref_show_bgs_play, "Show BGChanges during Play/Record", true, EDIT_MODE_PRACTICE, 0, "NO","YES" )
2005-03-20 06:41:56 +00:00
);
static Menu g_InsertAttack(
"ScreenMiniMenuInsertAttack",
2005-04-14 06:34:17 +00:00
MenuRow( -1, "Duration seconds", true, EDIT_MODE_PRACTICE, 3, "5","10","15","20","25","30","35","40","45" ),
MenuRow( -1, "Set modifiers", true, EDIT_MODE_PRACTICE, 0, "PRESS START" )
2005-03-20 06:41:56 +00:00
);
static Menu g_CourseMode(
"ScreenMiniMenuCourseDisplay",
2005-04-14 06:34:17 +00:00
MenuRow( -1, "Play mods from course", true, EDIT_MODE_PRACTICE, 0, NULL )
2005-03-20 06:41:56 +00:00
);
2004-01-26 20:56:58 +00:00
2003-11-12 08:13:02 +00:00
// HACK: need to remember the track we're inserting on so
// that we can lay the attack note after coming back from
// menus.
int g_iLastInsertAttackTrack = -1;
2003-11-12 08:32:32 +00:00
float g_fLastInsertAttackDurationSeconds = -1;
2003-11-12 08:13:02 +00:00
2004-11-26 17:28:47 +00:00
REGISTER_SCREEN_CLASS( ScreenEdit );
ScreenEdit::ScreenEdit( CString sName ) : ScreenWithMenuElements( sName )
2002-05-20 08:59:37 +00:00
{
LOG->Trace( "ScreenEdit::ScreenEdit()" );
2005-02-28 20:12:47 +00:00
2005-03-12 23:27:48 +00:00
PREV_SCREEN.Load( sName, "PrevScreen" );
2005-02-28 20:12:47 +00:00
ASSERT( GAMESTATE->m_pCurSong );
ASSERT( GAMESTATE->m_pCurSteps[0] );
}
void ScreenEdit::Init()
{
ScreenWithMenuElements::Init();
2002-05-20 08:59:37 +00:00
InitEditMappings();
2003-12-18 08:53:38 +00:00
/* We do this ourself. */
SOUND->HandleSongTimer( false );
2005-03-08 21:19:17 +00:00
// save the originals for reverting later
CopyToLastSave();
m_CurrentAction = MAIN_MENU_CHOICE_INVALID;
2005-03-08 21:19:17 +00:00
2002-08-17 06:44:04 +00:00
// set both players to joined so the credit message doesn't show
FOREACH_PlayerNumber( p )
2002-08-20 21:00:56 +00:00
GAMESTATE->m_bSideIsJoined[p] = true;
2002-08-17 06:44:04 +00:00
SCREENMAN->RefreshCreditsMessages();
2002-07-23 01:41:40 +00:00
m_pSong = GAMESTATE->m_pCurSong;
2004-05-24 06:12:17 +00:00
m_pSteps = GAMESTATE->m_pCurSteps[PLAYER_1];
2004-01-26 20:56:58 +00:00
m_pAttacksFromCourse = NULL;
2002-05-20 08:59:37 +00:00
2002-07-03 03:13:13 +00:00
2004-02-01 02:05:09 +00:00
GAMESTATE->m_bPastHereWeGo = false;
2002-07-28 20:28:37 +00:00
GAMESTATE->m_bEditing = true;
GAMESTATE->m_fSongBeat = 0;
m_fTrailingBeat = GAMESTATE->m_fSongBeat;
2002-08-01 13:42:56 +00:00
2003-08-09 19:00:52 +00:00
/* Not all games have a noteskin named "note" ... */
if( NOTESKIN->DoesNoteSkinExist("note") )
m_PlayerStateEdit.m_PlayerOptions.m_sNoteSkin = "note"; // change noteskin before loading all of the edit Actors
m_PlayerStateEdit.m_PlayerNumber = PLAYER_1;
m_PlayerStateEdit.m_PlayerOptions.m_sNoteSkin = GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerOptions.m_sNoteSkin;
m_PlayerStateEdit.ResetNoteSkins();
GAMESTATE->ResetNoteSkins();
GAMESTATE->StoreSelectedOptions();
2002-05-20 08:59:37 +00:00
g_iShiftAnchor = -1;
2003-09-21 23:16:44 +00:00
2005-04-14 06:34:17 +00:00
m_EditState = STATE_INVALID;
TransitionEditState( STATE_EDITING );
2005-03-18 19:44:01 +00:00
this->AddChild( &m_Background );
2003-09-21 23:16:44 +00:00
m_SnapDisplay.SetXY( EDIT_X, PLAYER_Y_STANDARD );
2002-08-17 06:44:04 +00:00
m_SnapDisplay.Load( PLAYER_1 );
m_SnapDisplay.SetZoom( 0.5f );
2005-03-18 19:44:01 +00:00
this->AddChild( &m_SnapDisplay );
2002-05-20 08:59:37 +00:00
NoteData noteData;
m_pSteps->GetNoteData( noteData );
m_NoteDataEdit.CopyAll( noteData );
2005-04-07 19:27:53 +00:00
m_NoteFieldEdit.SetXY( EDIT_X, EDIT_Y );
2005-03-18 19:44:01 +00:00
m_NoteFieldEdit.SetZoom( 0.5f );
m_NoteFieldEdit.Init( &m_PlayerStateEdit, PLAYER_HEIGHT*2 );
m_NoteFieldEdit.Load( &m_NoteDataEdit, -240, 800 );
2005-03-18 19:44:01 +00:00
this->AddChild( &m_NoteFieldEdit );
2002-05-20 08:59:37 +00:00
m_NoteDataRecord.CopyAll( noteData );
2005-04-07 19:27:53 +00:00
m_NoteFieldRecord.SetXY( RECORD_X, RECORD_Y );
m_NoteFieldRecord.Init( GAMESTATE->m_pPlayerState[PLAYER_1], 10 );
2005-04-08 20:59:03 +00:00
m_NoteFieldRecord.Load( &m_NoteDataRecord, -(int)SCREEN_HEIGHT/2, (int)SCREEN_HEIGHT/2 );
2005-03-18 19:44:01 +00:00
this->AddChild( &m_NoteFieldRecord );
2002-07-02 00:27:58 +00:00
m_Clipboard.SetNumTracks( m_NoteDataEdit.GetNumTracks() );
2002-05-20 08:59:37 +00:00
m_bHasUndo = false;
2005-03-23 10:43:57 +00:00
m_Undo.SetNumTracks( m_NoteDataEdit.GetNumTracks() );
2003-02-19 06:27:20 +00:00
2004-01-24 20:36:09 +00:00
/* XXX: Do we actually have to send real note data here, and to m_NoteFieldRecord?
* (We load again on play/record.) */
2005-02-26 05:59:12 +00:00
m_Player.Init( "Player", GAMESTATE->m_pPlayerState[PLAYER_1], NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
m_Player.Load( noteData );
GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerController = PC_HUMAN;
2004-12-01 04:02:00 +00:00
m_Player.SetXY( PLAYER_X, PLAYER_Y );
2005-03-18 19:44:01 +00:00
this->AddChild( &m_Player );
this->AddChild( &m_Foreground );
2002-05-20 08:59:37 +00:00
2005-03-20 07:11:23 +00:00
m_textInputTips.SetName( "InputTips" );
2005-03-20 07:22:55 +00:00
m_textInputTips.LoadFromFont( THEME->GetPathF("ScreenEdit","InputTips") );
2005-03-20 07:11:23 +00:00
m_textInputTips.SetText( INPUT_TIPS_TEXT );
SET_XY_AND_ON_COMMAND( m_textInputTips );
this->AddChild( &m_textInputTips );
m_textInfo.SetName( "Info" );
2005-03-20 07:22:55 +00:00
m_textInfo.LoadFromFont( THEME->GetPathF("ScreenEdit","Info") );
2005-03-20 07:11:23 +00:00
SET_XY_AND_ON_COMMAND( m_textInfo );
2005-03-18 19:44:01 +00:00
this->AddChild( &m_textInfo );
m_textPlayRecordHelp.SetName( "PlayRecordHelp" );
m_textPlayRecordHelp.LoadFromFont( THEME->GetPathF("ScreenEdit","PlayRecordHelp") );
m_textPlayRecordHelp.SetText( PLAY_RECORD_HELP_TEXT );
SET_XY_AND_ON_COMMAND( m_textPlayRecordHelp );
this->AddChild( &m_textPlayRecordHelp );
2005-03-18 19:44:01 +00:00
this->SortByDrawOrder();
2002-06-29 11:59:09 +00:00
2005-03-23 10:43:57 +00:00
m_soundAddNote.Load( THEME->GetPathS("ScreenEdit","AddNote"), true );
2005-03-22 13:38:18 +00:00
m_soundRemoveNote.Load( THEME->GetPathS("ScreenEdit","RemoveNote"), true );
2005-03-18 19:44:01 +00:00
m_soundChangeLine.Load( THEME->GetPathS("ScreenEdit","line"), true );
m_soundChangeSnap.Load( THEME->GetPathS("ScreenEdit","snap"), true );
m_soundMarker.Load( THEME->GetPathS("ScreenEdit","marker"), true );
2005-03-21 03:02:47 +00:00
m_soundSwitch.Load( THEME->GetPathS("ScreenEdit","switch") );
m_soundSave.Load( THEME->GetPathS("ScreenEdit","save") );
2002-05-20 08:59:37 +00:00
2002-06-29 11:59:09 +00:00
2005-01-15 18:33:09 +00:00
m_soundMusic.Load( m_pSong->GetMusicPath() );
2002-05-20 08:59:37 +00:00
2005-03-18 19:44:01 +00:00
m_soundAssistTick.Load( THEME->GetPathS("ScreenEdit","assist tick"), true );
2005-04-01 08:34:23 +00:00
this->HandleScreenMessage( SM_UpdateTextInfo );
m_bTextInfoNeedsUpdate = true;
2002-05-20 08:59:37 +00:00
}
ScreenEdit::~ScreenEdit()
{
// UGLY: Don't delete the Song's steps.
m_songLastSave.DetachSteps();
LOG->Trace( "ScreenEdit::~ScreenEdit()" );
m_soundMusic.StopPlaying();
2002-05-20 08:59:37 +00:00
}
// play assist ticks
2004-01-12 09:36:01 +00:00
void ScreenEdit::PlayTicks()
{
2005-04-14 06:34:17 +00:00
if( !GAMESTATE->m_SongOptions.m_bAssistTick || m_EditState != STATE_PLAYING )
2004-01-12 09:36:01 +00:00
return;
/* Sound cards have a latency between when a sample is Play()ed and when the sound
* will start coming out the speaker. Compensate for this by boosting fPositionSeconds
* ahead. This is just to make sure that we request the sound early enough for it to
* come out on time; the actual precise timing is handled by SetStartTime. */
float fPositionSeconds = GAMESTATE->m_fMusicSeconds;
2004-01-12 09:36:01 +00:00
fPositionSeconds += SOUND->GetPlayLatency() + (float)TICK_EARLY_SECONDS + 0.250f;
const float fSongBeat = GAMESTATE->m_pCurSong->GetBeatFromElapsedTime( fPositionSeconds );
2004-01-12 09:36:01 +00:00
const int iSongRow = max( 0, BeatToNoteRowNotRounded( fSongBeat ) );
2004-04-04 04:12:26 +00:00
static int iRowLastCrossed = -1;
if( iSongRow < iRowLastCrossed )
2004-06-06 05:28:58 +00:00
iRowLastCrossed = iSongRow;
2004-01-12 09:36:01 +00:00
int iTickRow = -1;
2004-12-03 23:50:20 +00:00
// for each index we crossed since the last update:
2005-01-31 19:12:30 +00:00
FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( m_Player.m_NoteData, r, iRowLastCrossed+1, iSongRow+1 )
2004-10-23 17:43:49 +00:00
if( m_Player.m_NoteData.IsThereATapOrHoldHeadAtRow( r ) )
2004-01-12 09:36:01 +00:00
iTickRow = r;
2004-01-12 09:36:01 +00:00
iRowLastCrossed = iSongRow;
2004-01-12 09:36:01 +00:00
if( iTickRow != -1 )
{
const float fTickBeat = NoteRowToBeat( iTickRow );
const float fTickSecond = GAMESTATE->m_pCurSong->m_Timing.GetElapsedTimeFromBeat( fTickBeat );
float fSecondsUntil = fTickSecond - GAMESTATE->m_fMusicSeconds;
fSecondsUntil /= m_soundMusic.GetPlaybackRate(); /* 2x music rate means the time until the tick is halved */
RageSoundParams p;
2004-04-04 04:11:43 +00:00
p.StartTime = GAMESTATE->m_LastBeatUpdate + (fSecondsUntil - (float)TICK_EARLY_SECONDS);
m_soundAssistTick.Play( &p );
2004-01-12 09:36:01 +00:00
}
}
2002-05-20 08:59:37 +00:00
2003-03-05 02:38:17 +00:00
void ScreenEdit::PlayPreviewMusic()
{
2003-07-26 22:53:22 +00:00
SOUND->PlayMusic("");
2004-04-04 05:39:10 +00:00
SOUND->PlayMusic( m_pSong->GetMusicPath(), false,
2003-03-05 02:38:17 +00:00
m_pSong->m_fMusicSampleStartSeconds,
m_pSong->m_fMusicSampleLengthSeconds,
1.5f );
}
2002-05-20 08:59:37 +00:00
void ScreenEdit::Update( float fDeltaTime )
{
m_PlayerStateEdit.Update( fDeltaTime );
2004-01-18 06:57:59 +00:00
if( m_soundMusic.IsPlaying() )
{
RageTimer tm;
const float fSeconds = m_soundMusic.GetPositionSeconds( NULL, &tm );
GAMESTATE->UpdateSongPosition( fSeconds, GAMESTATE->m_pCurSong->m_Timing, tm );
}
2005-04-14 06:34:17 +00:00
if( m_EditState == STATE_RECORDING )
2002-10-18 19:01:32 +00:00
{
// add or extend holds
2004-06-28 07:26:00 +00:00
for( int t=0; t<GAMESTATE->GetCurrentStyle()->m_iColsPerPlayer; t++ ) // for each track
2002-10-18 19:01:32 +00:00
{
StyleInput StyleI( PLAYER_1, t );
float fSecsHeld = INPUTMAPPER->GetSecsHeld( StyleI );
if( fSecsHeld > RECORD_HOLD_SECONDS && GAMESTATE->m_fSongBeat > 0 )
2002-10-18 19:01:32 +00:00
{
// add or extend hold
const float fHoldStartSeconds = m_soundMusic.GetPositionSeconds() - fSecsHeld;
float fStartBeat = max( 0, m_pSong->GetBeatFromElapsedTime( fHoldStartSeconds ) );
float fEndBeat = max( fStartBeat, GAMESTATE->m_fSongBeat );
2002-10-18 19:01:32 +00:00
// Round hold start and end to the nearest snap interval
2004-10-24 17:44:51 +00:00
fStartBeat = Quantize( fStartBeat, NoteTypeToBeat(m_SnapDisplay.GetNoteType()) );
fEndBeat = Quantize( fEndBeat, NoteTypeToBeat(m_SnapDisplay.GetNoteType()) );
2002-10-18 19:01:32 +00:00
// create a new hold note
2005-01-25 05:02:35 +00:00
m_NoteDataRecord.AddHoldNote( t, BeatToNoteRow(fStartBeat), BeatToNoteRow(fEndBeat), TAP_ORIGINAL_HOLD_HEAD );
2002-10-18 19:01:32 +00:00
}
}
}
2005-04-14 06:34:17 +00:00
if( m_EditState == STATE_RECORDING || m_EditState == STATE_PLAYING )
2002-05-20 08:59:37 +00:00
{
// check for end of playback/record
2002-05-20 08:59:37 +00:00
if( GAMESTATE->m_fSongBeat > NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker) + 4 ) // give a one measure lead out
2002-05-20 08:59:37 +00:00
{
2005-04-14 06:34:17 +00:00
TransitionEditState( STATE_EDITING );
GAMESTATE->m_fSongBeat = NoteRowToBeat( m_NoteFieldEdit.m_iEndMarker );
2002-05-20 08:59:37 +00:00
}
}
//LOG->Trace( "ScreenEdit::Update(%f)", fDeltaTime );
ScreenWithMenuElements::Update( fDeltaTime );
2002-05-20 08:59:37 +00:00
2002-06-29 11:59:09 +00:00
// Update trailing beat
float fDelta = GAMESTATE->m_fSongBeat - m_fTrailingBeat;
2005-02-03 03:39:15 +00:00
if( fabsf(fDelta) < 10 )
fapproach( m_fTrailingBeat, GAMESTATE->m_fSongBeat,
fDeltaTime*40 / m_PlayerStateEdit.m_CurrentPlayerOptions.m_fScrollSpeed );
2002-06-29 11:59:09 +00:00
else
2005-02-03 03:39:15 +00:00
fapproach( m_fTrailingBeat, GAMESTATE->m_fSongBeat,
fabsf(fDelta) * fDeltaTime*5 );
2002-05-20 08:59:37 +00:00
2004-01-12 09:36:01 +00:00
PlayTicks();
}
void ScreenEdit::UpdateTextInfo()
{
if( m_pSteps == NULL )
return;
2005-04-01 08:34:23 +00:00
// Don't update the text during playback or record. It causes skips.
2005-04-14 06:34:17 +00:00
if( m_EditState != STATE_EDITING )
2005-04-01 08:34:23 +00:00
return;
if( !m_bTextInfoNeedsUpdate )
return;
m_bTextInfoNeedsUpdate = false;
2005-03-20 11:35:45 +00:00
int iNumTaps = m_NoteDataEdit.GetNumTapNotes();
2005-03-20 20:13:27 +00:00
int iNumJumps = m_NoteDataEdit.GetNumJumps();
2005-03-20 11:35:45 +00:00
int iNumHands = m_NoteDataEdit.GetNumHands();
int iNumHolds = m_NoteDataEdit.GetNumHoldNotes();
2005-03-20 09:52:48 +00:00
int iNumMines = m_NoteDataEdit.GetNumMines();
2005-01-15 13:05:33 +00:00
CString sNoteType = NoteTypeToString(m_SnapDisplay.GetNoteType()) + " notes";
2002-05-20 08:59:37 +00:00
CString sText;
2005-03-20 11:35:45 +00:00
sText += ssprintf( "Current beat:\n %.3f\n", GAMESTATE->m_fSongBeat );
sText += ssprintf( "Current sec:\n %.3f\n", m_pSong->GetElapsedTimeFromBeat(GAMESTATE->m_fSongBeat) );
2005-04-16 20:43:26 +00:00
if( EDIT_MODE >= EDIT_MODE_HOME )
sText += ssprintf( "Snap to:\n %s\n", sNoteType.c_str() );
2005-03-20 11:35:45 +00:00
sText += ssprintf( "Selection beat:\n %s\n %s\n", m_NoteFieldEdit.m_iBeginMarker==-1 ? "----" : ssprintf("%.3f",NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker)).c_str(), m_NoteFieldEdit.m_iEndMarker==-1 ? "----" : ssprintf("%.3f",NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker)).c_str() );
2005-04-14 06:34:17 +00:00
if( EDIT_MODE == EDIT_MODE_FULL )
2005-03-20 09:52:48 +00:00
{
2005-04-14 06:34:17 +00:00
sText += ssprintf( "Difficulty:\n %s\n", DifficultyToString( m_pSteps->GetDifficulty() ).c_str() );
2005-03-20 11:35:45 +00:00
sText += ssprintf( "Description:\n %s\n", GAMESTATE->m_pCurSteps[PLAYER_1] ? GAMESTATE->m_pCurSteps[PLAYER_1]->GetDescription().c_str() : "no description" );
sText += ssprintf( "Main title:\n %s\n", m_pSong->m_sMainTitle.c_str() );
sText += ssprintf( "Sub title:\n %s\n", m_pSong->m_sSubTitle.c_str() );
2005-03-20 09:52:48 +00:00
}
2005-03-20 11:35:45 +00:00
sText += ssprintf( "Tap steps:\n %d\n", iNumTaps );
sText += ssprintf( "Jumps:\n %d\n", iNumJumps );
sText += ssprintf( "Hands:\n %d\n", iNumHands );
sText += ssprintf( "Holds:\n %d\n", iNumHolds );
sText += ssprintf( "Mines:\n %d\n", iNumMines );
2005-04-14 06:34:17 +00:00
if( EDIT_MODE == EDIT_MODE_FULL )
{
2005-03-20 11:35:45 +00:00
sText += ssprintf( "Beat 0 Offset:\n %.3f secs\n", m_pSong->m_Timing.m_fBeat0OffsetInSeconds );
sText += ssprintf( "Preview Start:\n %.2f secs\n", m_pSong->m_fMusicSampleStartSeconds );
sText += ssprintf( "Preview Length:\n %.2f secs\n",m_pSong->m_fMusicSampleLengthSeconds );
2005-04-14 06:34:17 +00:00
}
m_textInfo.SetText( sText );
2002-05-20 08:59:37 +00:00
}
void ScreenEdit::DrawPrimitives()
{
2005-03-18 19:44:01 +00:00
// HACK: Draw using the trailing beat
float fSongBeat = GAMESTATE->m_fSongBeat; // save song beat
GAMESTATE->m_fSongBeat = m_fTrailingBeat; // put trailing beat in effect
2002-05-20 08:59:37 +00:00
ScreenWithMenuElements::DrawPrimitives();
2005-03-18 19:44:01 +00:00
GAMESTATE->m_fSongBeat = fSongBeat; // restore real song beat
2002-05-20 08:59:37 +00:00
}
void ScreenEdit::Input( const DeviceInput& DeviceI, const InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI )
{
2003-02-25 00:33:42 +00:00
// LOG->Trace( "ScreenEdit::Input()" );
2002-05-20 08:59:37 +00:00
if( m_In.IsTransitioning() || m_Out.IsTransitioning() )
return;
const DeviceInput& di = DeviceI;
2004-10-28 07:56:13 +00:00
EditButton EditB;
DeviceToEdit( di, EditB );
2005-04-14 06:34:17 +00:00
switch( m_EditState )
2002-05-20 08:59:37 +00:00
{
2005-04-14 06:34:17 +00:00
case STATE_EDITING:
InputEdit( di, type, GameI, MenuI, StyleI, EditB );
2005-04-01 08:34:23 +00:00
m_bTextInfoNeedsUpdate = true;
break;
2005-04-14 06:34:17 +00:00
case STATE_RECORDING:
InputRecord( di, type, GameI, MenuI, StyleI, EditB );
break;
2005-04-14 06:34:17 +00:00
case STATE_PLAYING:
InputPlay( di, type, GameI, MenuI, StyleI, EditB );
break;
2002-08-17 06:44:04 +00:00
default: ASSERT(0);
2002-05-20 08:59:37 +00:00
}
}
2005-03-24 23:03:12 +00:00
static void ShiftToRightSide( int &iCol, int iNumTracks )
{
switch( GAMESTATE->GetCurrentStyle()->m_StyleType )
{
case ONE_PLAYER_ONE_SIDE:
break;
case TWO_PLAYERS_TWO_SIDES:
case ONE_PLAYER_TWO_SIDES:
iCol += iNumTracks/2;
break;
default:
ASSERT(0);
}
}
2003-09-07 22:28:46 +00:00
void ScreenEdit::InputEdit( const DeviceInput& DeviceI, const InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI, EditButton EditB )
2002-05-20 08:59:37 +00:00
{
2004-09-09 22:21:50 +00:00
if( type == IET_LEVEL_CHANGED )
return; // don't care
2005-01-15 18:33:09 +00:00
if( type == IET_RELEASE )
{
2005-01-23 23:49:19 +00:00
if( EditPressed( EDIT_BUTTON_SCROLL_SELECT, DeviceI ) )
g_iShiftAnchor = -1;
return;
}
const int iSongBeat = BeatToNoteRow(GAMESTATE->m_fSongBeat);
switch( EditB )
2002-05-20 08:59:37 +00:00
{
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:
2002-05-20 08:59:37 +00:00
{
2002-08-17 06:44:04 +00:00
if( type != IET_FIRST_PRESS )
break; // We only care about first presses
2002-05-20 08:59:37 +00:00
int iCol = EditB - EDIT_BUTTON_COLUMN_0;
2003-08-31 23:52:02 +00:00
// Alt + number = input to right half
if( EditIsBeingPressed(EDIT_BUTTON_RIGHT_SIDE) )
2005-03-24 23:03:12 +00:00
ShiftToRightSide( iCol, m_NoteDataEdit.GetNumTracks() );
2003-08-31 23:52:02 +00:00
2003-04-26 06:06:24 +00:00
2002-08-17 06:44:04 +00:00
const float fSongBeat = GAMESTATE->m_fSongBeat;
const int iSongIndex = BeatToNoteRow( fSongBeat );
2002-05-20 08:59:37 +00:00
if( iCol >= m_NoteDataEdit.GetNumTracks() ) // this button is not in the range of columns for this Style
2002-08-17 06:44:04 +00:00
break;
2002-05-20 08:59:37 +00:00
2002-08-17 06:44:04 +00:00
// check for to see if the user intended to remove a HoldNote
2005-03-22 13:38:18 +00:00
int iHeadRow;
if( m_NoteDataEdit.IsHoldNoteAtBeat( iCol, iSongIndex, &iHeadRow ) )
2002-08-17 06:44:04 +00:00
{
2005-03-22 13:38:18 +00:00
m_soundRemoveNote.Play();
2005-03-23 10:43:57 +00:00
SaveUndo();
m_NoteDataEdit.SetTapNote( iCol, iHeadRow, TAP_EMPTY );
// Don't CheckNumberOfNotesAndUndo. We don't want to revert any change that removes notes.
2002-05-20 08:59:37 +00:00
}
2005-03-22 13:38:18 +00:00
else if( m_NoteDataEdit.GetTapNote(iCol, iSongIndex).type != TapNote::empty )
2003-11-15 08:51:47 +00:00
{
2005-03-22 13:38:18 +00:00
m_soundRemoveNote.Play();
2005-03-23 10:43:57 +00:00
SaveUndo();
m_NoteDataEdit.SetTapNote( iCol, iSongIndex, TAP_EMPTY );
// Don't CheckNumberOfNotesAndUndo. We don't want to revert any change that removes notes.
2003-11-15 08:51:47 +00:00
}
2005-01-21 06:47:50 +00:00
else if( EditIsBeingPressed(EDIT_BUTTON_LAY_MINE) )
2003-11-15 08:51:47 +00:00
{
2005-03-22 13:38:18 +00:00
m_soundAddNote.Play();
2005-03-23 10:43:57 +00:00
SaveUndo();
m_NoteDataEdit.SetTapNote(iCol, iSongIndex, TAP_ORIGINAL_MINE );
CheckNumberOfNotesAndUndo();
2003-11-15 08:51:47 +00:00
}
2005-01-21 06:47:50 +00:00
else if( EditIsBeingPressed(EDIT_BUTTON_LAY_ATTACK) )
2003-11-15 08:51:47 +00:00
{
g_iLastInsertAttackTrack = iCol;
SCREENMAN->MiniMenu( &g_InsertAttack, SM_BackFromInsertAttack );
}
else
{
2005-03-22 13:38:18 +00:00
m_soundAddNote.Play();
2005-03-23 10:43:57 +00:00
SaveUndo();
m_NoteDataEdit.SetTapNote(iCol, iSongIndex, TAP_ORIGINAL_TAP );
CheckNumberOfNotesAndUndo();
2003-11-15 08:51:47 +00:00
}
2002-08-17 06:44:04 +00:00
}
break;
case EDIT_BUTTON_SCROLL_SPEED_UP:
case EDIT_BUTTON_SCROLL_SPEED_DOWN:
2002-08-17 06:44:04 +00:00
{
float& fScrollSpeed = m_PlayerStateEdit.m_PlayerOptions.m_fScrollSpeed;
float fNewScrollSpeed = fScrollSpeed;
2005-03-27 00:32:20 +00:00
if( EditB == EDIT_BUTTON_SCROLL_SPEED_DOWN )
{
if( fScrollSpeed == 4 )
fNewScrollSpeed = 2;
else if( fScrollSpeed == 2 )
fNewScrollSpeed = 1;
}
2005-03-27 00:32:20 +00:00
else if( EditB == EDIT_BUTTON_SCROLL_SPEED_UP )
{
if( fScrollSpeed == 2 )
fNewScrollSpeed = 4;
else if( fScrollSpeed == 1 )
fNewScrollSpeed = 2;
}
2004-03-07 03:49:28 +00:00
if( fNewScrollSpeed != fScrollSpeed )
{
fScrollSpeed = fNewScrollSpeed;
m_soundMarker.Play();
2003-02-18 23:15:38 +00:00
}
break;
}
2003-02-18 23:15:38 +00:00
break;
case EDIT_BUTTON_SCROLL_UP_LINE:
case EDIT_BUTTON_SCROLL_UP_PAGE:
case EDIT_BUTTON_SCROLL_DOWN_LINE:
case EDIT_BUTTON_SCROLL_DOWN_PAGE:
case EDIT_BUTTON_SCROLL_HOME:
case EDIT_BUTTON_SCROLL_END:
{
2002-09-07 10:33:44 +00:00
float fBeatsToMove=0.f;
switch( EditB )
2002-05-20 08:59:37 +00:00
{
case EDIT_BUTTON_SCROLL_UP_LINE:
case EDIT_BUTTON_SCROLL_DOWN_LINE:
2002-10-18 19:01:32 +00:00
fBeatsToMove = NoteTypeToBeat( m_SnapDisplay.GetNoteType() );
if( EditB == EDIT_BUTTON_SCROLL_UP_LINE )
2002-08-17 06:44:04 +00:00
fBeatsToMove *= -1;
break;
case EDIT_BUTTON_SCROLL_UP_PAGE:
case EDIT_BUTTON_SCROLL_DOWN_PAGE:
2002-08-17 06:44:04 +00:00
fBeatsToMove = BEATS_PER_MEASURE;
if( EditB == EDIT_BUTTON_SCROLL_UP_PAGE )
2002-08-17 06:44:04 +00:00
fBeatsToMove *= -1;
break;
case EDIT_BUTTON_SCROLL_HOME:
fBeatsToMove = -GAMESTATE->m_fSongBeat;
break;
case EDIT_BUTTON_SCROLL_END:
fBeatsToMove = m_NoteDataEdit.GetLastBeat() - GAMESTATE->m_fSongBeat;
break;
2002-08-17 06:44:04 +00:00
}
const float fOriginalBeat = GAMESTATE->m_fSongBeat;
float fDestinationBeat = GAMESTATE->m_fSongBeat + fBeatsToMove;
fDestinationBeat = Quantize( fDestinationBeat, NoteTypeToBeat(m_SnapDisplay.GetNoteType()) );
CLAMP( fDestinationBeat, 0, GetMaximumBeatForMoving() );
// Don't play the sound and do the hold note logic below if our position didn't change.
if( fOriginalBeat == fDestinationBeat )
return;
GAMESTATE->m_fSongBeat = fDestinationBeat;
2002-05-20 08:59:37 +00:00
2002-08-17 06:44:04 +00:00
// check to see if they're holding a button
for( int n=0; n<NUM_EDIT_BUTTON_COLUMNS; n++ )
2002-08-17 06:44:04 +00:00
{
2003-08-31 23:52:02 +00:00
int iCol = n;
// Ctrl + number = input to right half
if( EditIsBeingPressed(EDIT_BUTTON_RIGHT_SIDE) )
2005-03-24 23:03:12 +00:00
ShiftToRightSide( iCol, m_NoteDataEdit.GetNumTracks() );
2003-08-31 23:52:02 +00:00
if( iCol >= m_NoteDataEdit.GetNumTracks() )
2003-08-31 23:52:02 +00:00
continue; // skip
EditButton b = EditButton(EDIT_BUTTON_COLUMN_0+n);
if( !EditIsBeingPressed(b) )
continue;
// create a new hold note
int iStartRow = BeatToNoteRow( min(fOriginalBeat, fDestinationBeat) );
int iEndRow = BeatToNoteRow( max(fOriginalBeat, fDestinationBeat) );
2005-03-23 10:43:57 +00: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.
m_NoteDataEdit.AddHoldNote( iCol, iStartRow, iEndRow, TAP_ORIGINAL_HOLD_HEAD );
}
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( g_iShiftAnchor == -1 )
g_iShiftAnchor = BeatToNoteRow(fOriginalBeat);
if( iDestinationRow == g_iShiftAnchor )
{
/* We're back at the anchor, so we have nothing selected. */
m_NoteFieldEdit.m_iBeginMarker = m_NoteFieldEdit.m_iEndMarker = -1;
}
else
2002-05-20 08:59:37 +00:00
{
m_NoteFieldEdit.m_iBeginMarker = g_iShiftAnchor;
m_NoteFieldEdit.m_iEndMarker = iDestinationRow;
if( m_NoteFieldEdit.m_iBeginMarker > m_NoteFieldEdit.m_iEndMarker )
swap( m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker );
2002-05-20 08:59:37 +00:00
}
}
2002-08-17 06:44:04 +00:00
2002-06-29 11:59:09 +00:00
m_soundChangeLine.Play();
2002-08-17 06:44:04 +00:00
}
break;
case EDIT_BUTTON_SNAP_NEXT:
2004-08-13 02:41:19 +00:00
if( m_SnapDisplay.PrevSnapMode() )
OnSnapModeChange();
2002-08-17 06:44:04 +00:00
break;
case EDIT_BUTTON_SNAP_PREV:
2004-08-13 02:41:19 +00:00
if( m_SnapDisplay.NextSnapMode() )
OnSnapModeChange();
2002-08-17 06:44:04 +00:00
break;
case EDIT_BUTTON_LAY_SELECT:
if( m_NoteFieldEdit.m_iBeginMarker==-1 && m_NoteFieldEdit.m_iEndMarker==-1 )
2002-08-17 06:44:04 +00:00
{
2003-02-18 23:15:38 +00:00
// lay begin marker
m_NoteFieldEdit.m_iBeginMarker = BeatToNoteRow(GAMESTATE->m_fSongBeat);
2002-08-17 06:44:04 +00:00
}
else if( m_NoteFieldEdit.m_iEndMarker==-1 ) // only begin marker is laid
2002-08-17 06:44:04 +00:00
{
if( iSongBeat == m_NoteFieldEdit.m_iBeginMarker )
2002-05-20 08:59:37 +00:00
{
m_NoteFieldEdit.m_iBeginMarker = -1;
2002-05-20 08:59:37 +00:00
}
else
{
m_NoteFieldEdit.m_iEndMarker = max( m_NoteFieldEdit.m_iBeginMarker, iSongBeat );
m_NoteFieldEdit.m_iBeginMarker = min( m_NoteFieldEdit.m_iBeginMarker, iSongBeat );
2002-05-20 08:59:37 +00:00
}
2002-08-17 06:44:04 +00:00
}
2003-02-18 23:15:38 +00:00
else // both markers are laid
2002-08-17 06:44:04 +00:00
{
m_NoteFieldEdit.m_iBeginMarker = iSongBeat;
m_NoteFieldEdit.m_iEndMarker = -1;
2002-08-17 06:44:04 +00:00
}
2003-02-18 23:15:38 +00:00
m_soundMarker.Play();
2002-08-17 06:44:04 +00:00
break;
case EDIT_BUTTON_OPEN_AREA_MENU:
2002-08-17 06:44:04 +00:00
{
2003-02-18 23:15:38 +00:00
// update enabled/disabled in g_AreaMenu
bool bAreaSelected = m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1;
2005-03-20 06:41:56 +00:00
g_AreaMenu.rows[cut].bEnabled = bAreaSelected;
g_AreaMenu.rows[copy].bEnabled = bAreaSelected;
g_AreaMenu.rows[paste_at_current_beat].bEnabled = !m_Clipboard.IsEmpty();
g_AreaMenu.rows[paste_at_begin_marker].bEnabled = !m_Clipboard.IsEmpty() != 0 && m_NoteFieldEdit.m_iBeginMarker!=-1;
2005-03-20 06:41:56 +00:00
g_AreaMenu.rows[clear].bEnabled = bAreaSelected;
g_AreaMenu.rows[quantize].bEnabled = bAreaSelected;
g_AreaMenu.rows[turn].bEnabled = bAreaSelected;
g_AreaMenu.rows[transform].bEnabled = bAreaSelected;
g_AreaMenu.rows[alter].bEnabled = bAreaSelected;
g_AreaMenu.rows[tempo].bEnabled = bAreaSelected;
g_AreaMenu.rows[play].bEnabled = bAreaSelected;
g_AreaMenu.rows[record].bEnabled = bAreaSelected;
g_AreaMenu.rows[convert_beat_to_pause].bEnabled = bAreaSelected;
g_AreaMenu.rows[undo].bEnabled = m_bHasUndo;
2003-02-18 23:15:38 +00:00
SCREENMAN->MiniMenu( &g_AreaMenu, SM_BackFromAreaMenu );
2002-08-17 06:44:04 +00:00
}
break;
case EDIT_BUTTON_OPEN_EDIT_MENU:
2003-02-18 23:15:38 +00:00
SCREENMAN->MiniMenu( &g_MainMenu, SM_BackFromMainMenu );
2002-08-17 06:44:04 +00:00
break;
case EDIT_BUTTON_OPEN_INPUT_HELP:
SCREENMAN->MiniMenu( &g_EditHelp, SM_None );
break;
case EDIT_BUTTON_TOGGLE_ASSIST_TICK:
2003-04-23 01:23:14 +00:00
GAMESTATE->m_SongOptions.m_bAssistTick ^= 1;
break;
case EDIT_BUTTON_OPEN_NEXT_STEPS:
case EDIT_BUTTON_OPEN_PREV_STEPS:
2003-08-24 05:12:08 +00:00
{
2005-03-23 10:43:57 +00:00
// don't keep undo when changing Steps
m_bHasUndo = false;
2005-03-23 10:43:57 +00:00
m_Undo.ClearAll();
2003-08-24 05:12:08 +00:00
// save current steps
2004-05-24 06:12:17 +00:00
Steps* pSteps = GAMESTATE->m_pCurSteps[PLAYER_1];
2004-05-24 03:41:39 +00:00
ASSERT( pSteps );
pSteps->SetNoteData( m_NoteDataEdit );
2003-08-24 05:12:08 +00:00
// Get all Steps of this StepsType
2004-05-24 03:41:39 +00:00
StepsType st = pSteps->m_StepsType;
2003-08-24 05:12:08 +00:00
vector<Steps*> vSteps;
GAMESTATE->m_pCurSong->GetSteps( vSteps, st );
2004-01-24 20:36:09 +00:00
// Sort them by difficulty.
StepsUtil::SortStepsByTypeAndDifficulty( vSteps );
2004-01-24 20:36:09 +00:00
2003-08-24 05:12:08 +00:00
// Find out what index the current Steps are
2004-05-24 03:41:39 +00:00
vector<Steps*>::iterator it = find( vSteps.begin(), vSteps.end(), pSteps );
2003-08-24 05:12:08 +00:00
ASSERT( it != vSteps.end() );
switch( EditB )
2003-08-24 05:12:08 +00:00
{
case EDIT_BUTTON_OPEN_PREV_STEPS:
2003-08-24 05:12:08 +00:00
if( it==vSteps.begin() )
{
SCREENMAN->PlayInvalidSound();
2003-08-24 05:12:08 +00:00
return;
}
it--;
break;
case EDIT_BUTTON_OPEN_NEXT_STEPS:
2003-08-24 05:12:08 +00:00
it++;
if( it==vSteps.end() )
{
SCREENMAN->PlayInvalidSound();
2003-08-24 05:12:08 +00:00
return;
}
break;
default: ASSERT(0); return;
}
2004-05-24 03:41:39 +00:00
pSteps = *it;
GAMESTATE->m_pCurSteps[PLAYER_1].Set( pSteps );
2005-02-25 05:27:28 +00:00
m_pSteps = pSteps;
pSteps->GetNoteData( m_NoteDataEdit );
2003-08-24 05:12:08 +00:00
SCREENMAN->SystemMessage( ssprintf(
"Switched to %s %s '%s'",
2004-07-12 02:19:24 +00:00
GAMEMAN->StepsTypeToString( pSteps->m_StepsType ).c_str(),
2004-05-24 03:41:39 +00:00
DifficultyToString( pSteps->GetDifficulty() ).c_str(),
pSteps->GetDescription().c_str() ) );
2005-03-21 03:02:47 +00:00
m_soundSwitch.Play();
2003-08-24 05:12:08 +00:00
}
break;
case EDIT_BUTTON_BPM_UP:
case EDIT_BUTTON_BPM_DOWN:
2002-08-17 06:44:04 +00:00
{
float fBPM = m_pSong->GetBPMAtBeat( GAMESTATE->m_fSongBeat );
float fDeltaBPM;
switch( EditB )
2002-05-20 08:59:37 +00:00
{
case EDIT_BUTTON_BPM_UP: fDeltaBPM = +0.020f; break;
case EDIT_BUTTON_BPM_DOWN: fDeltaBPM = -0.020f; break;
2002-09-07 10:31:35 +00:00
default: ASSERT(0); return;
2002-06-29 11:59:09 +00:00
}
if( EditIsBeingPressed( EDIT_BUTTON_ADJUST_FINE ) )
fDeltaBPM /= 2;
2003-06-17 06:24:13 +00:00
else switch( type )
2002-05-20 08:59:37 +00:00
{
2002-08-17 06:44:04 +00:00
case IET_SLOW_REPEAT: fDeltaBPM *= 10; break;
case IET_FAST_REPEAT: fDeltaBPM *= 40; break;
2002-05-20 08:59:37 +00:00
}
2003-09-07 22:28:46 +00:00
2002-08-17 06:44:04 +00:00
float fNewBPM = fBPM + fDeltaBPM;
2003-09-07 22:28:46 +00:00
m_pSong->SetBPMAtBeat( GAMESTATE->m_fSongBeat, fNewBPM );
2002-08-17 06:44:04 +00:00
}
break;
case EDIT_BUTTON_STOP_UP:
case EDIT_BUTTON_STOP_DOWN:
2002-08-17 06:44:04 +00:00
{
float fStopDelta;
switch( EditB )
2002-06-29 11:59:09 +00:00
{
case EDIT_BUTTON_STOP_UP: fStopDelta = +0.020f; break;
case EDIT_BUTTON_STOP_DOWN: fStopDelta = -0.020f; break;
2002-09-07 10:31:35 +00:00
default: ASSERT(0); return;
2002-06-29 11:59:09 +00:00
}
if( EditIsBeingPressed( EDIT_BUTTON_ADJUST_FINE ) )
fStopDelta /= 20; /* 1ms */
2003-11-03 08:44:49 +00:00
else switch( type )
2002-06-29 11:59:09 +00:00
{
case IET_SLOW_REPEAT: fStopDelta *= 10; break;
case IET_FAST_REPEAT: fStopDelta *= 40; break;
2002-05-20 08:59:37 +00:00
}
2002-06-29 11:59:09 +00:00
unsigned i;
2003-12-18 04:48:26 +00:00
for( i=0; i<m_pSong->m_Timing.m_StopSegments.size(); i++ )
2002-05-20 08:59:37 +00:00
{
if( m_pSong->m_Timing.m_StopSegments[i].m_iStartRow == BeatToNoteRow(GAMESTATE->m_fSongBeat) )
2002-08-17 06:44:04 +00:00
break;
2002-05-20 08:59:37 +00:00
}
2003-12-18 04:48:26 +00:00
if( i == m_pSong->m_Timing.m_StopSegments.size() ) // there is no BPMSegment at the current beat
2002-06-29 11:59:09 +00:00
{
2002-08-17 06:44:04 +00:00
// create a new StopSegment
if( fStopDelta > 0 )
m_pSong->AddStopSegment( StopSegment(BeatToNoteRow(GAMESTATE->m_fSongBeat), fStopDelta) );
2002-06-29 11:59:09 +00:00
}
2003-12-18 04:48:26 +00:00
else // StopSegment being modified is m_Timing.m_StopSegments[i]
2002-06-29 11:59:09 +00:00
{
2003-12-18 04:48:26 +00:00
m_pSong->m_Timing.m_StopSegments[i].m_fStopSeconds += fStopDelta;
if( m_pSong->m_Timing.m_StopSegments[i].m_fStopSeconds <= 0 )
m_pSong->m_Timing.m_StopSegments.erase( m_pSong->m_Timing.m_StopSegments.begin()+i,
m_pSong->m_Timing.m_StopSegments.begin()+i+1);
2002-06-29 11:59:09 +00:00
}
2002-08-17 06:44:04 +00:00
}
break;
case EDIT_BUTTON_OFFSET_UP:
case EDIT_BUTTON_OFFSET_DOWN:
2002-08-17 06:44:04 +00:00
{
float fOffsetDelta;
switch( EditB )
2002-07-02 00:27:58 +00:00
{
case EDIT_BUTTON_OFFSET_DOWN: fOffsetDelta = -0.02f; break;
case EDIT_BUTTON_OFFSET_UP: fOffsetDelta = +0.02f; break;
2002-09-07 10:31:35 +00:00
default: ASSERT(0); return;
2002-07-02 00:27:58 +00:00
}
if( EditIsBeingPressed( EDIT_BUTTON_ADJUST_FINE ) )
fOffsetDelta /= 20; /* 1ms */
else switch( type )
2002-07-02 00:27:58 +00:00
{
2002-08-17 06:44:04 +00:00
case IET_SLOW_REPEAT: fOffsetDelta *= 10; break;
case IET_FAST_REPEAT: fOffsetDelta *= 40; break;
}
2002-06-29 11:59:09 +00:00
2003-12-18 04:48:26 +00:00
m_pSong->m_Timing.m_fBeat0OffsetInSeconds += fOffsetDelta;
2002-08-17 06:44:04 +00:00
}
break;
case EDIT_BUTTON_SAMPLE_START_UP:
case EDIT_BUTTON_SAMPLE_START_DOWN:
2002-08-17 06:44:04 +00:00
{
float fDelta;
switch( EditB )
2002-08-17 06:44:04 +00:00
{
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;
2002-09-07 10:31:35 +00:00
default: ASSERT(0); return;
2002-07-02 00:27:58 +00:00
}
2002-08-17 06:44:04 +00:00
switch( type )
{
case IET_SLOW_REPEAT: fDelta *= 10; break;
case IET_FAST_REPEAT: fDelta *= 40; break;
}
if( EditB == EDIT_BUTTON_SAMPLE_LENGTH_DOWN || EditB == EDIT_BUTTON_SAMPLE_LENGTH_UP )
{
m_pSong->m_fMusicSampleLengthSeconds += fDelta;
m_pSong->m_fMusicSampleLengthSeconds = max(m_pSong->m_fMusicSampleLengthSeconds,0);
} else {
m_pSong->m_fMusicSampleStartSeconds += fDelta;
m_pSong->m_fMusicSampleStartSeconds = max(m_pSong->m_fMusicSampleStartSeconds,0);
}
2002-07-02 00:27:58 +00:00
}
2002-08-17 06:44:04 +00:00
break;
case EDIT_BUTTON_PLAY_SAMPLE_MUSIC:
2003-03-05 02:38:17 +00:00
PlayPreviewMusic();
break;
case EDIT_BUTTON_OPEN_BGA_MENU:
2005-03-20 06:41:56 +00:00
HandleMainMenuChoice( edit_bg_change );
break;
case EDIT_BUTTON_OPEN_COURSE_MENU:
2004-01-26 20:56:58 +00:00
{
g_CourseMode.rows[0].choices.clear();
g_CourseMode.rows[0].choices.push_back( "OFF" );
2005-03-20 06:41:56 +00:00
g_CourseMode.rows[0].iDefaultChoice = 0;
2004-01-26 20:56:58 +00:00
vector<Course*> courses;
SONGMAN->GetAllCourses( courses, false );
for( unsigned i = 0; i < courses.size(); ++i )
{
const Course *crs = courses[i];
bool bUsesThisSong = false;
for( unsigned e = 0; e < crs->m_entries.size(); ++e )
{
if( crs->m_entries[e].type != COURSE_ENTRY_FIXED )
continue;
if( crs->m_entries[e].pSong != m_pSong )
continue;
bUsesThisSong = true;
}
if( bUsesThisSong )
{
2004-07-11 10:02:38 +00:00
g_CourseMode.rows[0].choices.push_back( crs->GetFullDisplayTitle() );
2004-01-26 20:56:58 +00:00
if( crs == m_pAttacksFromCourse )
2005-03-20 06:41:56 +00:00
g_CourseMode.rows[0].iDefaultChoice = g_CourseMode.rows[0].choices.size()-1;
2004-01-26 20:56:58 +00:00
}
}
SCREENMAN->MiniMenu( &g_CourseMode, SM_BackFromCourseModeMenu );
break;
}
case EDIT_BUTTON_PLAY_FROM_START:
2005-03-20 06:41:56 +00:00
HandleMainMenuChoice( play_whole_song );
break;
case EDIT_BUTTON_PLAY_FROM_CURSOR:
2005-03-20 06:41:56 +00:00
HandleMainMenuChoice( play_current_beat_to_end );
2003-04-21 03:09:48 +00:00
break;
case EDIT_BUTTON_PLAY_SELECTION:
if( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 )
2005-03-20 06:41:56 +00:00
HandleAreaMenuChoice( play );
else
2005-03-20 06:41:56 +00:00
HandleMainMenuChoice( play_current_beat_to_end );
break;
case EDIT_BUTTON_RECORD:
if( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 )
2005-03-20 06:41:56 +00:00
HandleAreaMenuChoice( record );
break;
case EDIT_BUTTON_INSERT:
2005-03-20 06:41:56 +00:00
HandleAreaMenuChoice( insert_and_shift );
SCREENMAN->PlayInvalidSound();
break;
case EDIT_BUTTON_INSERT_SHIFT_PAUSES:
2005-03-20 06:41:56 +00:00
HandleAreaMenuChoice( shift_pauses_forward );
SCREENMAN->PlayInvalidSound();
break;
case EDIT_BUTTON_DELETE:
2005-03-20 06:41:56 +00:00
HandleAreaMenuChoice( delete_and_shift );
SCREENMAN->PlayInvalidSound();
break;
case EDIT_BUTTON_DELETE_SHIFT_PAUSES:
2005-03-20 06:41:56 +00:00
HandleAreaMenuChoice( shift_pauses_backward );
SCREENMAN->PlayInvalidSound();
break;
2002-05-20 08:59:37 +00:00
}
}
void ScreenEdit::InputRecord( const DeviceInput& DeviceI, const InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI, EditButton EditB )
2002-05-20 08:59:37 +00:00
{
if( EditB == EDIT_BUTTON_RETURN_TO_EDIT )
2002-05-20 08:59:37 +00:00
{
2005-04-14 06:34:17 +00:00
TransitionEditState( STATE_EDITING );
2002-10-18 19:01:32 +00:00
return;
}
2002-05-20 08:59:37 +00:00
2002-10-18 19:01:32 +00:00
if( StyleI.player != PLAYER_1 )
return; // ignore
2002-05-20 08:59:37 +00:00
2002-10-18 19:01:32 +00:00
const int iCol = StyleI.col;
2002-05-20 08:59:37 +00:00
2002-10-18 19:01:32 +00:00
switch( type )
{
case IET_FIRST_PRESS:
{
// Add a tap
2002-05-20 08:59:37 +00:00
2002-10-18 19:01:32 +00:00
float fBeat = GAMESTATE->m_fSongBeat;
2004-10-24 17:44:51 +00:00
fBeat = Quantize( fBeat, NoteTypeToBeat(m_SnapDisplay.GetNoteType()) );
2002-10-18 19:01:32 +00:00
const int iRow = BeatToNoteRow( fBeat );
if( iRow < 0 )
break;
// Remove hold if any so that we don't have taps inside of a hold.
int iHeadRow;
if( m_NoteDataRecord.IsHoldNoteAtBeat( iCol, iRow, &iHeadRow ) )
m_NoteDataRecord.SetTapNote( iCol, iHeadRow, TAP_EMPTY );
m_NoteDataRecord.SetTapNote(iCol, iRow, TAP_ORIGINAL_TAP);
2004-07-02 20:08:17 +00:00
m_NoteFieldRecord.Step( iCol, TNS_MARVELOUS );
2002-10-18 19:01:32 +00:00
}
break;
case IET_SLOW_REPEAT:
case IET_FAST_REPEAT:
case IET_RELEASE:
// don't add or extend holds here
break;
2002-05-20 08:59:37 +00:00
}
}
void ScreenEdit::InputPlay( const DeviceInput& DeviceI, const InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI, EditButton EditB )
2002-05-20 08:59:37 +00:00
{
if( type != IET_FIRST_PRESS )
return;
switch( EditB )
2002-05-20 08:59:37 +00:00
{
case EDIT_BUTTON_RETURN_TO_EDIT:
2005-04-14 06:34:17 +00:00
TransitionEditState( STATE_EDITING );
break;
case EDIT_BUTTON_TOGGLE_ASSIST_TICK:
GAMESTATE->m_SongOptions.m_bAssistTick ^= 1;
break;
case EDIT_BUTTON_TOGGLE_AUTOPLAY:
2002-05-20 08:59:37 +00:00
{
PREFSMAN->m_bAutoPlay = !PREFSMAN->m_bAutoPlay;
FOREACH_HumanPlayer( p )
GAMESTATE->m_pPlayerState[p]->m_PlayerController = PREFSMAN->m_bAutoPlay?PC_AUTOPLAY:PC_HUMAN;
}
break;
case EDIT_BUTTON_OFFSET_UP:
case EDIT_BUTTON_OFFSET_DOWN:
{
float fOffsetDelta;
switch( EditB )
{
case EDIT_BUTTON_OFFSET_DOWN: fOffsetDelta = -0.020f; break;
case EDIT_BUTTON_OFFSET_UP: fOffsetDelta = +0.020f; break;
default: ASSERT(0); return;
}
2002-09-11 04:49:07 +00:00
if( EditIsBeingPressed( EDIT_BUTTON_ADJUST_FINE ) )
fOffsetDelta /= 20; /* 1ms */
else switch( type )
{
case IET_SLOW_REPEAT: fOffsetDelta *= 10; break;
case IET_FAST_REPEAT: fOffsetDelta *= 40; break;
2002-09-11 04:49:07 +00:00
}
m_pSong->m_Timing.m_fBeat0OffsetInSeconds += fOffsetDelta;
2002-05-20 08:59:37 +00:00
}
break;
2002-05-20 08:59:37 +00:00
}
switch( StyleI.player )
{
2003-07-13 00:34:30 +00:00
case PLAYER_1:
if( !PREFSMAN->m_bAutoPlay )
m_Player.Step( StyleI.col, DeviceI.ts );
break;
2002-05-20 08:59:37 +00:00
}
}
2005-04-14 06:34:17 +00:00
void ScreenEdit::TransitionEditState( EditState em )
2002-05-20 08:59:37 +00:00
{
2005-04-14 06:34:17 +00:00
EditState old = m_EditState;
2005-03-18 19:44:01 +00:00
switch( em )
{
2005-04-14 06:34:17 +00:00
case STATE_EDITING:
2005-03-18 19:44:01 +00:00
m_sprOverlay->PlayCommand( "Edit" );
2005-03-18 19:44:01 +00:00
/* Important: people will stop playing, change the BG and start again; make sure we reload */
m_Background.Unload();
m_Foreground.Unload();
2005-03-18 19:44:01 +00:00
GAMESTATE->m_bPastHereWeGo = false;
m_soundMusic.StopPlaying();
m_soundAssistTick.StopPlaying(); /* Stop any queued assist ticks. */
2005-03-18 19:44:01 +00:00
/* Make sure we're snapped. */
GAMESTATE->m_fSongBeat = Quantize( GAMESTATE->m_fSongBeat, NoteTypeToBeat(m_SnapDisplay.GetNoteType()) );
2004-01-26 20:56:58 +00:00
2005-03-18 19:44:01 +00:00
/* Playing and recording have lead-ins, which may start before beat 0;
* make sure we don't stay there if we escaped out early. */
GAMESTATE->m_fSongBeat = max( GAMESTATE->m_fSongBeat, 0 );
/* Stop displaying course attacks, if any. */
GAMESTATE->RemoveAllActiveAttacks();
GAMESTATE->RebuildPlayerOptionsFromActiveAttacks( PLAYER_1 );
GAMESTATE->m_pPlayerState[PLAYER_1]->m_CurrentPlayerOptions = GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerOptions;
2005-04-14 06:34:17 +00:00
if( old == STATE_RECORDING )
2005-03-18 19:44:01 +00:00
{
2005-03-23 10:43:57 +00:00
SaveUndo();
2005-03-18 19:44:01 +00:00
// delete old TapNotes in the range
m_NoteDataEdit.ClearRange( m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker );
m_NoteDataEdit.CopyRange( m_NoteDataRecord, m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker, m_NoteFieldEdit.m_iBeginMarker );
m_NoteDataRecord.ClearAll();
2005-03-23 10:43:57 +00:00
CheckNumberOfNotesAndUndo();
2005-03-18 19:44:01 +00:00
}
break;
2005-04-14 06:34:17 +00:00
case STATE_RECORDING:
2005-03-18 19:44:01 +00:00
break;
2005-04-14 06:34:17 +00:00
case STATE_PLAYING:
2005-03-18 19:44:01 +00:00
break;
default:
ASSERT(0);
}
2002-10-18 00:45:09 +00:00
2002-05-20 08:59:37 +00:00
2005-03-18 19:44:01 +00:00
//
// Show/hide depending on em
//
2005-04-14 06:34:17 +00:00
m_Background.SetHidden( !PREFSMAN->m_bEditorShowBGChangesPlay || em == STATE_EDITING );
m_sprUnderlay->SetHidden( em != STATE_EDITING );
m_sprOverlay->SetHidden( em != STATE_EDITING );
m_textInputTips.SetHidden( em != STATE_EDITING );
m_textInfo.SetHidden( em != STATE_EDITING );
2005-03-20 11:35:45 +00:00
// Play the OnCommands again so that these will be re-hidden if the OnCommand hides them.
2005-04-14 06:34:17 +00:00
if( em == STATE_EDITING )
2005-03-20 11:35:45 +00:00
{
m_textInputTips.PlayCommand( "On" );
m_textInfo.PlayCommand( "On" );
}
2005-04-14 06:34:17 +00:00
m_textPlayRecordHelp.SetHidden( em == STATE_EDITING );
m_SnapDisplay.SetHidden( em != STATE_EDITING );
m_NoteFieldEdit.SetHidden( em != STATE_EDITING );
m_NoteFieldRecord.SetHidden( em != STATE_RECORDING );
m_Player.SetHidden( em != STATE_PLAYING );
m_Foreground.SetHidden( !PREFSMAN->m_bEditorShowBGChangesPlay || em == STATE_EDITING );
2002-05-20 08:59:37 +00:00
2005-01-15 13:05:33 +00:00
2005-04-14 06:34:17 +00:00
m_EditState = em;
2002-05-20 08:59:37 +00:00
}
void ScreenEdit::HandleScreenMessage( const ScreenMessage SM )
{
2005-04-01 08:34:23 +00:00
if( SM != SM_UpdateTextInfo )
m_bTextInfoNeedsUpdate = true;
2005-04-01 08:34:23 +00:00
if( SM == SM_UpdateTextInfo )
{
UpdateTextInfo();
this->PostScreenMessage( SM_UpdateTextInfo, 0.1f );
2005-04-01 08:34:23 +00:00
}
else if( SM == SM_GoToNextScreen )
2002-05-20 08:59:37 +00:00
{
2005-03-12 23:27:48 +00:00
SCREENMAN->SetNewScreen( PREV_SCREEN );
GAMESTATE->m_bEditing = false;
}
else if( SM == SM_BackFromMainMenu )
{
2005-03-20 06:41:56 +00:00
HandleMainMenuChoice( (MainMenuChoice)ScreenMiniMenu::s_iLastRowCode, ScreenMiniMenu::s_viLastAnswers );
}
else if( SM == SM_BackFromAreaMenu )
{
2005-03-20 06:41:56 +00:00
HandleAreaMenuChoice( (AreaMenuChoice)ScreenMiniMenu::s_iLastRowCode, ScreenMiniMenu::s_viLastAnswers );
}
else if( SM == SM_BackFromStepsInformation )
{
2005-03-20 20:13:27 +00:00
HandleStepsInformationChoice( (StepsInformationChoice)ScreenMiniMenu::s_iLastRowCode, ScreenMiniMenu::s_viLastAnswers );
}
else if( SM == SM_BackFromSongInformation )
{
2005-03-20 20:13:27 +00:00
HandleSongInformationChoice( (SongInformationChoice)ScreenMiniMenu::s_iLastRowCode, ScreenMiniMenu::s_viLastAnswers );
}
else if( SM == SM_BackFromBPMChange )
{
float fBPM = strtof( ScreenTextEntry::s_sLastAnswer, NULL );
if( fBPM > 0 )
m_pSong->SetBPMAtBeat( GAMESTATE->m_fSongBeat, fBPM );
}
else if( SM == SM_BackFromStopChange )
{
float fStop = strtof( ScreenTextEntry::s_sLastAnswer, NULL );
if( fStop >= 0 )
m_pSong->m_Timing.SetStopAtBeat( GAMESTATE->m_fSongBeat, fStop );
}
else if( SM == SM_BackFromBGChange )
{
2005-03-20 06:41:56 +00:00
HandleBGChangeChoice( (BGChangeChoice)ScreenMiniMenu::s_iLastRowCode, ScreenMiniMenu::s_viLastAnswers );
}
else if( SM == SM_BackFromPrefs )
{
2005-03-20 06:41:56 +00:00
PREFSMAN->m_bEditorShowBGChangesPlay = !!ScreenMiniMenu::s_viLastAnswers[pref_show_bgs_play];
PREFSMAN->SaveGlobalPrefsToDisk();
}
else if( SM == SM_BackFromCourseModeMenu )
2004-01-26 20:56:58 +00:00
{
2005-03-20 06:41:56 +00:00
const int num = ScreenMiniMenu::s_viLastAnswers[0];
2004-01-26 20:56:58 +00:00
m_pAttacksFromCourse = NULL;
if( num != 0 )
{
const CString name = g_CourseMode.rows[0].choices[num];
m_pAttacksFromCourse = SONGMAN->FindCourse( name );
ASSERT( m_pAttacksFromCourse );
}
}
else if(
SM == SM_BackFromPlayerOptions ||
SM == SM_BackFromSongOptions )
{
GAMESTATE->StoreSelectedOptions(); // so that the options stick when we reset Course attacks
// stop any music that screen may have been playing
SOUND->StopMusic();
}
else if( SM == SM_BackFromInsertAttack )
{
int iDurationChoice = ScreenMiniMenu::s_viLastAnswers[0];
g_fLastInsertAttackDurationSeconds = strtof( g_InsertAttack.rows[0].choices[iDurationChoice], NULL );
// XXX: Fix me
//SCREENMAN->AddNewScreenToTop( "ScreenPlayerOptions", SM_BackFromInsertAttackPlayerOptions );
}
else if( SM == SM_BackFromInsertAttackPlayerOptions )
{
PlayerOptions poChosen = GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerOptions;
CString sMods = poChosen.GetString();
const int row = BeatToNoteRow( GAMESTATE->m_fSongBeat );
TapNote tn(
TapNote::attack, TapNote::original,
sMods,
g_fLastInsertAttackDurationSeconds,
false,
0 );
2005-03-23 10:43:57 +00:00
SaveUndo();
m_NoteDataEdit.SetTapNote( g_iLastInsertAttackTrack, row, tn );
2005-03-23 10:43:57 +00:00
CheckNumberOfNotesAndUndo();
}
else if( SM == SM_DoRevertToLastSave )
{
2005-03-08 21:19:17 +00:00
if( ScreenPrompt::s_LastAnswer == ANSWER_YES )
2004-01-24 20:36:09 +00:00
{
2005-03-08 21:19:17 +00:00
CopyFromLastSave();
m_pSteps->GetNoteData( m_NoteDataEdit );
m_bHasUndo = false;
2005-03-23 10:43:57 +00:00
m_Undo.ClearAll();
2004-01-24 20:36:09 +00:00
}
}
else if( SM == SM_DoSaveAndExit ) // just asked "save before exiting? yes, no, cancel"
{
switch( ScreenPrompt::s_LastAnswer )
{
case ANSWER_YES:
// This will send SM_Success or SM_Failure.
2005-03-20 06:41:56 +00:00
HandleMainMenuChoice( ScreenEdit::save_on_exit );
return;
case ANSWER_NO:
/* Don't save; just exit. */
SCREENMAN->SendMessageToTopScreen( SM_DoExit );
return;
case ANSWER_CANCEL:
break; // do nothing
}
}
else if( SM == SM_Success )
{
LOG->Trace( "Save successful." );
m_pSteps->SetSavedToDisk( true );
CopyToLastSave();
if( m_CurrentAction == save_on_exit )
HandleScreenMessage( SM_DoExit );
}
else if( SM == SM_Failure ) // 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 deleteing the Steps below
CopyFromLastSave();
// If these steps have never been saved, then we should delete them.
// If the user created them in the edit menu and never bothered
// to save them, then they aren't wanted.
Steps* pSteps = GAMESTATE->m_pCurSteps[PLAYER_1];
if( !pSteps->GetSavedToDisk() )
{
Song* pSong = GAMESTATE->m_pCurSong;
pSong->RemoveSteps( pSteps );
m_pSteps = NULL;
GAMESTATE->m_pCurSteps[PLAYER_1].Set( NULL );
}
m_Out.StartTransitioning( SM_GoToNextScreen );
}
else if( SM == SM_GainFocus )
{
2003-12-22 20:27:47 +00:00
/* We do this ourself. */
SOUND->HandleSongTimer( false );
/* When another screen comes up, RageSounds takes over the sound timer. When we come
* back, put the timer back to where it was. */
GAMESTATE->m_fSongBeat = m_fTrailingBeat;
}
else if( SM == SM_LoseFocus )
{
/* Snap the trailing beat, in case we lose focus while tweening. */
m_fTrailingBeat = GAMESTATE->m_fSongBeat;
2002-05-20 08:59:37 +00:00
}
}
void ScreenEdit::OnSnapModeChange()
{
2002-06-29 11:59:09 +00:00
m_soundChangeSnap.Play();
2002-05-20 08:59:37 +00:00
2002-10-18 19:01:32 +00:00
NoteType nt = m_SnapDisplay.GetNoteType();
int iStepIndex = BeatToNoteRow( GAMESTATE->m_fSongBeat );
2002-05-20 08:59:37 +00:00
int iElementsPerNoteType = BeatToNoteRow( NoteTypeToBeat(nt) );
int iStepIndexHangover = iStepIndex % iElementsPerNoteType;
GAMESTATE->m_fSongBeat -= NoteRowToBeat( iStepIndexHangover );
2002-05-20 08:59:37 +00:00
}
2002-08-17 06:44:04 +00:00
2003-02-19 05:46:09 +00:00
// Helper function for below
// Begin helper functions for InputEdit
void ChangeDescription( CString sNew )
{
2004-05-24 06:12:17 +00:00
Steps* pSteps = GAMESTATE->m_pCurSteps[PLAYER_1];
2004-05-24 03:41:39 +00:00
pSteps->SetDescription(sNew);
2003-02-19 05:46:09 +00:00
}
void ChangeMainTitle( CString sNew )
{
Song* pSong = GAMESTATE->m_pCurSong;
pSong->m_sMainTitle = sNew;
}
void ChangeSubTitle( CString sNew )
{
Song* pSong = GAMESTATE->m_pCurSong;
pSong->m_sSubTitle = sNew;
}
void ChangeArtist( CString sNew )
{
Song* pSong = GAMESTATE->m_pCurSong;
pSong->m_sArtist = sNew;
}
2003-06-23 02:24:13 +00:00
void ChangeCredit( CString sNew )
{
Song* pSong = GAMESTATE->m_pCurSong;
pSong->m_sCredit = sNew;
}
2003-02-19 05:46:09 +00:00
void ChangeMainTitleTranslit( CString sNew )
{
Song* pSong = GAMESTATE->m_pCurSong;
pSong->m_sMainTitleTranslit = sNew;
}
void ChangeSubTitleTranslit( CString sNew )
{
Song* pSong = GAMESTATE->m_pCurSong;
pSong->m_sSubTitleTranslit = sNew;
}
void ChangeArtistTranslit( CString sNew )
{
Song* pSong = GAMESTATE->m_pCurSong;
pSong->m_sArtistTranslit = sNew;
}
// End helper functions
2003-02-19 05:46:09 +00:00
2005-03-20 06:41:56 +00:00
void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector<int> &iAnswers )
2003-02-18 23:15:38 +00:00
{
switch( c )
{
2005-03-20 20:13:27 +00:00
case edit_steps_information:
2003-02-18 23:15:38 +00:00
{
2004-05-24 03:41:39 +00:00
/* XXX: If the difficulty is changed from EDIT, and pSteps->WasLoadedFromProfile()
2004-02-25 23:43:50 +00:00
* is true, we should warn that the steps will no longer be saved to the profile. */
2004-05-24 06:12:17 +00:00
Steps* pSteps = GAMESTATE->m_pCurSteps[PLAYER_1];
2003-02-18 23:15:38 +00:00
float fMusicSeconds = m_soundMusic.GetLengthSeconds();
2005-04-16 04:55:50 +00:00
g_StepsInformation.rows[difficulty].choices.clear();
FOREACH_Difficulty( dc )
g_StepsInformation.rows[difficulty].choices.push_back( DifficultyToThemedString(pSteps->GetDifficulty()) );
2005-03-20 20:13:27 +00:00
g_StepsInformation.rows[difficulty].iDefaultChoice = pSteps->GetDifficulty();
2005-04-16 04:55:50 +00:00
g_StepsInformation.rows[difficulty].bEnabled = EDIT_MODE >= EDIT_MODE_FULL;
2005-03-20 20:13:27 +00:00
g_StepsInformation.rows[meter].iDefaultChoice = clamp( pSteps->GetMeter()-1, 0, MAX_METER+1 );
2005-04-16 04:55:50 +00:00
g_StepsInformation.rows[meter].bEnabled = EDIT_MODE >= EDIT_MODE_HOME;
2005-03-20 20:13:27 +00:00
g_StepsInformation.rows[predict_meter].choices.resize(1);g_StepsInformation.rows[predict_meter].choices[0] = ssprintf("%.2f",pSteps->PredictMeter());
2005-04-14 06:34:17 +00:00
g_StepsInformation.rows[description].choices.resize(1); g_StepsInformation.rows[description].choices[0] = pSteps->GetDescription(); g_StepsInformation.rows[description].bEnabled = EDIT_MODE == EDIT_MODE_FULL;
2005-03-20 20:13:27 +00:00
g_StepsInformation.rows[tap_notes].choices.resize(1); g_StepsInformation.rows[tap_notes].choices[0] = ssprintf("%d", m_NoteDataEdit.GetNumTapNotes());
g_StepsInformation.rows[jumps].choices.resize(1); g_StepsInformation.rows[jumps].choices[0] = ssprintf("%d", m_NoteDataEdit.GetNumJumps());
g_StepsInformation.rows[hands].choices.resize(1); g_StepsInformation.rows[hands].choices[0] = ssprintf("%d", m_NoteDataEdit.GetNumHands());
g_StepsInformation.rows[quads].choices.resize(1); g_StepsInformation.rows[quads].choices[0] = ssprintf("%d", m_NoteDataEdit.GetNumQuads());
g_StepsInformation.rows[holds].choices.resize(1); g_StepsInformation.rows[holds].choices[0] = ssprintf("%d", m_NoteDataEdit.GetNumHoldNotes());
g_StepsInformation.rows[mines].choices.resize(1); g_StepsInformation.rows[mines].choices[0] = ssprintf("%d", m_NoteDataEdit.GetNumMines());
g_StepsInformation.rows[stream].choices.resize(1); g_StepsInformation.rows[stream].choices[0] = ssprintf("%.2f", NoteDataUtil::GetStreamRadarValue(m_NoteDataEdit,fMusicSeconds));
g_StepsInformation.rows[voltage].choices.resize(1); g_StepsInformation.rows[voltage].choices[0] = ssprintf("%.2f", NoteDataUtil::GetVoltageRadarValue(m_NoteDataEdit,fMusicSeconds));
g_StepsInformation.rows[air].choices.resize(1); g_StepsInformation.rows[air].choices[0] = ssprintf("%.2f", NoteDataUtil::GetAirRadarValue(m_NoteDataEdit,fMusicSeconds));
g_StepsInformation.rows[freeze].choices.resize(1); g_StepsInformation.rows[freeze].choices[0] = ssprintf("%.2f", NoteDataUtil::GetFreezeRadarValue(m_NoteDataEdit,fMusicSeconds));
g_StepsInformation.rows[chaos].choices.resize(1); g_StepsInformation.rows[chaos].choices[0] = ssprintf("%.2f", NoteDataUtil::GetChaosRadarValue(m_NoteDataEdit,fMusicSeconds));
SCREENMAN->MiniMenu( &g_StepsInformation, SM_BackFromStepsInformation );
2003-02-18 23:15:38 +00:00
}
break;
case play_whole_song:
2003-02-19 05:46:09 +00:00
{
m_NoteFieldEdit.m_iBeginMarker = 0;
m_NoteFieldEdit.m_iEndMarker = m_NoteDataEdit.GetLastRow();
2005-03-20 06:41:56 +00:00
HandleAreaMenuChoice( play );
2003-02-19 05:46:09 +00:00
}
2003-02-18 23:15:38 +00:00
break;
case play_current_beat_to_end:
{
m_NoteFieldEdit.m_iBeginMarker = BeatToNoteRow(GAMESTATE->m_fSongBeat);
m_NoteFieldEdit.m_iEndMarker = m_NoteDataEdit.GetLastRow();
2005-03-20 06:41:56 +00:00
HandleAreaMenuChoice( play );
}
break;
2003-02-18 23:15:38 +00:00
case save:
case save_on_exit:
2003-02-18 23:15:38 +00:00
{
m_CurrentAction = c;
2003-08-03 00:13:55 +00:00
// copy edit into current Steps
Song* pSong = GAMESTATE->m_pCurSong;
2004-05-24 06:12:17 +00:00
Steps* pSteps = GAMESTATE->m_pCurSteps[PLAYER_1];
2004-05-24 03:41:39 +00:00
ASSERT( pSteps );
2003-02-18 23:15:38 +00:00
pSteps->SetNoteData( m_NoteDataEdit );
pSteps->CalculateRadarValues( pSong->m_fMusicLengthSeconds );
2005-03-08 21:19:17 +00:00
2005-04-14 06:34:17 +00:00
switch( EDIT_MODE )
{
2005-04-14 06:34:17 +00:00
case EDIT_MODE_HOME:
{
2005-04-14 06:34:17 +00:00
CString s;
switch( c )
{
case save: s = "ScreenMemcardSaveEditsAfterSave"; break;
case save_on_exit: s = "ScreenMemcardSaveEditsAfterExit"; break;
default: ASSERT(0);
}
SCREENMAN->AddNewScreenToTop( s );
}
2005-04-14 06:34:17 +00:00
break;
case EDIT_MODE_FULL:
{
pSteps->SetSavedToDisk( true );
CopyToLastSave();
2005-04-14 06:34:17 +00:00
GAMESTATE->m_pCurSong->Save();
SCREENMAN->ZeroNextUpdate();
2005-03-08 21:19:17 +00:00
2005-04-14 06:34:17 +00:00
// we shouldn't say we're saving a DWI if we're on any game besides
// dance, it just looks tacky and people may be wondering where the
// DWI file is :-)
if ((int)pSteps->m_StepsType <= (int)STEPS_TYPE_DANCE_SOLO)
SCREENMAN->SystemMessage( "Saved as SM and DWI." );
else
SCREENMAN->SystemMessage( "Saved as SM." );
2005-04-14 06:34:17 +00:00
HandleScreenMessage( SM_Success );
}
break;
case EDIT_MODE_PRACTICE:
break;
default:
ASSERT(0);
}
2003-02-18 23:15:38 +00:00
2005-03-21 03:02:47 +00:00
m_soundSave.Play();
2003-02-18 23:15:38 +00:00
}
break;
2005-03-08 21:19:17 +00:00
case revert_to_last_save:
SCREENMAN->Prompt( SM_DoRevertToLastSave,
"Do you want to revert to your last save?\n\nThis will destroy all unsaved changes.",
PROMPT_YES_NO, ANSWER_NO );
2004-01-24 20:36:09 +00:00
break;
2003-02-18 23:15:38 +00:00
case player_options:
SCREENMAN->AddNewScreenToTop( "ScreenPlayerOptionsEdit" );
2003-02-18 23:15:38 +00:00
break;
case song_options:
SCREENMAN->AddNewScreenToTop( "ScreenSongOptionsEdit" );
2003-02-18 23:15:38 +00:00
break;
case edit_song_info:
2003-02-19 05:46:09 +00:00
{
Song* pSong = GAMESTATE->m_pCurSong;
2005-03-20 20:13:27 +00:00
g_SongInformation.rows[main_title].choices.resize(1); g_SongInformation.rows[main_title].choices[0] = pSong->m_sMainTitle;
g_SongInformation.rows[sub_title].choices.resize(1); g_SongInformation.rows[sub_title].choices[0] = pSong->m_sSubTitle;
g_SongInformation.rows[artist].choices.resize(1); g_SongInformation.rows[artist].choices[0] = pSong->m_sArtist;
g_SongInformation.rows[credit].choices.resize(1); g_SongInformation.rows[credit].choices[0] = pSong->m_sCredit;
g_SongInformation.rows[main_title_transliteration].choices.resize(1); g_SongInformation.rows[main_title_transliteration].choices[0] = pSong->m_sMainTitleTranslit;
g_SongInformation.rows[sub_title_transliteration].choices.resize(1); g_SongInformation.rows[sub_title_transliteration].choices[0] = pSong->m_sSubTitleTranslit;
g_SongInformation.rows[artist_transliteration].choices.resize(1); g_SongInformation.rows[artist_transliteration].choices[0] = pSong->m_sArtistTranslit;
SCREENMAN->MiniMenu( &g_SongInformation, SM_BackFromSongInformation );
2003-02-19 05:46:09 +00:00
}
2003-02-18 23:15:38 +00:00
break;
case edit_bpm:
2005-03-23 04:08:27 +00:00
SCREENMAN->TextEntry(
SM_BackFromBPMChange,
"Enter new BPM value.",
ssprintf( "%.4f", m_pSong->GetBPMAtBeat(GAMESTATE->m_fSongBeat) ),
10
);
break;
case edit_stop:
{
unsigned i;
for( i=0; i<m_pSong->m_Timing.m_StopSegments.size(); i++ )
{
// XXX
if( m_pSong->m_Timing.m_StopSegments[i].m_iStartRow == BeatToNoteRow(GAMESTATE->m_fSongBeat) )
break;
}
if ( i == m_pSong->m_Timing.m_StopSegments.size() )
2005-03-23 04:08:27 +00:00
{
SCREENMAN->TextEntry(
SM_BackFromStopChange,
"Enter new Stop value.",
"0.00",
10
);
}
else
2005-03-23 04:08:27 +00:00
{
SCREENMAN->TextEntry(
SM_BackFromStopChange,
"Enter new Stop value.",
ssprintf( "%.4f", m_pSong->m_Timing.m_StopSegments[i].m_fStopSeconds ),
10
);
}
break;
}
2003-02-18 23:15:38 +00:00
case edit_bg_change:
2003-02-19 05:46:09 +00:00
{
//
// Fill in option names
//
// m_pSong->GetSongDir() has trailing slash
2005-03-20 06:41:56 +00:00
g_BackgroundChange.rows[add_song_bganimation].choices.clear();
GetDirListing( m_pSong->GetSongDir()+"*", g_BackgroundChange.rows[add_song_bganimation].choices, true );
g_BackgroundChange.rows[add_song_movie].choices.clear();
GetDirListing( m_pSong->GetSongDir()+"*.avi", g_BackgroundChange.rows[add_song_movie].choices, false );
GetDirListing( m_pSong->GetSongDir()+"*.mpg", g_BackgroundChange.rows[add_song_movie].choices, false );
GetDirListing( m_pSong->GetSongDir()+"*.mpeg", g_BackgroundChange.rows[add_song_movie].choices, false );
g_BackgroundChange.rows[add_song_still].choices.clear();
GetDirListing( m_pSong->GetSongDir()+"*.png", g_BackgroundChange.rows[add_song_still].choices, false );
GetDirListing( m_pSong->GetSongDir()+"*.jpg", g_BackgroundChange.rows[add_song_still].choices, false );
GetDirListing( m_pSong->GetSongDir()+"*.gif", g_BackgroundChange.rows[add_song_still].choices, false );
GetDirListing( m_pSong->GetSongDir()+"*.bmp", g_BackgroundChange.rows[add_song_still].choices, false );
g_BackgroundChange.rows[add_global_random_movie].choices.clear();
GetDirListing( RANDOMMOVIES_DIR+"*.avi", g_BackgroundChange.rows[add_global_random_movie].choices, false );
GetDirListing( RANDOMMOVIES_DIR+"*.mpg", g_BackgroundChange.rows[add_global_random_movie].choices, false );
GetDirListing( RANDOMMOVIES_DIR+"*.mpeg", g_BackgroundChange.rows[add_global_random_movie].choices, false );
2005-03-14 12:11:28 +00:00
vector<CString> vSubDirs;
GetDirListing( RANDOMMOVIES_DIR+"*", vSubDirs, true );
FOREACH_CONST( CString, vSubDirs, s )
{
const CString &sSubDir = *s;
vector<CString> vsMovies;
GetDirListing( RANDOMMOVIES_DIR+sSubDir+"/*.avi", vsMovies, false );
GetDirListing( RANDOMMOVIES_DIR+sSubDir+"/*.mpg", vsMovies, false );
GetDirListing( RANDOMMOVIES_DIR+sSubDir+"/*.mpeg", vsMovies, false );
FOREACH_CONST( CString, vsMovies, m )
2005-03-20 06:41:56 +00:00
g_BackgroundChange.rows[add_global_random_movie].choices.push_back( sSubDir +"/"+ *m );
2005-03-14 12:11:28 +00:00
}
2005-03-20 06:41:56 +00:00
g_BackgroundChange.rows[add_global_bganimation].choices.clear();
GetDirListing( BG_ANIMS_DIR+"*", g_BackgroundChange.rows[add_global_bganimation].choices, true );
2005-03-20 06:41:56 +00:00
g_BackgroundChange.rows[add_global_visualization].choices.clear();
GetDirListing( VISUALIZATIONS_DIR+"*.avi", g_BackgroundChange.rows[add_global_visualization].choices, false );
GetDirListing( VISUALIZATIONS_DIR+"*.mpg", g_BackgroundChange.rows[add_global_visualization].choices, false );
GetDirListing( VISUALIZATIONS_DIR+"*.mpeg", g_BackgroundChange.rows[add_global_visualization].choices, false );
//
// Fill in line enabled/disabled
//
bool bAlreadyBGChangeHere = false;
BackgroundChange bgChange;
FOREACH( BackgroundChange, m_pSong->m_BackgroundChanges, bgc )
{
if( bgc->m_fStartBeat == GAMESTATE->m_fSongBeat )
{
bAlreadyBGChangeHere = true;
bgChange = *bgc;
}
}
2005-03-20 06:41:56 +00:00
g_BackgroundChange.rows[add_random].bEnabled = true;
g_BackgroundChange.rows[add_song_bganimation].bEnabled = g_BackgroundChange.rows[add_song_bganimation].choices.size() > 0;
g_BackgroundChange.rows[add_song_movie].bEnabled = g_BackgroundChange.rows[add_song_movie].choices.size() > 0;
g_BackgroundChange.rows[add_song_still].bEnabled = g_BackgroundChange.rows[add_song_still].choices.size() > 0;
g_BackgroundChange.rows[add_global_random_movie].bEnabled = g_BackgroundChange.rows[add_global_random_movie].choices.size() > 0;
g_BackgroundChange.rows[add_global_bganimation].bEnabled = g_BackgroundChange.rows[add_global_bganimation].choices.size() > 0;
g_BackgroundChange.rows[add_global_visualization].bEnabled = g_BackgroundChange.rows[add_global_visualization].choices.size() > 0;
g_BackgroundChange.rows[delete_change].bEnabled = bAlreadyBGChangeHere;
2003-02-19 05:46:09 +00:00
// set default choices
2005-03-20 06:41:56 +00:00
g_BackgroundChange.rows[rate]. SetDefaultChoiceIfPresent( ssprintf("%2.0f%%",bgChange.m_fRate*100) );
g_BackgroundChange.rows[fade_last].iDefaultChoice = bgChange.m_bFadeLast ? 1 : 0;
g_BackgroundChange.rows[rewind_movie].iDefaultChoice = bgChange.m_bRewindMovie ? 1 : 0;
g_BackgroundChange.rows[loop].iDefaultChoice = bgChange.m_bLoop ? 1 : 0;
g_BackgroundChange.rows[add_song_bganimation]. SetDefaultChoiceIfPresent( bgChange.m_sBGName );
g_BackgroundChange.rows[add_song_movie]. SetDefaultChoiceIfPresent( bgChange.m_sBGName );
g_BackgroundChange.rows[add_song_still]. SetDefaultChoiceIfPresent( bgChange.m_sBGName );
g_BackgroundChange.rows[add_global_random_movie]. SetDefaultChoiceIfPresent( bgChange.m_sBGName );
g_BackgroundChange.rows[add_global_bganimation]. SetDefaultChoiceIfPresent( bgChange.m_sBGName );
g_BackgroundChange.rows[add_global_visualization]. SetDefaultChoiceIfPresent( bgChange.m_sBGName );
SCREENMAN->MiniMenu( &g_BackgroundChange, SM_BackFromBGChange );
2003-02-19 05:46:09 +00:00
}
2003-02-18 23:15:38 +00:00
break;
case preferences:
2005-03-20 06:41:56 +00:00
g_Prefs.rows[pref_show_bgs_play].iDefaultChoice = PREFSMAN->m_bEditorShowBGChangesPlay;
SCREENMAN->MiniMenu( &g_Prefs, SM_BackFromPrefs );
break;
2003-02-18 23:15:38 +00:00
case play_preview_music:
2003-03-05 02:38:17 +00:00
PlayPreviewMusic();
2003-02-18 23:15:38 +00:00
break;
case exit:
2005-04-14 06:34:17 +00:00
switch( EDIT_MODE )
{
case EDIT_MODE_FULL:
case EDIT_MODE_HOME:
SCREENMAN->Prompt(
SM_DoSaveAndExit,
"Do you want to save changes before exiting?",
PROMPT_YES_NO_CANCEL, ANSWER_CANCEL );
break;
case EDIT_MODE_PRACTICE:
SCREENMAN->SendMessageToTopScreen( SM_DoExit );
break;
default:
ASSERT(0);
}
2003-02-18 23:15:38 +00:00
break;
default:
ASSERT(0);
};
}
2005-03-23 10:43:57 +00:00
void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector<int> &iAnswers, bool bAllowUndo )
2003-02-18 23:15:38 +00:00
{
2005-03-23 10:43:57 +00:00
bool bSaveUndo = false;
switch( c )
{
case cut:
case copy:
case play:
case record:
case undo:
bSaveUndo = false;
break;
case paste_at_current_beat:
case paste_at_begin_marker:
case clear:
case quantize:
case turn:
case transform:
case alter:
case tempo:
case insert_and_shift:
case delete_and_shift:
case shift_pauses_forward:
case shift_pauses_backward:
case convert_beat_to_pause:
case convert_pause_to_beat:
bSaveUndo = true;
break;
default:
ASSERT(0);
}
// 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();
2003-02-18 23:15:38 +00:00
switch( c )
{
case cut:
{
2005-03-20 06:41:56 +00:00
HandleAreaMenuChoice( copy );
HandleAreaMenuChoice( clear );
2003-02-18 23:15:38 +00:00
}
break;
case copy:
{
ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 );
2003-02-18 23:15:38 +00:00
m_Clipboard.ClearAll();
m_Clipboard.CopyRange( m_NoteDataEdit, m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker );
2003-02-18 23:15:38 +00:00
}
break;
2003-02-22 00:48:38 +00:00
case paste_at_current_beat:
case paste_at_begin_marker:
{
int iDestFirstRow = -1;
switch( c )
{
case paste_at_current_beat:
iDestFirstRow = BeatToNoteRow( GAMESTATE->m_fSongBeat );
break;
case paste_at_begin_marker:
ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 );
iDestFirstRow = m_NoteFieldEdit.m_iBeginMarker;
break;
default:
ASSERT(0);
}
int iRowsToCopy = m_Clipboard.GetLastRow()+1;
m_NoteDataEdit.CopyRange( m_Clipboard, 0, iRowsToCopy, iDestFirstRow );
2003-02-22 00:48:38 +00:00
}
break;
2003-02-18 23:15:38 +00:00
case clear:
{
ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 );
m_NoteDataEdit.ClearRange( m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker );
2003-02-18 23:15:38 +00:00
}
break;
case quantize:
{
NoteType nt = (NoteType)iAnswers[c];
NoteDataUtil::SnapToNearestNoteType( m_NoteDataEdit, nt, nt, m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker );
2003-02-18 23:15:38 +00:00
}
break;
2003-03-13 09:20:21 +00:00
case turn:
2003-02-18 23:15:38 +00:00
{
const NoteData OldClipboard( m_Clipboard );
2005-03-20 06:41:56 +00:00
HandleAreaMenuChoice( cut );
2003-02-22 00:48:38 +00:00
2004-06-28 07:26:00 +00:00
StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType;
2003-03-13 09:20:21 +00:00
TurnType tt = (TurnType)iAnswers[c];
2003-02-18 23:15:38 +00:00
switch( tt )
{
2003-08-07 06:36:34 +00:00
case left: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::left ); break;
case right: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::right ); break;
case mirror: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::mirror ); break;
case shuffle: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::shuffle ); break;
case super_shuffle: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::super_shuffle ); break;
2003-02-18 23:15:38 +00:00
default: ASSERT(0);
}
2005-03-20 06:41:56 +00:00
HandleAreaMenuChoice( paste_at_begin_marker );
m_Clipboard = OldClipboard;
2003-02-18 23:15:38 +00:00
}
break;
2003-03-13 09:20:21 +00:00
case transform:
{
int iBeginRow = m_NoteFieldEdit.m_iBeginMarker;
int iEndRow = m_NoteFieldEdit.m_iEndMarker;
2003-03-13 09:20:21 +00:00
TransformType tt = (TransformType)iAnswers[c];
2004-06-28 07:26:00 +00:00
StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType;
2003-03-13 09:20:21 +00:00
switch( tt )
{
case noholds: NoteDataUtil::RemoveHoldNotes( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case nomines: NoteDataUtil::RemoveMines( m_NoteDataEdit, iBeginRow, iBeginRow ); break;
case little: NoteDataUtil::Little( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case wide: NoteDataUtil::Wide( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case big: NoteDataUtil::Big( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case quick: NoteDataUtil::Quick( m_NoteDataEdit, iBeginRow, iEndRow ); break;
case skippy: NoteDataUtil::Skippy( m_NoteDataEdit, iBeginRow, iEndRow ); break;
2005-03-20 20:13:27 +00:00
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;
2003-03-13 09:20:21 +00:00
default: ASSERT(0);
}
// bake in the additions
NoteDataUtil::ConvertAdditionsToRegular( m_NoteDataEdit );
2003-03-13 09:20:21 +00:00
}
break;
case alter:
{
const NoteData OldClipboard( m_Clipboard );
2005-03-20 06:41:56 +00:00
HandleAreaMenuChoice( cut );
AlterType at = (AlterType)iAnswers[c];
switch( at )
{
2005-03-25 09:36:08 +00:00
case autogen_to_fill_width:
{
NoteData temp( m_Clipboard );
int iNumUsedTracks = NoteDataUtil::GetNumUsedTracks( temp );
2005-03-30 06:09:30 +00:00
if( iNumUsedTracks == 0 )
break;
2005-03-25 09:36:08 +00:00
temp.SetNumTracks( iNumUsedTracks );
NoteDataUtil::LoadTransformedSlidingWindow( temp, m_Clipboard, m_Clipboard.GetNumTracks() );
NoteDataUtil::FixImpossibleRows( 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;
2003-12-31 07:49:30 +00:00
case collapse_left: NoteDataUtil::CollapseLeft( m_Clipboard ); break;
case shift_left: NoteDataUtil::ShiftLeft( m_Clipboard ); break;
case shift_right: NoteDataUtil::ShiftRight( m_Clipboard ); break;
default: ASSERT(0);
}
2005-03-20 06:41:56 +00:00
HandleAreaMenuChoice( paste_at_begin_marker );
m_Clipboard = OldClipboard;
}
break;
2003-09-07 22:28:46 +00:00
case tempo:
{
// This affects all steps.
const NoteData OldClipboard( m_Clipboard );
2005-03-20 06:41:56 +00:00
HandleAreaMenuChoice( cut );
2003-09-07 22:28:46 +00:00
AlterType at = (AlterType)iAnswers[c];
float fScale = -1;
switch( at )
{
2003-11-03 08:44:49 +00: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;
2003-09-07 22:28:46 +00:00
default: ASSERT(0);
}
switch( at )
{
case compress_2x: NoteDataUtil::Scale( m_Clipboard, fScale ); break;
2003-11-03 08:44:49 +00:00
case compress_3_2: NoteDataUtil::Scale( m_Clipboard, fScale ); break;
case compress_4_3: NoteDataUtil::Scale( m_Clipboard, fScale ); break;
case expand_4_3: NoteDataUtil::Scale( m_Clipboard, fScale ); break;
case expand_3_2: NoteDataUtil::Scale( m_Clipboard, fScale ); break;
2003-09-07 22:28:46 +00:00
case expand_2x: NoteDataUtil::Scale( m_Clipboard, fScale ); break;
default: ASSERT(0);
}
int iOldClipboardBeats = m_NoteFieldEdit.m_iEndMarker - m_NoteFieldEdit.m_iBeginMarker;
int iNewClipboardBeats = lrintf( iOldClipboardBeats * fScale );
int iDeltaBeats = iNewClipboardBeats - iOldClipboardBeats;
int iNewClipboardEndBeat = m_NoteFieldEdit.m_iBeginMarker + iNewClipboardBeats;
NoteDataUtil::ShiftRows( m_NoteDataEdit, m_NoteFieldEdit.m_iBeginMarker, iDeltaBeats );
m_pSong->m_Timing.ScaleRegion( fScale, m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker );
2005-03-20 06:41:56 +00:00
HandleAreaMenuChoice( paste_at_begin_marker );
const vector<Steps*> sIter = m_pSong->GetAllSteps();
CString sTempStyle, sTempDiff;
2004-02-26 06:47:13 +00:00
for( unsigned i = 0; i < sIter.size(); i++ )
{
if( sIter[i]->IsAutogen() )
continue;
2004-02-26 06:47:13 +00:00
2004-05-24 03:41:39 +00:00
/* XXX: Edits are distinguished by description. Compare vs m_pSteps. */
2004-05-24 06:12:17 +00:00
if( (sIter[i]->m_StepsType == GAMESTATE->m_pCurSteps[PLAYER_1]->m_StepsType) &&
(sIter[i]->GetDifficulty() == GAMESTATE->m_pCurSteps[PLAYER_1]->GetDifficulty()) )
continue;
2005-01-25 05:02:35 +00:00
NoteData ndTemp;
2004-10-23 17:43:49 +00:00
sIter[i]->GetNoteData( ndTemp );
NoteDataUtil::ScaleRegion( ndTemp, fScale, m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker );
2004-10-23 17:43:49 +00:00
sIter[i]->SetNoteData( ndTemp );
}
2003-09-07 22:28:46 +00:00
m_NoteFieldEdit.m_iEndMarker = iNewClipboardEndBeat;
2003-09-07 22:28:46 +00:00
float fOldBPM = m_pSong->GetBPMAtBeat( NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker) );
2003-09-07 22:28:46 +00:00
float fNewBPM = fOldBPM * fScale;
m_pSong->SetBPMAtBeat( NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker), fNewBPM );
m_pSong->SetBPMAtBeat( NoteRowToBeat(iNewClipboardEndBeat), fOldBPM );
2003-09-07 22:28:46 +00:00
}
break;
2003-02-18 23:15:38 +00:00
case play:
{
ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 );
2003-02-18 23:15:38 +00:00
2003-07-26 22:53:22 +00:00
SOUND->PlayMusic("");
2005-04-14 06:34:17 +00:00
TransitionEditState( STATE_PLAYING );
2005-01-15 04:15:15 +00:00
m_sprOverlay->PlayCommand( "Play" );
2004-02-01 02:05:09 +00:00
GAMESTATE->m_bPastHereWeGo = true;
2003-02-18 23:15:38 +00:00
/* Reset the note skin, in case preferences have changed. */
GAMESTATE->ResetNoteSkins();
2003-06-25 05:35:14 +00:00
/* Give a 1 measure lead-in. Set this before loading Player, so it knows
* where we're starting. */
float fSeconds = m_pSong->m_Timing.GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker) - 4 );
2004-01-26 20:56:58 +00:00
GAMESTATE->UpdateSongPosition( fSeconds, m_pSong->m_Timing );
/* If we're in course display mode, set that up. */
2004-01-26 20:56:58 +00:00
SetupCourseAttacks();
2003-06-25 05:35:14 +00:00
m_Player.Load( m_NoteDataEdit );
GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerController = PREFSMAN->m_bAutoPlay?PC_AUTOPLAY:PC_HUMAN;
2003-02-18 23:15:38 +00:00
2003-06-25 05:35:14 +00:00
const float fStartSeconds = m_pSong->GetElapsedTimeFromBeat(GAMESTATE->m_fSongBeat) ;
2003-02-25 00:33:42 +00:00
LOG->Trace( "Starting playback at %f", fStartSeconds );
if( PREFSMAN->m_bEditorShowBGChangesPlay )
{
/* FirstBeat affects backgrounds, so commit changes to memory (not to disk)
* and recalc it. */
2004-05-24 06:12:17 +00:00
Steps* pSteps = GAMESTATE->m_pCurSteps[PLAYER_1];
2004-05-24 03:41:39 +00:00
ASSERT( pSteps );
pSteps->SetNoteData( m_NoteDataEdit );
m_pSong->ReCalculateRadarValuesAndLastBeat();
m_Background.Unload();
m_Background.LoadFromSong( m_pSong );
m_Foreground.Unload();
m_Foreground.LoadFromSong( m_pSong );
}
RageSoundParams p;
p.SetPlaybackRate( GAMESTATE->m_SongOptions.m_fMusicRate );
p.m_StartSecond = fStartSeconds;
p.AccurateSync = true;
p.StopMode = RageSoundParams::M_CONTINUE;
m_soundMusic.Play( &p );
2003-02-18 23:15:38 +00:00
}
break;
case record:
{
ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 );
2003-02-18 23:15:38 +00:00
2003-07-26 22:53:22 +00:00
SOUND->PlayMusic("");
2005-04-14 06:34:17 +00:00
TransitionEditState( STATE_RECORDING );
2005-01-15 04:15:15 +00:00
m_sprOverlay->PlayCommand( "Record" );
2004-02-01 02:05:09 +00:00
GAMESTATE->m_bPastHereWeGo = true;
2003-02-18 23:15:38 +00:00
/* Reset the note skin, in case preferences have changed. */
GAMESTATE->ResetNoteSkins();
2003-02-18 23:15:38 +00:00
// initialize m_NoteFieldRecord
m_NoteDataRecord.SetNumTracks( m_NoteDataEdit.GetNumTracks() );
m_NoteDataRecord.CopyAll( m_NoteDataEdit );
m_NoteFieldRecord.Load( &m_NoteDataRecord, -150, 350 );
2003-02-18 23:15:38 +00:00
GAMESTATE->m_fSongBeat = NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker - ROWS_PER_MEASURE ); // give a 1 measure lead-in
2003-02-25 00:33:42 +00:00
float fStartSeconds = m_pSong->GetElapsedTimeFromBeat(GAMESTATE->m_fSongBeat);
LOG->Trace( "Starting playback at %f", fStartSeconds );
RageSoundParams p;
p.SetPlaybackRate( GAMESTATE->m_SongOptions.m_fMusicRate );
p.m_StartSecond = fStartSeconds;
p.AccurateSync = true;
p.StopMode = RageSoundParams::M_CONTINUE;
m_soundMusic.Play( &p );
2003-02-18 23:15:38 +00:00
}
break;
case insert_and_shift:
NoteDataUtil::ShiftRows( m_NoteDataEdit, BeatToNoteRow(GAMESTATE->m_fSongBeat), BeatToNoteRow(1) );
2003-02-18 23:15:38 +00:00
break;
case delete_and_shift:
NoteDataUtil::ShiftRows( m_NoteDataEdit, BeatToNoteRow(GAMESTATE->m_fSongBeat), BeatToNoteRow(-1) );
break;
case shift_pauses_forward:
m_pSong->m_Timing.ShiftRows( BeatToNoteRow(GAMESTATE->m_fSongBeat), BeatToNoteRow(+1) );
break;
case shift_pauses_backward:
m_pSong->m_Timing.ShiftRows( BeatToNoteRow(GAMESTATE->m_fSongBeat), BeatToNoteRow(-1) );
2003-02-18 23:15:38 +00:00
break;
2003-11-03 08:44:49 +00:00
// MD 11/02/03 - Converting selected region to a pause of the same length.
case convert_beat_to_pause:
{
ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 );
float fMarkerStart = m_pSong->m_Timing.GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker) );
float fMarkerEnd = m_pSong->m_Timing.GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker) );
2004-02-23 17:18:02 +00:00
float fStopLength = fMarkerEnd - fMarkerStart;
2003-11-03 08:44:49 +00:00
// be sure not to clobber the row at the start - a row at the end
// can be dropped safely, though
NoteDataUtil::ShiftRows( m_NoteDataEdit,
m_NoteFieldEdit.m_iBeginMarker + 1,
-m_NoteFieldEdit.m_iEndMarker+m_NoteFieldEdit.m_iBeginMarker
2003-11-03 08:44:49 +00:00
);
m_pSong->m_Timing.ShiftRows( m_NoteFieldEdit.m_iBeginMarker + 1,
-m_NoteFieldEdit.m_iEndMarker+m_NoteFieldEdit.m_iBeginMarker
);
2003-11-03 08:44:49 +00:00
unsigned i;
2003-12-18 04:48:26 +00:00
for( i=0; i<m_pSong->m_Timing.m_StopSegments.size(); i++ )
2003-11-03 08:44:49 +00:00
{
float fStart = m_pSong->m_Timing.GetElapsedTimeFromBeat(NoteRowToBeat(m_pSong->m_Timing.m_StopSegments[i].m_iStartRow));
2004-02-23 17:18:02 +00:00
float fEnd = fStart + m_pSong->m_Timing.m_StopSegments[i].m_fStopSeconds;
if( fStart > fMarkerEnd || fEnd < fMarkerStart )
continue;
else {
if( fStart > fMarkerStart )
m_pSong->m_Timing.m_StopSegments[i].m_iStartRow = m_NoteFieldEdit.m_iBeginMarker;
2004-02-23 17:18:02 +00:00
m_pSong->m_Timing.m_StopSegments[i].m_fStopSeconds = fStopLength;
2003-11-03 08:44:49 +00:00
break;
2004-02-23 17:18:02 +00:00
}
2003-11-03 08:44:49 +00:00
}
2003-12-18 04:48:26 +00:00
if( i == m_pSong->m_Timing.m_StopSegments.size() ) // there is no BPMSegment at the current beat
m_pSong->AddStopSegment( StopSegment(m_NoteFieldEdit.m_iBeginMarker, fStopLength) );
m_NoteFieldEdit.m_iEndMarker = -1;
2003-11-03 08:44:49 +00:00
break;
}
// MD 11/02/03 - Converting a pause at the current beat into beats.
// I know this will break holds that cross the pause. Anyone who
// wants to rewrite this to fix that behavior is welcome to - I'm
// not sure how exactly to do it without making this a lot longer
// than it is.
// NOTE: Fixed this so that holds aren't broken by it. Working in 2s and
// 3s makes this work better, too. :-) It sorta makes you wonder WHY we
// don't bring it into 2s and 3s when we bring up the editor.
2003-11-03 08:44:49 +00:00
case convert_pause_to_beat:
{
float fBPMatPause = m_pSong->GetBPMAtBeat( GAMESTATE->m_fSongBeat );
unsigned i;
2003-12-18 04:48:26 +00:00
for( i=0; i<m_pSong->m_Timing.m_StopSegments.size(); i++ )
2003-11-03 08:44:49 +00:00
{
if( m_pSong->m_Timing.m_StopSegments[i].m_iStartRow == BeatToNoteRow(GAMESTATE->m_fSongBeat) )
2003-11-03 08:44:49 +00:00
break;
}
2003-12-18 04:48:26 +00:00
if( i == m_pSong->m_Timing.m_StopSegments.size() ) // there is no BPMSegment at the current beat
2003-11-03 08:44:49 +00:00
break;
2003-12-18 04:48:26 +00:00
else // StopSegment being modified is m_Timing.m_StopSegments[i]
2003-11-03 08:44:49 +00:00
{
2003-12-18 04:48:26 +00:00
float fStopLength = m_pSong->m_Timing.m_StopSegments[i].m_fStopSeconds;
m_pSong->m_Timing.m_StopSegments.erase( m_pSong->m_Timing.m_StopSegments.begin()+i,
m_pSong->m_Timing.m_StopSegments.begin()+i+1);
2004-02-23 17:18:02 +00:00
fStopLength *= fBPMatPause;
fStopLength /= 60;
2003-11-03 08:44:49 +00:00
// don't move the step from where it is, just move everything later
NoteDataUtil::ShiftRows( m_NoteDataEdit, BeatToNoteRow(GAMESTATE->m_fSongBeat) + 1, BeatToNoteRow(fStopLength) );
m_pSong->m_Timing.ShiftRows( BeatToNoteRow(GAMESTATE->m_fSongBeat) + 1, BeatToNoteRow(fStopLength) );
2003-11-03 08:44:49 +00:00
}
}
2005-03-23 10:43:57 +00:00
break;
case undo:
Undo();
break;
2003-02-18 23:15:38 +00:00
default:
ASSERT(0);
};
2005-03-23 10:43:57 +00:00
if( bSaveUndo )
CheckNumberOfNotesAndUndo();
2003-02-18 23:15:38 +00:00
}
2005-03-20 20:13:27 +00:00
void ScreenEdit::HandleStepsInformationChoice( StepsInformationChoice c, const vector<int> &iAnswers )
2002-08-17 06:44:04 +00:00
{
2004-05-24 06:12:17 +00:00
Steps* pSteps = GAMESTATE->m_pCurSteps[PLAYER_1];
2003-02-19 05:46:09 +00:00
Difficulty dc = (Difficulty)iAnswers[difficulty];
2004-05-24 03:41:39 +00:00
pSteps->SetDifficulty( dc );
2003-02-19 05:46:09 +00:00
int iMeter = iAnswers[meter]+1;
2004-05-24 03:41:39 +00:00
pSteps->SetMeter( iMeter );
2003-02-18 23:15:38 +00:00
switch( c )
{
2003-02-19 05:46:09 +00:00
case description:
2005-03-23 04:08:27 +00:00
SCREENMAN->TextEntry(
SM_None,
"Enter a description.",
m_pSteps->GetDescription(),
2005-04-13 08:05:48 +00:00
(dc == DIFFICULTY_EDIT) ? MAX_EDIT_DESCRIPTION_LENGTH : 255,
2005-03-23 05:12:31 +00:00
NULL,
2005-03-23 04:08:27 +00:00
ChangeDescription,
NULL
);
2003-02-18 23:15:38 +00:00
break;
2003-02-19 05:46:09 +00:00
}
2002-08-17 06:44:04 +00:00
}
2003-02-18 23:15:38 +00:00
2005-03-20 20:13:27 +00:00
void ScreenEdit::HandleSongInformationChoice( SongInformationChoice c, const vector<int> &iAnswers )
2003-02-18 23:15:38 +00:00
{
2003-02-19 05:46:09 +00:00
Song* pSong = GAMESTATE->m_pCurSong;
2003-02-18 23:15:38 +00:00
switch( c )
{
case main_title:
2005-03-23 05:12:31 +00:00
SCREENMAN->TextEntry( SM_None, "Edit main title.\nPress Enter to confirm,\nEscape to cancel.", pSong->m_sMainTitle, 100, NULL, ChangeMainTitle, NULL );
2003-02-18 23:15:38 +00:00
break;
case sub_title:
2005-03-23 05:12:31 +00:00
SCREENMAN->TextEntry( SM_None, "Edit sub title.\nPress Enter to confirm,\nEscape to cancel.", pSong->m_sSubTitle, 100, NULL, ChangeSubTitle, NULL );
2003-02-18 23:15:38 +00:00
break;
case artist:
2005-03-23 05:12:31 +00:00
SCREENMAN->TextEntry( SM_None, "Edit artist.\nPress Enter to confirm,\nEscape to cancel.", pSong->m_sArtist, 100, NULL, ChangeArtist, NULL );
2003-02-18 23:15:38 +00:00
break;
2003-06-23 02:24:13 +00:00
case credit:
2005-03-23 05:12:31 +00:00
SCREENMAN->TextEntry( SM_None, "Edit credit.\nPress Enter to confirm,\nEscape to cancel.", pSong->m_sCredit, 100, NULL, ChangeCredit, NULL );
2003-06-23 02:24:13 +00:00
break;
2003-02-18 23:15:38 +00:00
case main_title_transliteration:
2005-03-23 05:12:31 +00:00
SCREENMAN->TextEntry( SM_None, "Edit main title transliteration.\nPress Enter to confirm,\nEscape to cancel.", pSong->m_sMainTitleTranslit, 100, NULL, ChangeMainTitleTranslit, NULL );
2003-02-18 23:15:38 +00:00
break;
case sub_title_transliteration:
2005-03-23 05:12:31 +00:00
SCREENMAN->TextEntry( SM_None, "Edit sub title transliteration.\nPress Enter to confirm,\nEscape to cancel.", pSong->m_sSubTitleTranslit, 100, NULL, ChangeSubTitleTranslit, NULL );
2003-02-18 23:15:38 +00:00
break;
case artist_transliteration:
2005-03-23 05:12:31 +00:00
SCREENMAN->TextEntry( SM_None, "Edit artist transliteration.\nPress Enter to confirm,\nEscape to cancel.", pSong->m_sArtistTranslit, 100, NULL, ChangeArtistTranslit, NULL );
2003-02-18 23:15:38 +00:00
break;
default:
ASSERT(0);
};
}
2005-03-20 06:41:56 +00:00
void ScreenEdit::HandleBGChangeChoice( BGChangeChoice c, const vector<int> &iAnswers )
{
BackgroundChange newChange;
FOREACH( BackgroundChange, m_pSong->m_BackgroundChanges, iter )
{
if( iter->m_fStartBeat == GAMESTATE->m_fSongBeat )
{
newChange = *iter;
// delete the old change. We'll add a new one below.
m_pSong->m_BackgroundChanges.erase( iter );
break;
}
}
newChange.m_fStartBeat = GAMESTATE->m_fSongBeat;
switch( c )
{
case add_random:
newChange.m_sBGName = "-random-";
break;
case add_song_bganimation:
case add_song_movie:
2003-04-13 23:22:27 +00:00
case add_song_still:
case add_global_random_movie:
case add_global_bganimation:
case add_global_visualization:
2005-03-20 06:41:56 +00:00
newChange.m_sBGName = g_BackgroundChange.rows[c].choices[iAnswers[c]];
break;
case delete_change:
newChange.m_sBGName = "";
break;
default:
break;
};
2005-03-20 06:41:56 +00:00
newChange.m_fRate = strtof( g_BackgroundChange.rows[rate].choices[iAnswers[rate]], NULL )/100.f;
newChange.m_bFadeLast = !!iAnswers[fade_last];
newChange.m_bRewindMovie = !!iAnswers[rewind_movie];
newChange.m_bLoop = !!iAnswers[loop];
if( newChange.m_sBGName != "" )
m_pSong->AddBackgroundChange( newChange );
}
2004-01-26 20:56:58 +00:00
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;
2004-01-26 20:56:58 +00:00
// Put course options into effect.
GAMESTATE->m_pPlayerState[PLAYER_1]->m_ModsToApply.clear();
2004-01-26 20:56:58 +00:00
GAMESTATE->RemoveActiveAttacksForPlayer( PLAYER_1 );
if( m_pAttacksFromCourse )
{
m_pAttacksFromCourse->LoadFromCRSFile( m_pAttacksFromCourse->m_sPath );
AttackArray Attacks;
for( unsigned e = 0; e < m_pAttacksFromCourse->m_entries.size(); ++e )
{
if( m_pAttacksFromCourse->m_entries[e].type != COURSE_ENTRY_FIXED )
continue;
if( m_pAttacksFromCourse->m_entries[e].pSong != m_pSong )
continue;
Attacks = m_pAttacksFromCourse->m_entries[e].attacks;
break;
}
for( unsigned i=0; i<Attacks.size(); ++i )
GAMESTATE->LaunchAttack( PLAYER_1, Attacks[i] );
}
GAMESTATE->RebuildPlayerOptionsFromActiveAttacks( PLAYER_1 );
}
2004-06-08 05:22:33 +00:00
2005-03-08 21:19:17 +00:00
void ScreenEdit::CopyToLastSave()
{
m_songLastSave = *GAMESTATE->m_pCurSong;
if( GAMESTATE->m_pCurSteps[PLAYER_1] )
m_stepsLastSave = *GAMESTATE->m_pCurSteps[PLAYER_1];
2005-03-08 21:19:17 +00:00
}
void ScreenEdit::CopyFromLastSave()
{
*GAMESTATE->m_pCurSong = m_songLastSave;
if( GAMESTATE->m_pCurSteps[PLAYER_1] )
*GAMESTATE->m_pCurSteps[PLAYER_1] = m_stepsLastSave;
2005-03-08 21:19:17 +00:00
}
2005-03-23 10:43:57 +00:00
void ScreenEdit::SaveUndo()
{
m_bHasUndo = true;
2005-03-23 10:43:57 +00:00
m_Undo.CopyAll( m_NoteDataEdit );
}
void ScreenEdit::Undo()
{
m_NoteDataEdit.CopyAll( m_Undo );
m_bHasUndo = false;
2005-03-23 10:43:57 +00:00
m_Undo.ClearAll();
}
void ScreenEdit::CheckNumberOfNotesAndUndo()
{
for( int row=0; row<=m_NoteDataEdit.GetLastRow(); row+=ROWS_PER_MEASURE )
{
int iNumNotesThisMeasure = 0;
FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( m_NoteDataEdit, r, row, row+ROWS_PER_MEASURE )
iNumNotesThisMeasure += m_NoteDataEdit.GetNumTapNonEmptyTracks( r );
if( iNumNotesThisMeasure > MAX_NOTES_PER_MEASURE )
{
Undo();
2005-03-23 10:56:51 +00:00
CString sError = ssprintf(
"This change creates more than %d notes in a measure.\n\nMore than %d notes per measure is not allowed. This change has been reverted.",
MAX_NOTES_PER_MEASURE, MAX_NOTES_PER_MEASURE );
SCREENMAN->Prompt( SM_None, sError );
2005-03-23 10:43:57 +00:00
return;
}
}
if( GAMESTATE->m_pCurSteps[0]->IsAnEdit() )
{
// Check that the action didn't push notes any farther past the last measure.
// This blocks Insert Beat from pushing past the end, but allows Delete Beat
// to pull back the notes that are already past the end.
float fNewLastBeat = m_NoteDataEdit.GetLastBeat();
bool bLastBeatIncreased = fNewLastBeat > m_Undo.GetLastBeat();
bool bPassedTheEnd = fNewLastBeat > GetMaximumBeatForNewNote();
if( bLastBeatIncreased && bPassedTheEnd )
{
Undo();
CString sError = ssprintf(
"This change creates notes past the end of the music and is not allowed.\n\nThe change has been reverted.",
MAX_NOTES_PER_MEASURE, MAX_NOTES_PER_MEASURE );
SCREENMAN->Prompt( SM_None, sError );
return;
}
}
2005-03-23 10:43:57 +00:00
}
float ScreenEdit::GetMaximumBeatForNewNote() const
{
if( GAMESTATE->m_pCurSteps[0]->IsAnEdit() )
{
float fEndBeat = GAMESTATE->m_pCurSong->m_fLastBeat;
// Round up to the next measure end. Some songs end on weird beats
// mid-measure, and it's odd to have movement capped to these weird
// beats.
fEndBeat += BEATS_PER_MEASURE;
fEndBeat = ftruncf( fEndBeat, (float)BEATS_PER_MEASURE );
return fEndBeat;
}
else
{
return FLT_MAX;
}
}
float ScreenEdit::GetMaximumBeatForMoving() const
{
float fEndBeat = GetMaximumBeatForNewNote();
// Jump to GetLastBeat even if it's past m_pCurSong->m_fLastBeat
// so that users can delete garbage steps past then end that they have
// have inserted in a text editor. Once they delete all steps on
// GetLastBeat() and move off of that beat, they won't be able to return.
fEndBeat = max( fEndBeat, m_NoteDataEdit.GetLastBeat() );
return fEndBeat;
}
2004-06-08 05:22:33 +00:00
/*
* (c) 2001-2004 Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/