From 4558db37bb7bcfe81aa928b5956d75380d7cc804 Mon Sep 17 00:00:00 2001 From: Chris Danford Date: Sat, 17 Aug 2002 06:44:04 +0000 Subject: [PATCH] added menu to editor --- stepmania/README-FIRST.TXT | 277 ++++++- stepmania/src/GameManager.cpp | 133 +++- stepmania/src/GameManager.h | 7 +- stepmania/src/NoteData.cpp | 2 +- stepmania/src/NoteField.cpp | 6 +- stepmania/src/Notes.cpp | 118 +++ stepmania/src/Notes.h | 1 + stepmania/src/Player.cpp | 10 +- stepmania/src/PrefsManager.cpp | 6 +- stepmania/src/ScreenEdit.cpp | 1081 +++++++++++++++------------ stepmania/src/ScreenEdit.h | 16 +- stepmania/src/ScreenEditMenu.cpp | 4 +- stepmania/src/ScreenSelectStyle.cpp | 2 +- stepmania/src/ScreenTitleMenu.cpp | 16 +- stepmania/src/SnapDisplay.cpp | 2 +- stepmania/src/SnapDisplay.h | 2 +- stepmania/src/Song.cpp | 49 ++ stepmania/src/Style.h | 1 + stepmania/src/StyleDef.h | 8 +- stepmania/src/song.h | 1 + 20 files changed, 1201 insertions(+), 541 deletions(-) diff --git a/stepmania/README-FIRST.TXT b/stepmania/README-FIRST.TXT index 6303a522d5..85a0305442 100644 --- a/stepmania/README-FIRST.TXT +++ b/stepmania/README-FIRST.TXT @@ -51,8 +51,25 @@ Table of Contents ************************************************************ StepMania game system is capable of playing many game types. Currently, it -supports games Dance Dance Revolution and Pump It Up, with future support for EZ -2 Dancer, BeatMania, Guitar Freaks, DrumMania, Para Para Paradise and more. +supports games similar to Dance Dance Revolution, Pump It Up, and EZ 2 +Dancer. In the future, it will support games similar to BeatMania, Guitar +Freaks, DrumMania, Para Para Paradise and more. + +StepMania is a rhythm game. Arrows pointing in different directions scroll +up from the bottom of the screen, and the player must hit the corresponding +direction in time to the music. The game can be played with your hands on +the keyboard, but the real fun comes when the arrows are registered by dancing +on a sensor-laden mat. The game is very similar to Konami's Dance Dance +Revolution and Andamiro's Pump It Up games, but while those play only their +own songs, StepMania can play any song that includes a step file. + +In Stepmania most popular mode, "dance", the player uses four arrows - up, +down, left, and right - , similar to Konami's Dance Dance Revolution series +of games. In "pump" mode, the player must deal with and five direction of +steps - ala Andamiro's Pump it Up games. + +Later versions of StepMania will support steps similar to Amuseworld's +EZ2Dancer games, as well as any that there is a sizable demand for. ************************************************************ @@ -61,7 +78,7 @@ supports games Dance Dance Revolution and Pump It Up, with future support for EZ * Windows 98, Windows ME, Windows 2000, or Windows XP * Pentium II, Pentium III, Celeron, Athlon, or compatible processor, 266MHz - minimum (400 MHz highly recommended) + minimum (400 MHz recommended) * 64 MB of RAM * Video card that supports High Color (16-bit color) and has 16MB video RAM * DirectX 8.1 compatible video card with drivers @@ -116,6 +133,254 @@ In gameplay: * Hold Escape = abort playing +************************************************************ +6. Playing the Game +************************************************************ + +This section primarily covers StepMania's most popular game type, "dance". +The various games supported by StepMania are similar, and much of this +information applies to other games too. + +Title Menu screen: At the title screen are a series of options. + + * Game Start: + Begin playing the game and go to the Style Select screen. Make sure + you've configured your keyboard or dance pad before chosing this + option. + * Switch Game: + Allows you to chose between the various games supported by StepMania + (dance, pump, ez2, etc). + * Config Key/Joy: + This is where you go to assign key presses or pad presses. You'll + want to use this screen before playing. + * Game Options: + This is you can adjust properties of the game, like difficulty + and number of stages. + * Game Options: + This is you can adjust graphic detail and other settings that + the performance of the game. + * Appearance Options: + Here, you can customize the appearance of StepMania by chosing the + announcer, theme, and note skin. + * Edit/Record/Synch: + In this mode, you can edit songs and step patterns, or create your + own step patterns from scratch. + * Exit: + Exits the program. + * At the upper-left corner is the total number of songs found when + StepMania perused your songs foler on startup. + * At the upper-right is your version of StepMania. + + +Config Key/Joy screen: + + This menu allows you to map up to 2 keyboard/joystick buttons to each + function in the game. The third column is the default key mapping, and + cannot be changed. However, you can override a default keyboard key by + simply assigning it to another function. The mappings for player 1 are + on the left half of the screen, and the mapping for player 2 are on right + half. + + +Appearance Options screen: + + * Display: + Toggles between Fullscreen mode, in which StepMania is the only + program visible and takes up the entire screen, and Windowed mode, + in which StepMania runs in a window and can be moved about on your + desktop and minimized or maximized, much like any other window. + Many users have found that one mode or the other is more efficient + and produces a smoother game. This varies depending on memory and + video functionality. + * Display Res: + This switches between various standard resolutions of the screen. + A higher number of pixels implies a sharper image, but requires more + computer power. + * Texture Res: + Adjusts the resolution (pixel density) of video textures used in the + game. More detail requires a more powerful computer. + * Refresh Rate: + Sets the number of times that the screen will be redrawn in 1 second. + Note that this setting will only have an effect in Fullscreen mode. + 'Default' uses the system default refresh rate (60Hz on most computers). + * Ignore JoyAxes: + Many dance mat drivers (if you're using a dance mat) map the arrows + as directions on a joystick axis. A joystick cannot, logically, be + in more than one place at a time, such as left but also right. In + the game, it is possible to hit two directions at once (in fact, + required at times) and switching this setting to 'on' will make + StepMania ignore the joystick requirement so that your dance mat + will correctly register two arrows at once. See section in the README + "Connecting Dance Pads" for more information on what adapters to use. + * Menu Buttons: + Toggles whether or not the menus will respond to the gameplay buttons. + If not, dedicated buttons for menu navigation will be required. + * Show FPS: + Displays the current frames-per-second in the upper right side of the + screen. + * BG Mode: + This controls the state of the background behind the arrows. + OFF - Only the background graphic of the song is displayed. + ANIMATIONS - Along with the background graphic, animated graphics + (found in the BGAnimations folder) will dance around behind the + arrows. Keep in mind that the animation files are small graphics, + and must be loaded on the fly. On slower computers, this will + cause jumpiness during the song. If this is a problem, try + changing to Visualizations or even off. + VISUALIZATIONS - Along with the background graphic, movies (found in + the Visualizations folder) will be played. The default StepMania + Visualizations pack (available at www.stepmania.com) contains + swirling and twisting effects, but in theory any AVI or MPEG video + can be used. You must have the DivX codec installed on your + computer for this to work. Keep in mind that DivX decoding is + processor-intensive, and will decrease the framerate. Slower + computers will have a hard time playing StepMania AND decoding + DivX backgrounds. + RANDOM MOVIES - Movie files from the "RandomMovies" folder will be + played as the background for the song. + Sample animations, visualizations, and random movies can be found at + www.stepmania.com. + * BG Brightness: + Adjusts the brightness level of the backgrounds. Since the + backgrounds and the arrows are both brightly colored, darkening the + backgrounds makes the arrows more visible. + * Menu Timer: + Toggles whether or not StepMania will place a time limit on using any + given menu. This limit is usually in the upper-right corner of the + screen. + * Event Mode: + If set to ON, there is no limit to the number of songs played. The + player goes back to the Select Music screen even after failing a song, + and continues to do so until they press Esc to move back a menu. If + set to OFF, the game will end after a number of songs specified in + 'Arcade stages', the next option down. + * Arcade Stages: + If Event Mode is OFF, this is the number of songs that can + successfully be cleared before the game over screen is displayed. + * Judge Difficulty: + How accurate the player must be in stepping to get a better score for + the step. A higher number means they must be closer to the actual + timing of the arrow. Those of you who try to get all 'perfect' steps + will have a monster of a time with this setting all the way up. + * Life Difficulty: + How difficult it is to keep the life meter at the top of the screen + up. The higher this number, the less it will increase for precise + steps, and the more it will decrease for poorly timed steps. + * Auto Play: + The game will play as normal, but will hit all the arrows of its own + accord, without the player's input. It also will get a perfect on + every step. This will be saved as a high score for the song. + + +Appearance Options Menu: + + * Announcer: + Select from the installed Announcer packs. Get more at + www.stepmania.com. + * Theme: + Select from installed Theme packs. Themes change the look of Stepmania. + Get more at www.stepmania.com. + * Note Skin: + Change the appearance of the arrows in the game by selecting from the + available packs. + Announcer, theme, and note skin packs can be dowloaded from + www.stepmania.com. + + +Song Options Menu + +Upon selecting a song, the words 'Press NEXT for options' will appear on the screen. If you press the 'next' button (enter by default) you will come to the Song Options menu, which contains a variety of settings for changing the way the song and arrows are played. + +Speed: The stream of arrows can be stretched out so that it comes faster, but the arrows are more spaced out. It can be left at 1x (normal speed) or stretched by multiples of .5, .75, 1.5, 2, 3, 5, or even 8 times the original speed. + +Effect: Each of the effects changes the arrows themselves in some way, usually in such a way as to make them more obscure. Consider these challenege modes. + +Off - No effect, normal arrow scrolling. +Boost - Also known as 'parabolic' in some circles, this makes the arrows start up slowly and accelerate towards the top. +Wave - Arrows alternately speed up and slow down. +Drunk - Arrows sway back and forth as they scroll. +Dizzy - Arrows spin as they scroll. +Space - Similar to the scrolling effect in the Star Wars intros, arrows scroll away from the player. +Mini - Arrows are really small. + +Appear: These change the visibility of the arrows. + +Visible - Normal arrow visibility. +Hidden - Arrows disappear before they reach the top. +Sudden - Arrows are invisible until close to the top. +Stealth - Arrows are completely invisible. The only way to get them is to either memorize the song, watch another player perform the same song at the same time as you on the same difficulty setting, or be really really lucky. + +Turn: These rotate the arrows. The arrows will show up on screen in their rotated positions. + +Off - Normal arrows, unchanged from how they are in the step file +Mirror - Steps are rotated 180 degrees. Up becomes a down. +Left - Steps are rotated 90 degrees left. Up becomes a left. +Right - Steps are rotated 90 degrees right. Up becomes a right. +Shuffle - All steps in the step file are randomly shuffled. + +Little: Removes any arrows that aren't on the quarter beats. + +Scroll: BY reversing the scroll, the arrows will scroll from the top down instead of from the bottom up. + +Color: Changes the arrow colors. + +Vivid - Arrows cycle colors, and off-beat arrows are at different parts of the cycle so as to be easily identifiable. +Note - Off-beat arrows are a different color from on-beat arrows, but colors do not cycle. +Flat - Off-beat arrows are the same color as on-beat arrows +Plain - Same as flat, with the addition that notes do not cycle colors. + +Holds: If this is set to OFF, there will only be a normal arrow in place of any hold arrows that may appear. Some players don't like hold arrows. + +Dark: This removes the grey arrows from the top of the screen, so that the player can't use them as a reference as to when to hit the proper arrow. + +Life Type: Switch between BAR, where there is a meter that can be increased with accurate steps and decreased with poor steps, and BATTERY, where the player gets a set number of batteries, similar to 'lives' in most games, which are removed as they player misses steps. + +Bar Drain: Functional only if Life Type is set to BAR. Switch between three ways the life meter can function. + +Normal - Perfect and Great steps increase the bar, any others decrease it. +No Recover: Same as Normal but it can only go down, not up. Perfects and Greats leave it in place. +Sudden Death - Any step score other than Great or Perfect will automatically fail. + +Bat. Lives: Functional only when Life Type is set to BATTERY. This sets the number of batteries the player gets. + +Fail: If you fail by missing enough steps, this is when the song ends. + +Arcade - Song will end as soon as you fail it. +End of Song - As the name implies, you will not fail out until the music end. You miss every step and the song will keep playing until it's finished. +Off - You cannot fail the song. + +Assist: Makes a 'clap' sound every time you are supposed to hit an arrow, to help the player acquaint his or herself with the song's rhythmic structure. + +Rate: This is the percent of normal speed that the song plays at. Any song can be speeded up or slowed down as much as 30%. This setting is not to correct a song that is misaligned to its steps, as the steps are also sped up or slowed down at the same rate that the song is. + + + +Select Style screen: This is the screen where you choose your style of play. + + * Single: + One player, playing on one four-panel pad. Second player need not apply. + * Versus: + Two players each with their own respective 4-panel pad and set of arrows. + Each player can choose their own difficulty, and each has their own set + of arrows to follow. At the end of the song each player will recieve a + separate grade. There is no interaction between players other than + comparing grades and, if you have dance mats, the possibility of crashing + into each other during play :-) + * Double: + Same as single, except that one player uses both player's pads, and must + contend with 8 arrows now instead of only four. The step listings for + doubles mode are separate from single or versus. Only files containing + such a set of steps will be displayed. + * Couple: + Very similar to versus, except that each player has a different set of + steps, and each player must choose the same skill level. Often stepfile + authors use this mode to choreograph a patern between the two players. + * Solo: + One player plays on six panels. Like double, this uses a different step + chart than single or versus or double does, and only files containing + that set of steps will be displayed. + + ************************************************************ 6. How StepMania Loads Songs ************************************************************ @@ -851,6 +1116,9 @@ BUG FIX: Autoplay no longer misses the first step if it lies on beat 0. NEW FEATURE: Support for holds notes in KSF. CHANGE: KSF title discovery will use song foler name if KSF file contains foreign characters. +BUG FIX: Stepping before start of a note at beat 0 no longer results in a BAD. +BUG FIX: Editor now works with dance-couple note patterns +BUG FIX: Lead-in/lead-out time added to Play and Record in editor. ------------------------CVS after 3.00 beta 5---------------- OPTIMIZATION: Much faster song loading. @@ -1274,9 +1542,10 @@ Bug fix: Good and Boo arrows not being drawn. ************************************************************ Thanks to: + Warrior Bob (Dave H) for helping with the readme! Dj Slash & Tony Thai for the caution graphic Kyle "KeeL" Ward for his awesome menu music (www.ampcast.com/keel) - Gotetsu for being a utility player + Gotetsu for helping track down bugs and other various tasks ************************************************************ End of document diff --git a/stepmania/src/GameManager.cpp b/stepmania/src/GameManager.cpp index 005997f4dc..55f8f06412 100644 --- a/stepmania/src/GameManager.cpp +++ b/stepmania/src/GameManager.cpp @@ -23,24 +23,15 @@ GameManager* GAMEMAN = NULL; // global and accessable from anywhere in our progr const int DANCE_COL_SPACING = 64; const int DANCE_6PANEL_VERSUS_COL_SPACING = 54; - - -// <<<<<<< GameManager.cpp -// const int PUMP_COL_SPACING = 60; +const int PUMP_COL_SPACING = 50; const int EZ2_COL_SPACING = 46; const int EZ2_DOUBLE_ADJUST = 150; -// ======= -const int PUMP_COL_SPACING = 50; -//const int EZ2_COL_SPACING = 50; // // Important: Every game must define the buttons: "Start", "Back", "MenuLeft", and "MenuRight" // - -// >>>>>>> 1.24 - GameDef g_GameDefs[NUM_GAMES] = { { // GAME_DANCE @@ -289,12 +280,14 @@ GameDef g_GameDefs[NUM_GAMES] = StyleDef g_StyleDefs[NUM_STYLES] = { { // STYLE_DANCE_SINGLE - GAME_DANCE, // m_Game - "dance-single", // m_szName - NOTES_TYPE_DANCE_SINGLE, // m_NotesType - StyleDef::ONE_PLAYER_ONE_CREDIT, // m_StyleType - { 160, 480 }, // m_iCenterX - 4, // m_iColsPerPlayer + GAME_DANCE, // m_Game + true, // m_bUsedForGameplay + true, // m_bUsedForEdit + "dance-single", // m_szName + NOTES_TYPE_DANCE_SINGLE, // m_NotesType + StyleDef::ONE_PLAYER_ONE_CREDIT, // m_StyleType + { 160, 480 }, // m_iCenterX + 4, // m_iColsPerPlayer { // m_ColumnInfo[NUM_PLAYERS][MAX_COLS_PER_PLAYER]; { // PLAYER_1 { TRACK_1, GAME_CONTROLLER_1, DANCE_BUTTON_LEFT, -DANCE_COL_SPACING*1.5f }, @@ -314,12 +307,14 @@ StyleDef g_StyleDefs[NUM_STYLES] = }, }, { // STYLE_DANCE_VERSUS - GAME_DANCE, // m_Game - "dance-versus", // m_szName - NOTES_TYPE_DANCE_SINGLE, // m_NotesType - StyleDef::TWO_PLAYERS_TWO_CREDITS, // m_StyleType - { 160, 480 }, // m_iCenterX - 4, // m_iColsPerPlayer + GAME_DANCE, // m_Game + true, // m_bUsedForGameplay + false, // m_bUsedForEdit + "dance-versus", // m_szName + NOTES_TYPE_DANCE_SINGLE, // m_NotesType + StyleDef::TWO_PLAYERS_TWO_CREDITS, // m_StyleType + { 160, 480 }, // m_iCenterX + 4, // m_iColsPerPlayer { // m_ColumnInfo[NUM_PLAYERS][MAX_COLS_PER_PLAYER]; { // PLAYER_1 { TRACK_1, GAME_CONTROLLER_1, DANCE_BUTTON_LEFT, -DANCE_COL_SPACING*1.5f }, @@ -339,12 +334,14 @@ StyleDef g_StyleDefs[NUM_STYLES] = }, }, { // STYLE_DANCE_DOUBLE - GAME_DANCE, // m_Game - "dance-double", // m_szName - NOTES_TYPE_DANCE_DOUBLE, // m_NotesType - StyleDef::ONE_PLAYER_TWO_CREDITS, // m_StyleType - { 320, 320 }, // m_iCenterX - 8, // m_iColsPerPlayer + GAME_DANCE, // m_Game + true, // m_bUsedForGameplay + true, // m_bUsedForEdit + "dance-double", // m_szName + NOTES_TYPE_DANCE_DOUBLE, // m_NotesType + StyleDef::ONE_PLAYER_TWO_CREDITS, // m_StyleType + { 320, 320 }, // m_iCenterX + 8, // m_iColsPerPlayer { // m_ColumnInfo[NUM_PLAYERS][MAX_COLS_PER_PLAYER]; { // PLAYER_1 { TRACK_1, GAME_CONTROLLER_1, DANCE_BUTTON_LEFT, -DANCE_COL_SPACING*3.5f }, @@ -373,6 +370,8 @@ StyleDef g_StyleDefs[NUM_STYLES] = }, { // StyleDef GAME_DANCE, // m_Game + true, // m_bUsedForGameplay + false, // m_bUsedForEdit "dance-couple", // m_szName NOTES_TYPE_DANCE_COUPLE, // m_NotesType StyleDef::TWO_PLAYERS_TWO_CREDITS, // m_StyleType @@ -386,10 +385,10 @@ StyleDef g_StyleDefs[NUM_STYLES] = { TRACK_4, GAME_CONTROLLER_1, DANCE_BUTTON_RIGHT, +DANCE_COL_SPACING*1.5f }, }, { // PLAYER_2 - { TRACK_1, GAME_CONTROLLER_2, DANCE_BUTTON_LEFT, -DANCE_COL_SPACING*1.5f }, - { TRACK_2, GAME_CONTROLLER_2, DANCE_BUTTON_DOWN, -DANCE_COL_SPACING*0.5f }, - { TRACK_3, GAME_CONTROLLER_2, DANCE_BUTTON_UP, +DANCE_COL_SPACING*0.5f }, - { TRACK_4, GAME_CONTROLLER_2, DANCE_BUTTON_RIGHT, +DANCE_COL_SPACING*1.5f }, + { TRACK_5, GAME_CONTROLLER_2, DANCE_BUTTON_LEFT, -DANCE_COL_SPACING*1.5f }, + { TRACK_6, GAME_CONTROLLER_2, DANCE_BUTTON_DOWN, -DANCE_COL_SPACING*0.5f }, + { TRACK_7, GAME_CONTROLLER_2, DANCE_BUTTON_UP, +DANCE_COL_SPACING*0.5f }, + { TRACK_8, GAME_CONTROLLER_2, DANCE_BUTTON_RIGHT, +DANCE_COL_SPACING*1.5f }, }, }, { // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER]; @@ -398,6 +397,8 @@ StyleDef g_StyleDefs[NUM_STYLES] = }, { // STYLE_DANCE_SOLO GAME_DANCE, // m_Game + true, // m_bUsedForGameplay + true, // m_bUsedForEdit "dance-solo", // m_szName NOTES_TYPE_DANCE_SOLO, // m_NotesType StyleDef::ONE_PLAYER_ONE_CREDIT, // m_StyleType @@ -425,6 +426,41 @@ StyleDef g_StyleDefs[NUM_STYLES] = 0,1,2,3,4,5 }, }, + { // STYLE_DANCE_DOUBLE + GAME_DANCE, // m_Game + false, // m_bUsedForGameplay + true, // m_bUsedForEdit + "dance-edit-couple", // m_szName + NOTES_TYPE_DANCE_COUPLE, // m_NotesType + StyleDef::ONE_PLAYER_TWO_CREDITS, // m_StyleType + { 320, 320 }, // m_iCenterX + 8, // m_iColsPerPlayer + { // m_ColumnInfo[NUM_PLAYERS][MAX_COLS_PER_PLAYER]; + { // PLAYER_1 + { TRACK_1, GAME_CONTROLLER_1, DANCE_BUTTON_LEFT, -DANCE_COL_SPACING*3.5f }, + { TRACK_2, GAME_CONTROLLER_1, DANCE_BUTTON_DOWN, -DANCE_COL_SPACING*2.5f }, + { TRACK_3, GAME_CONTROLLER_1, DANCE_BUTTON_UP, -DANCE_COL_SPACING*1.5f }, + { TRACK_4, GAME_CONTROLLER_1, DANCE_BUTTON_RIGHT, -DANCE_COL_SPACING*0.5f }, + { TRACK_5, GAME_CONTROLLER_2, DANCE_BUTTON_LEFT, +DANCE_COL_SPACING*0.5f }, + { TRACK_6, GAME_CONTROLLER_2, DANCE_BUTTON_DOWN, +DANCE_COL_SPACING*1.5f }, + { TRACK_7, GAME_CONTROLLER_2, DANCE_BUTTON_UP, +DANCE_COL_SPACING*2.5f }, + { TRACK_8, GAME_CONTROLLER_2, DANCE_BUTTON_RIGHT, +DANCE_COL_SPACING*3.5f }, + }, + { // PLAYER_2 + { TRACK_1, GAME_CONTROLLER_1, DANCE_BUTTON_LEFT, -DANCE_COL_SPACING*3.5f }, + { TRACK_2, GAME_CONTROLLER_1, DANCE_BUTTON_DOWN, -DANCE_COL_SPACING*2.5f }, + { TRACK_3, GAME_CONTROLLER_1, DANCE_BUTTON_UP, -DANCE_COL_SPACING*1.5f }, + { TRACK_4, GAME_CONTROLLER_1, DANCE_BUTTON_RIGHT, -DANCE_COL_SPACING*0.5f }, + { TRACK_5, GAME_CONTROLLER_2, DANCE_BUTTON_LEFT, +DANCE_COL_SPACING*0.5f }, + { TRACK_6, GAME_CONTROLLER_2, DANCE_BUTTON_DOWN, +DANCE_COL_SPACING*1.5f }, + { TRACK_7, GAME_CONTROLLER_2, DANCE_BUTTON_UP, +DANCE_COL_SPACING*2.5f }, + { TRACK_8, GAME_CONTROLLER_2, DANCE_BUTTON_RIGHT, +DANCE_COL_SPACING*3.5f }, + }, + }, + { // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER]; + 0,1,2,3,4,5,6,7 + }, + }, /* { // STYLE_DANCE_SOLO_VERSUS "dance-solo-versus", // m_szName NOTES_TYPE_DANCE_SOLO, // m_NotesType @@ -452,9 +488,11 @@ StyleDef g_StyleDefs[NUM_STYLES] = { // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER]; 0,5,1,4,2,3 // outside in }, - }, -*/ { // PUMP_STYLE_SINGLE + }, */ + { // PUMP_STYLE_SINGLE GAME_PUMP, // m_Game + false, // m_bUsedForGameplay + false, // m_bUsedForEdit "pump-single", // m_szName NOTES_TYPE_PUMP_SINGLE, // m_NotesType StyleDef::ONE_PLAYER_ONE_CREDIT, // m_StyleType @@ -482,6 +520,8 @@ StyleDef g_StyleDefs[NUM_STYLES] = }, { // PUMP_STYLE_VERSUS GAME_PUMP, // m_Game + false, // m_bUsedForGameplay + false, // m_bUsedForEdit "pump-versus", // m_szName NOTES_TYPE_PUMP_SINGLE, // m_NotesType StyleDef::TWO_PLAYERS_TWO_CREDITS, // m_StyleType @@ -509,6 +549,8 @@ StyleDef g_StyleDefs[NUM_STYLES] = }, { // PUMP_STYLE_DOUBLE GAME_PUMP, // m_Game + false, // m_bUsedForGameplay + false, // m_bUsedForEdit "pump-double", // m_szName NOTES_TYPE_PUMP_DOUBLE, // m_NotesType StyleDef::ONE_PLAYER_TWO_CREDITS, // m_StyleType @@ -548,6 +590,8 @@ StyleDef g_StyleDefs[NUM_STYLES] = { // EZ2_STYLE_SINGLE GAME_EZ2, // m_Game + false, // m_bUsedForGameplay + false, // m_bUsedForEdit "ez2-single", // m_szName NOTES_TYPE_EZ2_SINGLE, // m_NotesType StyleDef::ONE_PLAYER_ONE_CREDIT, // m_StyleType @@ -575,6 +619,8 @@ StyleDef g_StyleDefs[NUM_STYLES] = }, { // EZ2_STYLE_SINGLE_HARD GAME_EZ2, // m_Game + false, // m_bUsedForGameplay + false, // m_bUsedForEdit "ez2-single-hard", // m_szName NOTES_TYPE_EZ2_SINGLE_HARD, // m_NotesType StyleDef::ONE_PLAYER_ONE_CREDIT, // m_StyleType @@ -602,6 +648,8 @@ StyleDef g_StyleDefs[NUM_STYLES] = }, { // EZ2_STYLE_DOUBLE GAME_EZ2, // m_Game + false, // m_bUsedForGameplay + false, // m_bUsedForEdit "ez2-double", // m_szName NOTES_TYPE_EZ2_DOUBLE, // m_NotesType StyleDef::ONE_PLAYER_TWO_CREDITS, // m_StyleType @@ -639,6 +687,8 @@ StyleDef g_StyleDefs[NUM_STYLES] = }, { // EZ2_STYLE_REAL GAME_EZ2, // m_Game + false, // m_bUsedForGameplay + false, // m_bUsedForEdit "ez2-real", // m_szName NOTES_TYPE_EZ2_REAL, // m_NotesType StyleDef::ONE_PLAYER_ONE_CREDIT, // m_StyleType @@ -670,6 +720,8 @@ StyleDef g_StyleDefs[NUM_STYLES] = }, { // EZ2_STYLE_SINGLE_VERSUS GAME_EZ2, // m_Game + false, // m_bUsedForGameplay + false, // m_bUsedForEdit "ez2-single-versus", // m_szName NOTES_TYPE_EZ2_SINGLE, // m_NotesType StyleDef::TWO_PLAYERS_TWO_CREDITS, // m_StyleType @@ -697,6 +749,8 @@ StyleDef g_StyleDefs[NUM_STYLES] = }, { // EZ2_STYLE_SINGLE_VERSUS GAME_EZ2, // m_Game + false, // m_bUsedForGameplay + false, // m_bUsedForEdit "ez2-single-hard-versus", // m_szName NOTES_TYPE_EZ2_SINGLE_HARD, // m_NotesType StyleDef::TWO_PLAYERS_TWO_CREDITS, // m_StyleType @@ -722,9 +776,10 @@ StyleDef g_StyleDefs[NUM_STYLES] = 2,0,4,1,3 // This should be from back to front: Down, UpLeft, UpRight, Upper Left Hand, Upper Right Hand }, }, - { // EZ2_STYLE_REAL_VERSUS GAME_EZ2, // m_Game + false, // m_bUsedForGameplay + false, // m_bUsedForEdit "ez2-real-versus", // m_szName NOTES_TYPE_EZ2_REAL, // m_NotesType StyleDef::TWO_PLAYERS_TWO_CREDITS, // m_StyleType @@ -774,19 +829,19 @@ StyleDef* GameManager::GetStyleDefForStyle( Style s ) return &g_StyleDefs[ s ]; } -Style GameManager::GetStyleThatPlaysNotesType( NotesType nt ) +Style GameManager::GetEditStyleThatPlaysNotesType( NotesType nt ) { for( int i=0; i& aStylesAddTo ) +void GameManager::GetGameplayStylesForGame( Game game, CArray& aStylesAddTo ) { for( int s=0; s& aStylesAddTo ); - void GetNotesTypesForGame( Game game, CArray& aNotesTypeAddTo ); + void GetGameplayStylesForGame( Game game, CArray& aStylesAddTo ); // do not include edit-specific + void GetNotesTypesForGame( Game game, CArray& aNotesTypeAddTo ); // only look at edit-specific styles + Style GetEditStyleThatPlaysNotesType( NotesType nt ); // void GetGameNames( CStringArray &AddTo ); // bool DoesGameExist( CString sGameName ); diff --git a/stepmania/src/NoteData.cpp b/stepmania/src/NoteData.cpp index a1453477a2..d36e0f5400 100644 --- a/stepmania/src/NoteData.cpp +++ b/stepmania/src/NoteData.cpp @@ -259,7 +259,7 @@ void NoteData::AddHoldNote( HoldNote add ) void NoteData::RemoveHoldNote( int iHoldIndex ) { - ASSERT( iHoldIndex > 0 && iHoldIndex < m_iNumHoldNotes ); + ASSERT( iHoldIndex >= 0 && iHoldIndex < m_iNumHoldNotes ); HoldNote& hn = m_HoldNotes[iHoldIndex]; diff --git a/stepmania/src/NoteField.cpp b/stepmania/src/NoteField.cpp index 66777c4c22..2f7f985b4a 100644 --- a/stepmania/src/NoteField.cpp +++ b/stepmania/src/NoteField.cpp @@ -194,8 +194,10 @@ void NoteField::DrawPrimitives() // // Draw measure bars // - for( float b=fFirstBeatToDraw; b<=fLastBeatToDraw; b+=1 ) - DrawMeasureBar( int(b) ); + int iFirstMeasureToDraw = int(fFirstBeatToDraw)/BEATS_PER_MEASURE; + int iLastMeasureToDraw = (int(fLastBeatToDraw)/BEATS_PER_MEASURE)+1; + for( i=iFirstMeasureToDraw; i<=fLastBeatToDraw; i++ ) + DrawMeasureBar( i ); // // BPM text diff --git a/stepmania/src/Notes.cpp b/stepmania/src/Notes.cpp index 6508de6747..43e34a5b4c 100644 --- a/stepmania/src/Notes.cpp +++ b/stepmania/src/Notes.cpp @@ -585,6 +585,124 @@ void Notes::WriteSMNotesTag( FILE* fp ) fprintf( fp, "%s;\n", m_sSMNoteData ); } +struct DWICharLookup { + char c; + bool bCol[6]; +}; + +char NotesToDWIChar( bool bCol1, bool bCol2, bool bCol3, bool bCol4, bool bCol5, bool bCol6 ) +{ + const DWICharLookup lookup[] = { + { '0', 0, 0, 0, 0, 0, 0 }, + { '1', 0, 1, 1, 0, 0, 0 }, + { '2', 0, 0, 1, 0, 0, 0 }, + { '3', 0, 0, 1, 0, 1, 0 }, + { '4', 0, 1, 0, 0, 0, 0 }, + { '6', 0, 0, 0, 0, 1, 0 }, + { '7', 0, 1, 0, 1, 0, 0 }, + { '8', 0, 0, 0, 1, 0, 0 }, + { '9', 0, 0, 0, 1, 1, 0 }, + { 'A', 0, 0, 1, 1, 0, 0 }, + { 'B', 0, 1, 0, 0, 1, 0 }, + { 'C', 0, 1, 0, 0, 0, 0 }, + { 'D', 0, 0, 0, 0, 1, 0 }, + { 'E', 1, 1, 0, 0, 0, 0 }, + { 'F', 0, 1, 1, 0, 0, 0 }, + { 'G', 0, 1, 0, 1, 0, 0 }, + { 'H', 0, 1, 0, 0, 0, 1 }, + { 'I', 1, 0, 0, 0, 1, 0 }, + { 'J', 0, 0, 1, 0, 1, 0 }, + { 'K', 0, 0, 0, 1, 1, 0 }, + { 'L', 0, 0, 0, 0, 1, 1 }, + { 'M', 0, 1, 0, 0, 1, 0 }, + }; + const int iNumLookups = sizeof(lookup) / sizeof(DWICharLookup); + + for( int i=0; iGetNoteData( ¬edata ); + notedata.ConvertHoldNotesTo2sAnd3s(); + + fprintf( fp, "<" ); // begin a 48th note series + for( int r=0; r" ); // end series +} + void Notes::SetNoteData( NoteData* pNewNoteData ) { ASSERT( pNewNoteData->m_iNumTracks == NotesTypeToNumTracks(m_NotesType) ); diff --git a/stepmania/src/Notes.h b/stepmania/src/Notes.h index a6816da7c9..5ce4a46e13 100644 --- a/stepmania/src/Notes.h +++ b/stepmania/src/Notes.h @@ -42,6 +42,7 @@ public: CString sNoteDataOut ); void WriteSMNotesTag( FILE* fp ); + void WriteDWINotesTag( FILE* fp ); public: NotesType m_NotesType; diff --git a/stepmania/src/Player.cpp b/stepmania/src/Player.cpp index 4bafaa1386..118f8fff19 100644 --- a/stepmania/src/Player.cpp +++ b/stepmania/src/Player.cpp @@ -302,15 +302,12 @@ void Player::Step( int col ) int iCurrentIndexEarlier = iIndexStartLookingAt - delta; int iCurrentIndexLater = iIndexStartLookingAt + delta; - // silly check to make sure we don't go out of bounds - iCurrentIndexEarlier = clamp( iCurrentIndexEarlier, 0, MAX_TAP_NOTE_ROWS-1 ); - iCurrentIndexLater = clamp( iCurrentIndexLater, 0, MAX_TAP_NOTE_ROWS-1 ); - //////////////////////////// // check the step to the left of iIndexStartLookingAt //////////////////////////// //LOG->Trace( "Checking Notes[%d]", iCurrentIndexEarlier ); - if( m_TapNotes[col][iCurrentIndexEarlier] != '0' && // there is a note here + if( iCurrentIndexEarlier >= 0 && + m_TapNotes[col][iCurrentIndexEarlier] != '0' && // there is a note here m_TapNoteScores[col][iCurrentIndexEarlier] == TNS_NONE ) // this note doesn't have a score { iIndexOverlappingNote = iCurrentIndexEarlier; @@ -322,7 +319,8 @@ void Player::Step( int col ) // check the step to the right of iIndexStartLookingAt //////////////////////////// //LOG->Trace( "Checking Notes[%d]", iCurrentIndexLater ); - if( m_TapNotes[col][iCurrentIndexLater] != '0' && // there is a note here + if( iCurrentIndexLater >= 0 && + m_TapNotes[col][iCurrentIndexLater] != '0' && // there is a note here m_TapNoteScores[col][iCurrentIndexLater] == TNS_NONE ) // this note doesn't have a score { iIndexOverlappingNote = iCurrentIndexLater; diff --git a/stepmania/src/PrefsManager.cpp b/stepmania/src/PrefsManager.cpp index ce9d3949dd..54b8684926 100644 --- a/stepmania/src/PrefsManager.cpp +++ b/stepmania/src/PrefsManager.cpp @@ -22,9 +22,13 @@ PrefsManager* PREFSMAN = NULL; // global and accessable from anywhere in our pro PrefsManager::PrefsManager() { +#ifdef _DEBUG + m_bWindowed = true; +#else m_bWindowed = false; +#endif m_iDisplayResolution = 640; - m_iTextureResolution = 512; + m_iTextureResolution = 1024; m_iRefreshRate = 0; m_bIgnoreJoyAxes = false; m_bOnlyDedicatedMenuButtons = false; diff --git a/stepmania/src/ScreenEdit.cpp b/stepmania/src/ScreenEdit.cpp index c6060051ba..9945cd3cd0 100644 --- a/stepmania/src/ScreenEdit.cpp +++ b/stepmania/src/ScreenEdit.cpp @@ -23,45 +23,54 @@ #include "GameConstantsAndTypes.h" #include "RageLog.h" #include "GameState.h" -#include "GameState.h" // // Defines specific to GameScreenTitleMenu // - const float MAX_SECONDS_CAN_BE_OFF_BY = 0.20f; -const float GRAY_ARROW_Y = ARROW_SIZE * 1.5; +const float GRAY_ARROW_Y = ARROW_SIZE * 1.5; -const float DEBUG_X = SCREEN_LEFT + 10; -const float DEBUG_Y = CENTER_Y-100; +const float DEBUG_X = SCREEN_LEFT + 10; +const float DEBUG_Y = CENTER_Y-100; -const float HELP_X = SCREEN_LEFT + 10; -const float HELP_Y = CENTER_Y; // top aligned +const float HELP_X = SCREEN_LEFT + 10; +const float HELP_Y = SCREEN_BOTTOM - 10; -const float INFO_X = SCREEN_RIGHT - 10 ; -const float INFO_Y = SCREEN_BOTTOM - 10; // bottom aligned +const float SHORTCUTS_X = SCREEN_LEFT + 10; +const float SHORTCUTS_Y = SCREEN_TOP + 8; + +const float INFO_X = SCREEN_RIGHT - 10 ; +const float INFO_Y = SCREEN_BOTTOM - 10; const float MENU_WIDTH = 110; -const float EDIT_X = CENTER_X + 100; -const float EDIT_GRAY_Y = CENTER_Y - 2.0f * (float)ARROW_SIZE; +const float EDIT_X = CENTER_X; +const float EDIT_GRAY_Y = GRAY_ARROW_Y; const float PLAYER_X = EDIT_X; const float PLAYER_Y = SCREEN_TOP; +const float MENU_ITEM_X = CENTER_X-200; +const float MENU_ITEM_START_Y = SCREEN_TOP + 30; +const float MENU_ITEM_SPACING_Y = 24; + const CString HELP_TEXT = - "Esc: exit\n" - "S: save changes\n" + "Esc: show menu\n" + "Hold F1 to show keyboard shortcuts\n" "Up/Down: change beat\n" "Left/Right: change snap\n" "PgUp/PgDn: jump 1 measure\n" "Home/End: jump to first/last beat\n" "Number keys: add or remove tap note\n" "To create a hold note, hold a number key\n" - " while changing the beat pressing Up/Down\n" + " while changing the beat pressing Up/Down\n"; + +const CString SHORTCUT_TEXT = + "S: save changes\n" + "I: save as SM and DWI (lossy)\n" "Enter/Space: set begin/end selection markers\n" - "G/H/J/K/L: Snap selected notes to nearest\n" + "G/H/J/K/L: Snap selection to nearest\n" " 4th / 8th / 12th / 16th / 12th or 16th\n" "P: Play selected area\n" "R: Record in selected area\n" @@ -72,15 +81,56 @@ const CString HELP_TEXT = "D: Toggle difficulty\n" "Ins: Insert blank beat\n" "Del: Delete current beat and shift\n" - " Hold F keys for faster change:\n" "F7/F8: Decrease/increase BPM at cur beat\n" "F9/F10: Dec/inc freeze secs at cur beat\n" "F11/F12: Decrease/increase music offset\n" "F1/F2 : Dec/inc sample music start\n" + " Hold F keys for faster change:\n" "NumPad -/+: Dec/inc sample music length\n" "M: Play sample music\n"; - +const CString MENU_ITEM_TEXT[NUM_MENU_ITEMS] = { + "Set begin marker (Enter)", + "Set end marker (Space)", + "Snap selection to nearest quarter note (G)", + "Snap selection to nearest eighth note (H)", + "Snap selection to nearest triplet (J)", + "Snap selection to nearest sixteenth note (K)", + "Snap selection to nearest triplet or sixteenth note (L)", + "(P)lay selection", + "(R)ecord in selection", + "(T)oggle Play/Record rate", + "Cut selection (X)", + "Copy selection (C)", + "Paste clipboard at current beat (V)", + "Toggle (D)ifficulty", + "(Ins)ert blank beat and shift down", + "(Del)ete blank beat and shift up", + "Play sample (M)usic", + "(S)ave changes", + "(Q)uit" +}; +int MENU_ITEM_KEY[NUM_MENU_ITEMS] = { + DIK_RETURN, + DIK_SPACE, + DIK_G, + DIK_H, + DIK_J, + DIK_K, + DIK_L, + DIK_P, + DIK_R, + DIK_T, + DIK_X, + DIK_C, + DIK_V, + DIK_D, + DIK_INSERT, + DIK_DELETE, + DIK_M, + DIK_S, + DIK_Q, +}; const ScreenMessage SM_GoToPrevState = ScreenMessage(SM_User+1); const ScreenMessage SM_GoToNextState = ScreenMessage(SM_User+2); @@ -90,6 +140,14 @@ ScreenEdit::ScreenEdit() { LOG->Trace( "ScreenEdit::ScreenEdit()" ); + // set both players to joined so the credit message doesn't show + for( int p=0; pm_bIsJoined[p] = true; + } + SCREENMAN->RefreshCreditsMessages(); + + m_pSong = GAMESTATE->m_pCurSong; m_pNotes = GAMESTATE->m_pCurNotes[PLAYER_1]; @@ -138,7 +196,7 @@ ScreenEdit::ScreenEdit() m_SnapDisplay.SetXY( EDIT_X, EDIT_GRAY_Y ); - m_SnapDisplay.Load(); + m_SnapDisplay.Load( PLAYER_1 ); m_SnapDisplay.SetZoom( 0.5f ); m_GrayArrowRowEdit.SetXY( EDIT_X, EDIT_GRAY_Y ); @@ -178,10 +236,19 @@ ScreenEdit::ScreenEdit() m_textHelp.LoadFromFont( THEME->GetPathTo("Fonts","normal") ); m_textHelp.SetXY( HELP_X, HELP_Y ); m_textHelp.SetHorizAlign( Actor::align_left ); + m_textHelp.SetVertAlign( Actor::align_top ); m_textHelp.SetZoom( 0.5f ); m_textHelp.SetShadowLength( 2 ); m_textHelp.SetText( HELP_TEXT ); + m_textShortcuts.LoadFromFont( THEME->GetPathTo("Fonts","normal") ); + m_textShortcuts.SetXY( SHORTCUTS_X, SHORTCUTS_Y ); + m_textShortcuts.SetHorizAlign( Actor::align_left ); + m_textShortcuts.SetVertAlign( Actor::align_bottom ); + m_textShortcuts.SetZoom( 0.5f ); + m_textShortcuts.SetShadowLength( 2 ); + m_textShortcuts.SetText( SHORTCUT_TEXT ); + m_soundChangeLine.Load( THEME->GetPathTo("Sounds","edit change line"), 10 ); m_soundChangeSnap.Load( THEME->GetPathTo("Sounds","edit change snap") ); @@ -191,6 +258,16 @@ ScreenEdit::ScreenEdit() m_soundMusic.Load( m_pSong->GetMusicPath(), true ); // enable accurate sync + for( int i=0; iGetPathTo("Fonts","normal") ); + m_textMenu[i].SetXY( MENU_ITEM_X, MENU_ITEM_START_Y + MENU_ITEM_SPACING_Y*i ); + m_textMenu[i].SetHorizAlign( Actor::align_left ); + m_textMenu[i].SetZoom( 0.5f ); + m_textMenu[i].SetShadowLength( 2 ); + m_textMenu[i].SetText( MENU_ITEM_TEXT[i] ); + } + m_iMenuSelection = 0; m_Fade.OpenWipingRight(); } @@ -221,16 +298,22 @@ void ScreenEdit::Update( float fDeltaTime ) { GAMESTATE->m_fSongBeat = fSongBeat; - if( GAMESTATE->m_fSongBeat > m_NoteFieldEdit.m_fEndMarker ) + if( GAMESTATE->m_fSongBeat > m_NoteFieldEdit.m_fEndMarker + 4 ) // give a one measure lead out { if( m_EditMode == MODE_RECORDING ) { TransitionToEditFromRecord(); + GAMESTATE->m_fSongBeat = m_NoteFieldEdit.m_fEndMarker; + m_rectRecordBack.BeginTweening( 0.5f ); + m_rectRecordBack.SetDiffuseColor( D3DXCOLOR(0,0,0,0) ); } else if( m_EditMode == MODE_PLAYING ) { m_soundMusic.Stop(); m_EditMode = MODE_EDITING; + GAMESTATE->m_fSongBeat = m_NoteFieldEdit.m_fEndMarker; + m_rectRecordBack.BeginTweening( 0.5f ); + m_rectRecordBack.SetDiffuseColor( D3DXCOLOR(0,0,0,0) ); } } } @@ -242,11 +325,9 @@ void ScreenEdit::Update( float fDeltaTime ) m_Fade.Update( fDeltaTime ); m_textHelp.Update( fDeltaTime ); m_textInfo.Update( fDeltaTime ); + m_textShortcuts.Update( fDeltaTime ); - if( m_EditMode == MODE_RECORDING || m_EditMode == MODE_PLAYING ) - { - m_rectRecordBack.Update( fDeltaTime ); - } + m_rectRecordBack.Update( fDeltaTime ); if( m_EditMode == MODE_RECORDING ) { @@ -290,6 +371,11 @@ void ScreenEdit::Update( float fDeltaTime ) // m_pSong->GetBeatAndBPSFromElapsedTime( fPositionSeconds, fSongBeat, fBPS ); // LOG->Trace( "fPositionSeconds = %f, fSongBeat = %f, fBPS = %f", fPositionSeconds, fSongBeat, fBPS ); + if( m_EditMode == MODE_MENU ) + { + for( int i=0; im_fSongBeat; // save song beat @@ -352,13 +437,13 @@ void ScreenEdit::DrawPrimitives() m_NoteFieldEdit.Draw(); GAMESTATE->m_fSongBeat = fSongBeat; // restore real song beat + if( INPUTMAN->IsBeingPressed( DeviceInput(DEVICE_KEYBOARD,DIK_F1) ) ) + m_textShortcuts.Draw(); + m_textHelp.Draw(); m_textInfo.Draw(); m_Fade.Draw(); - if( m_EditMode == MODE_RECORDING || m_EditMode == MODE_PLAYING ) - { - m_rectRecordBack.Draw(); - } + m_rectRecordBack.Draw(); if( m_EditMode == MODE_RECORDING ) { @@ -387,6 +472,12 @@ void ScreenEdit::DrawPrimitives() */ } + if( m_EditMode == MODE_MENU ) + { + for( int i=0; im_fSongBeat; - const int iSongIndex = BeatToNoteRow( fSongBeat ); + int iCol = DeviceI.button - DIK_1; + const float fSongBeat = GAMESTATE->m_fSongBeat; + const int iSongIndex = BeatToNoteRow( fSongBeat ); - if( iCol >= m_NoteFieldEdit.m_iNumTracks ) // this button is not in the range of columns for this StyleDef - break; - - // check for to see if the user intended to remove a HoldNote - bool bRemovedAHoldNote = false; - for( int i=0; i= hn.m_fStartBeat && fSongBeat <= hn.m_fEndBeat ) // the cursor lies within this HoldNote - { - m_NoteFieldEdit.RemoveHoldNote( i ); - bRemovedAHoldNote = true; - break; // stop iterating over all HoldNotes - } - } - - if( !bRemovedAHoldNote ) - { - // We didn't remove a HoldNote, so the user wants to add or delete a TapNote - if( m_NoteFieldEdit.m_TapNotes[iCol][iSongIndex] == '0' ) - m_NoteFieldEdit.m_TapNotes[iCol][iSongIndex] = '1'; - else - m_NoteFieldEdit.m_TapNotes[iCol][iSongIndex] = '0'; - } - } - break; - case DIK_ESCAPE: - SCREENMAN->SetNewScreen( new ScreenEditMenu ); - break; - case DIK_S: - { - // copy edit into current Notes - Song* pSong = GAMESTATE->m_pCurSong; - Notes* pNotes = GAMESTATE->m_pCurNotes[PLAYER_1]; - - if( pNotes == NULL ) - { - // allocate a new Notes - pNotes = new Notes; - pSong->m_apNotes.Add( pNotes ); - pNotes->m_NotesType = GAMEMAN->GetStyleDefForStyle( GAMESTATE->m_CurStyle )->m_NotesType; - pNotes->m_sDescription = "Untitled"; - pNotes->m_iMeter = 1; - } - - pNotes->SetNoteData( (NoteData*)&m_NoteFieldEdit ); - GAMESTATE->m_pCurSong->SaveToSMFile(); - SOUND->PlayOnceStreamed( THEME->GetPathTo("Sounds","edit save") ); - } - break; - case DIK_UP: - case DIK_DOWN: - case DIK_PGUP: - case DIK_PGDN: - { - float fBeatsToMove; - switch( DeviceI.button ) - { - case DIK_UP: - case DIK_DOWN: - fBeatsToMove = NoteTypeToBeat( m_SnapDisplay.GetSnapMode() ); - if( DeviceI.button == DIK_UP ) - fBeatsToMove *= -1; + if( iCol >= m_NoteFieldEdit.m_iNumTracks ) // this button is not in the range of columns for this StyleDef break; - case DIK_PGUP: - case DIK_PGDN: - fBeatsToMove = BEATS_PER_MEASURE; - if( DeviceI.button == DIK_PGUP ) - fBeatsToMove *= -1; - } - const float fStartBeat = GAMESTATE->m_fSongBeat; - const float fEndBeat = GAMESTATE->m_fSongBeat + fBeatsToMove; - - // check to see if they're holding a button - for( int col=0; col= hn.m_fStartBeat && fSongBeat <= hn.m_fEndBeat ) // the cursor lies within this HoldNote { - const DeviceInput di(DEVICE_KEYBOARD, DIK_1+col); - BOOL bIsBeingHeld = INPUTMAN->IsBeingPressed(di); - - if( bIsBeingHeld ) - { - // create a new hold note - HoldNote newHN; - newHN.m_iTrack = col; - newHN.m_fStartBeat = min(fStartBeat, fEndBeat); - newHN.m_fEndBeat = max(fStartBeat, fEndBeat); - m_NoteFieldEdit.AddHoldNote( newHN ); - } + m_NoteFieldEdit.RemoveHoldNote( i ); + bRemovedAHoldNote = true; + break; // stop iterating over all HoldNotes } + } - GAMESTATE->m_fSongBeat += fBeatsToMove; - GAMESTATE->m_fSongBeat = clamp( GAMESTATE->m_fSongBeat, 0, MAX_BEATS-1 ); - GAMESTATE->m_fSongBeat = froundf( GAMESTATE->m_fSongBeat, NoteTypeToBeat(m_SnapDisplay.GetSnapMode()) ); - m_soundChangeLine.Play(); - } - break; - case DIK_HOME: - GAMESTATE->m_fSongBeat = 0; - m_soundChangeLine.Play(); - break; - case DIK_END: - GAMESTATE->m_fSongBeat = m_NoteFieldEdit.GetLastBeat(); - m_soundChangeLine.Play(); - break; - case DIK_RIGHT: - m_SnapDisplay.PrevSnapMode(); - OnSnapModeChange(); - break; - case DIK_LEFT: - m_SnapDisplay.NextSnapMode(); - OnSnapModeChange(); - break; - case DIK_RETURN: - if( m_NoteFieldEdit.m_fEndMarker != -1 && GAMESTATE->m_fSongBeat > m_NoteFieldEdit.m_fEndMarker ) + if( !bRemovedAHoldNote ) { - // invalid! The begin maker must be placed before the end marker - m_soundInvalid.Play(); - } - else - { - m_NoteFieldEdit.m_fBeginMarker = GAMESTATE->m_fSongBeat; - m_soundMarker.Play(); - } - break; - case DIK_SPACE: - if( m_NoteFieldEdit.m_fBeginMarker != -1 && GAMESTATE->m_fSongBeat < m_NoteFieldEdit.m_fBeginMarker ) - { - // invalid! The end maker must be placed after the begin marker - m_soundInvalid.Play(); - } - else - { - m_NoteFieldEdit.m_fEndMarker = GAMESTATE->m_fSongBeat; - m_soundMarker.Play(); - } - break; - case DIK_G: - case DIK_H: - case DIK_J: - case DIK_K: - case DIK_L: - { - if( m_NoteFieldEdit.m_fBeginMarker == -1 || m_NoteFieldEdit.m_fEndMarker == -1 ) - { - m_soundInvalid.Play(); - } + // We didn't remove a HoldNote, so the user wants to add or delete a TapNote + if( m_NoteFieldEdit.m_TapNotes[iCol][iSongIndex] == '0' ) + m_NoteFieldEdit.m_TapNotes[iCol][iSongIndex] = '1'; else - { - NoteType noteType1; - NoteType noteType2; - switch( DeviceI.button ) - { - case DIK_G: noteType1 = NOTE_4TH; noteType2 = NOTE_4TH; break; - case DIK_H: noteType1 = NOTE_8TH; noteType2 = NOTE_8TH; break; - case DIK_J: noteType1 = NOTE_12TH; noteType2 = NOTE_12TH; break; - case DIK_K: noteType1 = NOTE_16TH; noteType2 = NOTE_16TH; break; - case DIK_L: noteType1 = NOTE_12TH; noteType2 = NOTE_16TH; break; - default: ASSERT( false ); - } - - m_NoteFieldEdit.SnapToNearestNoteType( noteType1, noteType2, m_NoteFieldEdit.m_fBeginMarker, m_NoteFieldEdit.m_fEndMarker ); - } + m_NoteFieldEdit.m_TapNotes[iCol][iSongIndex] = '0'; } - break; - case DIK_P: - { - if( m_NoteFieldEdit.m_fBeginMarker == -1 || m_NoteFieldEdit.m_fEndMarker == -1 ) - { - m_soundInvalid.Play(); - break; - } - - m_EditMode = MODE_PLAYING; - - m_Player.Load( PLAYER_1, (NoteData*)&m_NoteFieldEdit, NULL, NULL ); - - m_rectRecordBack.BeginTweening( 0.5f ); - m_rectRecordBack.SetTweenDiffuseColor( D3DXCOLOR(0,0,0,0.5f) ); - - GAMESTATE->m_fSongBeat = m_NoteFieldEdit.m_fBeginMarker; - float fElapsedSeconds = max( 0, m_pSong->GetElapsedTimeFromBeat(GAMESTATE->m_fSongBeat) ); - m_soundMusic.SetPositionSeconds( fElapsedSeconds ); - m_soundMusic.Play(); - m_soundMusic.SetPlaybackRate( GAMESTATE->m_SongOptions.m_fMusicRate ); - } - break; - case DIK_R: - { - if( m_NoteFieldEdit.m_fBeginMarker == -1 || m_NoteFieldEdit.m_fEndMarker == -1 ) - { - m_soundInvalid.Play(); - break; - } - - // initialize m_NoteFieldRecord - m_NoteFieldRecord.ClearAll(); - m_NoteFieldRecord.m_iNumTracks = m_NoteFieldEdit.m_iNumTracks; - m_NoteFieldRecord.m_fBeginMarker = m_NoteFieldEdit.m_fBeginMarker; - m_NoteFieldRecord.m_fEndMarker = m_NoteFieldEdit.m_fEndMarker; - - - m_EditMode = MODE_RECORDING; - m_rectRecordBack.BeginTweening( 0.5f ); - m_rectRecordBack.SetTweenDiffuseColor( D3DXCOLOR(0,0,0,0.5f) ); - - GAMESTATE->m_fSongBeat = m_NoteFieldEdit.m_fBeginMarker; - float fElapsedSeconds = max( 0, m_pSong->GetElapsedTimeFromBeat(GAMESTATE->m_fSongBeat) ); - m_soundMusic.SetPositionSeconds( fElapsedSeconds ); - m_soundMusic.Play(); - m_soundMusic.SetPlaybackRate( GAMESTATE->m_SongOptions.m_fMusicRate ); - for( int i=0; im_SongOptions.m_fMusicRate == 1.0f ) GAMESTATE->m_SongOptions.m_fMusicRate = 0.9f; - else if( GAMESTATE->m_SongOptions.m_fMusicRate == 0.9f ) GAMESTATE->m_SongOptions.m_fMusicRate = 0.8f; - else if( GAMESTATE->m_SongOptions.m_fMusicRate == 0.8f ) GAMESTATE->m_SongOptions.m_fMusicRate = 0.7f; - else if( GAMESTATE->m_SongOptions.m_fMusicRate == 0.7f ) GAMESTATE->m_SongOptions.m_fMusicRate = 1.5f; - else if( GAMESTATE->m_SongOptions.m_fMusicRate == 1.5f ) GAMESTATE->m_SongOptions.m_fMusicRate = 1.4f; - else if( GAMESTATE->m_SongOptions.m_fMusicRate == 1.4f ) GAMESTATE->m_SongOptions.m_fMusicRate = 1.3f; - else if( GAMESTATE->m_SongOptions.m_fMusicRate == 1.3f ) GAMESTATE->m_SongOptions.m_fMusicRate = 1.2f; - else if( GAMESTATE->m_SongOptions.m_fMusicRate == 1.2f ) GAMESTATE->m_SongOptions.m_fMusicRate = 1.1f; - else if( GAMESTATE->m_SongOptions.m_fMusicRate == 1.1f ) GAMESTATE->m_SongOptions.m_fMusicRate = 1.0f; - break; - case DIK_INSERT: - case DIK_DELETE: - { - NoteData temp; - temp.m_iNumTracks = m_NoteFieldEdit.m_iNumTracks; - int iTakeFromRow; - int iPasteAtRow; - switch( DeviceI.button ) - { - case DIK_INSERT: - iTakeFromRow = BeatToNoteRow( GAMESTATE->m_fSongBeat ); - iPasteAtRow = BeatToNoteRow( GAMESTATE->m_fSongBeat+1 ); - break; - case DIK_DELETE: - iTakeFromRow = BeatToNoteRow( GAMESTATE->m_fSongBeat+1 ); - iPasteAtRow = BeatToNoteRow( GAMESTATE->m_fSongBeat ); - break; - } - temp.CopyRange( &m_NoteFieldEdit, iTakeFromRow, MAX_TAP_NOTE_ROWS ); - m_NoteFieldEdit.ClearRange( min(iTakeFromRow,iPasteAtRow), MAX_TAP_NOTE_ROWS ); - m_NoteFieldEdit.CopyRange( &temp, 0, MAX_TAP_NOTE_ROWS-iTakeFromRow, iPasteAtRow ); - } - break; - case DIK_X: - if( m_NoteFieldEdit.m_fBeginMarker == -1 || m_NoteFieldEdit.m_fEndMarker == -1 ) - { - m_soundInvalid.Play(); - } - else - { - int iFirstRow = BeatToNoteRow( m_NoteFieldEdit.m_fBeginMarker ); - int iLastRow = BeatToNoteRow( m_NoteFieldEdit.m_fEndMarker ); - - m_Clipboard.CopyRange( &m_NoteFieldEdit, iFirstRow, iLastRow ); - m_NoteFieldEdit.ClearRange( iFirstRow, iLastRow ); - } - break; - case DIK_C: - if( m_NoteFieldEdit.m_fBeginMarker == -1 || m_NoteFieldEdit.m_fEndMarker == -1 ) - { - m_soundInvalid.Play(); - } - else - { - int iFirstRow = BeatToNoteRow( m_NoteFieldEdit.m_fBeginMarker ); - int iLastRow = BeatToNoteRow( m_NoteFieldEdit.m_fEndMarker ); - - m_Clipboard.CopyRange( &m_NoteFieldEdit, iFirstRow, iLastRow ); - } - break; - case DIK_V: - { - int iSrcFirstRow = 0; - int iSrcLastRow = BeatToNoteRow( m_Clipboard.GetLastBeat() ); - int iDestFirstRow = BeatToNoteRow( GAMESTATE->m_fSongBeat ); - - m_NoteFieldEdit.CopyRange( &m_Clipboard, iSrcFirstRow, iSrcLastRow, iDestFirstRow ); - } - break; - - case DIK_D: - { - DifficultyClass &dc = m_pNotes->m_DifficultyClass; - dc = DifficultyClass( (dc+1)%NUM_DIFFICULTY_CLASSES ); - } - break; - - case DIK_F7: - case DIK_F8: - { - float fBPM = m_pSong->GetBPMAtBeat( GAMESTATE->m_fSongBeat ); - float fDeltaBPM; - switch( DeviceI.button ) - { - case DIK_F7: fDeltaBPM = - 0.020f; break; - case DIK_F8: fDeltaBPM = + 0.020f; break; - default: ASSERT(0); - } - switch( type ) - { - case IET_SLOW_REPEAT: fDeltaBPM *= 10; break; - case IET_FAST_REPEAT: fDeltaBPM *= 40; break; - } - float fNewBPM = fBPM + fDeltaBPM; - - for( int i=0; im_BPMSegments.GetSize(); i++ ) - if( m_pSong->m_BPMSegments[i].m_fStartBeat == GAMESTATE->m_fSongBeat ) - break; - - if( i == m_pSong->m_BPMSegments.GetSize() ) // there is no BPMSegment at the current beat - { - // create a new BPMSegment - m_pSong->AddBPMSegment( BPMSegment(GAMESTATE->m_fSongBeat, fNewBPM) ); - } - else // BPMSegment being modified is m_BPMSegments[i] - { - if( i > 0 && fabsf(m_pSong->m_BPMSegments[i-1].m_fBPM - fNewBPM) < 0.025f ) - m_pSong->m_BPMSegments.RemoveAt( i ); - else - m_pSong->m_BPMSegments[i].m_fBPM = fNewBPM; - } - } - break; - case DIK_F9: - case DIK_F10: - { - float fFreezeDelta; - switch( DeviceI.button ) - { - case DIK_F9: fFreezeDelta = -0.020f; break; - case DIK_F10: fFreezeDelta = +0.020f; break; - default: ASSERT(0); - } - switch( type ) - { - case IET_SLOW_REPEAT: fFreezeDelta *= 10; break; - case IET_FAST_REPEAT: fFreezeDelta *= 40; break; - } - - for( int i=0; im_StopSegments.GetSize(); i++ ) - { - if( m_pSong->m_StopSegments[i].m_fStartBeat == GAMESTATE->m_fSongBeat ) - break; - } - - if( i == m_pSong->m_StopSegments.GetSize() ) // there is no BPMSegment at the current beat - { - // create a new StopSegment - if( fFreezeDelta > 0 ) - m_pSong->AddStopSegment( StopSegment(GAMESTATE->m_fSongBeat, fFreezeDelta) ); - } - else // StopSegment being modified is m_StopSegments[i] - { - m_pSong->m_StopSegments[i].m_fStopSeconds += fFreezeDelta; - if( m_pSong->m_StopSegments[i].m_fStopSeconds <= 0 ) - m_pSong->m_StopSegments.RemoveAt( i ); - } - } - break; - case DIK_F11: - case DIK_F12: - { - float fOffsetDelta; - switch( DeviceI.button ) - { - case DIK_F11: fOffsetDelta = -0.020f; break; - case DIK_F12: fOffsetDelta = +0.020f; break; - default: ASSERT(0); - } - switch( type ) - { - case IET_SLOW_REPEAT: fOffsetDelta *= 10; break; - case IET_FAST_REPEAT: fOffsetDelta *= 40; break; - } - - m_pSong->m_fBeat0OffsetInSeconds += fOffsetDelta; - } - break; - case DIK_M: - MUSIC->Load( m_pSong->GetMusicPath() ); - MUSIC->Play( false, m_pSong->m_fMusicSampleStartSeconds, m_pSong->m_fMusicSampleLengthSeconds ); - break; - case DIK_F1: - case DIK_F2: - { - float fOffsetDelta; - switch( DeviceI.button ) - { - case DIK_F1: fOffsetDelta = -0.025f; break; - case DIK_F2: fOffsetDelta = +0.025f; break; - default: ASSERT(0); - } - switch( type ) - { - case IET_SLOW_REPEAT: fOffsetDelta *= 10; break; - case IET_FAST_REPEAT: fOffsetDelta *= 40; break; - } - - m_pSong->m_fMusicSampleStartSeconds += fOffsetDelta; - } - break; - case DIK_SUBTRACT: - case DIK_ADD: - { - float fDelta; - switch( DeviceI.button ) - { - case DIK_SUBTRACT: fDelta = -0.025f; break; - case DIK_ADD: fDelta = +0.025f; break; - default: ASSERT(0); - } - switch( type ) - { - case IET_SLOW_REPEAT: fDelta *= 10; break; - case IET_FAST_REPEAT: fDelta *= 40; break; - } - - m_pSong->m_fMusicSampleLengthSeconds += fDelta; - } - break; } + break; + case DIK_Q: + SCREENMAN->SetNewScreen( new ScreenEditMenu ); + break; + case DIK_S: + { + // copy edit into current Notes + Song* pSong = GAMESTATE->m_pCurSong; + Notes* pNotes = GAMESTATE->m_pCurNotes[PLAYER_1]; + + if( pNotes == NULL ) + { + // allocate a new Notes + pNotes = new Notes; + pSong->m_apNotes.Add( pNotes ); + pNotes->m_NotesType = GAMEMAN->GetStyleDefForStyle( GAMESTATE->m_CurStyle )->m_NotesType; + pNotes->m_sDescription = "Untitled"; + pNotes->m_iMeter = 1; + } + + pNotes->SetNoteData( (NoteData*)&m_NoteFieldEdit ); + GAMESTATE->m_pCurSong->SaveToSMFile(); + SOUND->PlayOnceStreamed( THEME->GetPathTo("Sounds","edit save") ); + } + break; + case DIK_UP: + case DIK_DOWN: + case DIK_PGUP: + case DIK_PGDN: + { + float fBeatsToMove; + switch( DeviceI.button ) + { + case DIK_UP: + case DIK_DOWN: + fBeatsToMove = NoteTypeToBeat( m_SnapDisplay.GetSnapMode() ); + if( DeviceI.button == DIK_UP ) + fBeatsToMove *= -1; + break; + case DIK_PGUP: + case DIK_PGDN: + fBeatsToMove = BEATS_PER_MEASURE; + if( DeviceI.button == DIK_PGUP ) + fBeatsToMove *= -1; + } + + const float fStartBeat = GAMESTATE->m_fSongBeat; + const float fEndBeat = GAMESTATE->m_fSongBeat + fBeatsToMove; + + // check to see if they're holding a button + for( int col=0; colIsBeingPressed(di); + + if( bIsBeingHeld ) + { + // create a new hold note + HoldNote newHN; + newHN.m_iTrack = col; + newHN.m_fStartBeat = min(fStartBeat, fEndBeat); + newHN.m_fEndBeat = max(fStartBeat, fEndBeat); + m_NoteFieldEdit.AddHoldNote( newHN ); + } + } + + GAMESTATE->m_fSongBeat += fBeatsToMove; + GAMESTATE->m_fSongBeat = clamp( GAMESTATE->m_fSongBeat, 0, MAX_BEATS-1 ); + GAMESTATE->m_fSongBeat = froundf( GAMESTATE->m_fSongBeat, NoteTypeToBeat(m_SnapDisplay.GetSnapMode()) ); + m_soundChangeLine.Play(); + } + break; + case DIK_HOME: + GAMESTATE->m_fSongBeat = 0; + m_soundChangeLine.Play(); + break; + case DIK_END: + GAMESTATE->m_fSongBeat = m_NoteFieldEdit.GetLastBeat(); + m_soundChangeLine.Play(); + break; + case DIK_RIGHT: + m_SnapDisplay.PrevSnapMode(); + OnSnapModeChange(); + break; + case DIK_LEFT: + m_SnapDisplay.NextSnapMode(); + OnSnapModeChange(); + break; + case DIK_RETURN: + if( m_NoteFieldEdit.m_fEndMarker != -1 && GAMESTATE->m_fSongBeat > m_NoteFieldEdit.m_fEndMarker ) + { + // invalid! The begin maker must be placed before the end marker + m_soundInvalid.Play(); + } + else + { + m_NoteFieldEdit.m_fBeginMarker = GAMESTATE->m_fSongBeat; + m_soundMarker.Play(); + } + break; + case DIK_SPACE: + if( m_NoteFieldEdit.m_fBeginMarker != -1 && GAMESTATE->m_fSongBeat < m_NoteFieldEdit.m_fBeginMarker ) + { + // invalid! The end maker must be placed after the begin marker + m_soundInvalid.Play(); + } + else + { + m_NoteFieldEdit.m_fEndMarker = GAMESTATE->m_fSongBeat; + m_soundMarker.Play(); + } + break; + case DIK_G: + case DIK_H: + case DIK_J: + case DIK_K: + case DIK_L: + { + if( m_NoteFieldEdit.m_fBeginMarker == -1 || m_NoteFieldEdit.m_fEndMarker == -1 ) + { + m_soundInvalid.Play(); + } + else + { + NoteType noteType1; + NoteType noteType2; + switch( DeviceI.button ) + { + case DIK_G: noteType1 = NOTE_4TH; noteType2 = NOTE_4TH; break; + case DIK_H: noteType1 = NOTE_8TH; noteType2 = NOTE_8TH; break; + case DIK_J: noteType1 = NOTE_12TH; noteType2 = NOTE_12TH; break; + case DIK_K: noteType1 = NOTE_16TH; noteType2 = NOTE_16TH; break; + case DIK_L: noteType1 = NOTE_12TH; noteType2 = NOTE_16TH; break; + default: ASSERT( false ); + } + + m_NoteFieldEdit.SnapToNearestNoteType( noteType1, noteType2, m_NoteFieldEdit.m_fBeginMarker, m_NoteFieldEdit.m_fEndMarker ); + } + } + break; + case DIK_ESCAPE: + { + m_EditMode = MODE_MENU; + m_iMenuSelection = 0; + MenuItemGainFocus( m_iMenuSelection ); + + m_rectRecordBack.BeginTweening( 0.5f ); + m_rectRecordBack.SetTweenDiffuseColor( D3DXCOLOR(0,0,0,0.5f) ); + } + break; + case DIK_P: + { + if( m_NoteFieldEdit.m_fBeginMarker == -1 || m_NoteFieldEdit.m_fEndMarker == -1 ) + { + m_soundInvalid.Play(); + break; + } + + m_EditMode = MODE_PLAYING; + + m_Player.Load( PLAYER_1, (NoteData*)&m_NoteFieldEdit, NULL, NULL ); + + m_rectRecordBack.BeginTweening( 0.5f ); + m_rectRecordBack.SetTweenDiffuseColor( D3DXCOLOR(0,0,0,0.5f) ); + + GAMESTATE->m_fSongBeat = m_NoteFieldEdit.m_fBeginMarker - 4; // give a 1 measure lead-in + float fElapsedSeconds = max( 0, m_pSong->GetElapsedTimeFromBeat(GAMESTATE->m_fSongBeat) ); + m_soundMusic.SetPositionSeconds( fElapsedSeconds ); + m_soundMusic.Play(); + m_soundMusic.SetPlaybackRate( GAMESTATE->m_SongOptions.m_fMusicRate ); + } + break; + case DIK_R: + { + if( m_NoteFieldEdit.m_fBeginMarker == -1 || m_NoteFieldEdit.m_fEndMarker == -1 ) + { + m_soundInvalid.Play(); + break; + } + + // initialize m_NoteFieldRecord + m_NoteFieldRecord.ClearAll(); + m_NoteFieldRecord.m_iNumTracks = m_NoteFieldEdit.m_iNumTracks; + m_NoteFieldRecord.m_fBeginMarker = m_NoteFieldEdit.m_fBeginMarker; + m_NoteFieldRecord.m_fEndMarker = m_NoteFieldEdit.m_fEndMarker; + + + m_EditMode = MODE_RECORDING; + m_rectRecordBack.BeginTweening( 0.5f ); + m_rectRecordBack.SetTweenDiffuseColor( D3DXCOLOR(0,0,0,0.5f) ); + + GAMESTATE->m_fSongBeat = m_NoteFieldEdit.m_fBeginMarker - 4; // give a 1 measure lead-in + float fElapsedSeconds = max( 0, m_pSong->GetElapsedTimeFromBeat(GAMESTATE->m_fSongBeat) ); + m_soundMusic.SetPositionSeconds( fElapsedSeconds ); + m_soundMusic.Play(); + m_soundMusic.SetPlaybackRate( GAMESTATE->m_SongOptions.m_fMusicRate ); + } + break; + case DIK_T: + if( GAMESTATE->m_SongOptions.m_fMusicRate == 1.0f ) GAMESTATE->m_SongOptions.m_fMusicRate = 0.9f; + else if( GAMESTATE->m_SongOptions.m_fMusicRate == 0.9f ) GAMESTATE->m_SongOptions.m_fMusicRate = 0.8f; + else if( GAMESTATE->m_SongOptions.m_fMusicRate == 0.8f ) GAMESTATE->m_SongOptions.m_fMusicRate = 0.7f; + else if( GAMESTATE->m_SongOptions.m_fMusicRate == 0.7f ) GAMESTATE->m_SongOptions.m_fMusicRate = 1.5f; + else if( GAMESTATE->m_SongOptions.m_fMusicRate == 1.5f ) GAMESTATE->m_SongOptions.m_fMusicRate = 1.4f; + else if( GAMESTATE->m_SongOptions.m_fMusicRate == 1.4f ) GAMESTATE->m_SongOptions.m_fMusicRate = 1.3f; + else if( GAMESTATE->m_SongOptions.m_fMusicRate == 1.3f ) GAMESTATE->m_SongOptions.m_fMusicRate = 1.2f; + else if( GAMESTATE->m_SongOptions.m_fMusicRate == 1.2f ) GAMESTATE->m_SongOptions.m_fMusicRate = 1.1f; + else if( GAMESTATE->m_SongOptions.m_fMusicRate == 1.1f ) GAMESTATE->m_SongOptions.m_fMusicRate = 1.0f; + break; + case DIK_INSERT: + case DIK_DELETE: + { + NoteData temp; + temp.m_iNumTracks = m_NoteFieldEdit.m_iNumTracks; + int iTakeFromRow; + int iPasteAtRow; + switch( DeviceI.button ) + { + case DIK_INSERT: + iTakeFromRow = BeatToNoteRow( GAMESTATE->m_fSongBeat ); + iPasteAtRow = BeatToNoteRow( GAMESTATE->m_fSongBeat+1 ); + break; + case DIK_DELETE: + iTakeFromRow = BeatToNoteRow( GAMESTATE->m_fSongBeat+1 ); + iPasteAtRow = BeatToNoteRow( GAMESTATE->m_fSongBeat ); + break; + } + temp.CopyRange( &m_NoteFieldEdit, iTakeFromRow, MAX_TAP_NOTE_ROWS ); + m_NoteFieldEdit.ClearRange( min(iTakeFromRow,iPasteAtRow), MAX_TAP_NOTE_ROWS ); + m_NoteFieldEdit.CopyRange( &temp, 0, MAX_TAP_NOTE_ROWS-iTakeFromRow, iPasteAtRow ); + } + break; + case DIK_X: + if( m_NoteFieldEdit.m_fBeginMarker == -1 || m_NoteFieldEdit.m_fEndMarker == -1 ) + { + m_soundInvalid.Play(); + } + else + { + int iFirstRow = BeatToNoteRow( m_NoteFieldEdit.m_fBeginMarker ); + int iLastRow = BeatToNoteRow( m_NoteFieldEdit.m_fEndMarker ); + + m_Clipboard.CopyRange( &m_NoteFieldEdit, iFirstRow, iLastRow ); + m_NoteFieldEdit.ClearRange( iFirstRow, iLastRow ); + } + break; + case DIK_C: + if( m_NoteFieldEdit.m_fBeginMarker == -1 || m_NoteFieldEdit.m_fEndMarker == -1 ) + { + m_soundInvalid.Play(); + } + else + { + int iFirstRow = BeatToNoteRow( m_NoteFieldEdit.m_fBeginMarker ); + int iLastRow = BeatToNoteRow( m_NoteFieldEdit.m_fEndMarker ); + + m_Clipboard.CopyRange( &m_NoteFieldEdit, iFirstRow, iLastRow ); + } + break; + case DIK_V: + { + int iSrcFirstRow = 0; + int iSrcLastRow = BeatToNoteRow( m_Clipboard.GetLastBeat() ); + int iDestFirstRow = BeatToNoteRow( GAMESTATE->m_fSongBeat ); + + m_NoteFieldEdit.CopyRange( &m_Clipboard, iSrcFirstRow, iSrcLastRow, iDestFirstRow ); + } + break; + + case DIK_D: + { + DifficultyClass &dc = m_pNotes->m_DifficultyClass; + dc = DifficultyClass( (dc+1)%NUM_DIFFICULTY_CLASSES ); + } + break; + + case DIK_F7: + case DIK_F8: + { + float fBPM = m_pSong->GetBPMAtBeat( GAMESTATE->m_fSongBeat ); + float fDeltaBPM; + switch( DeviceI.button ) + { + case DIK_F7: fDeltaBPM = - 0.020f; break; + case DIK_F8: fDeltaBPM = + 0.020f; break; + default: ASSERT(0); + } + switch( type ) + { + case IET_SLOW_REPEAT: fDeltaBPM *= 10; break; + case IET_FAST_REPEAT: fDeltaBPM *= 40; break; + } + float fNewBPM = fBPM + fDeltaBPM; + + for( int i=0; im_BPMSegments.GetSize(); i++ ) + if( m_pSong->m_BPMSegments[i].m_fStartBeat == GAMESTATE->m_fSongBeat ) + break; + + if( i == m_pSong->m_BPMSegments.GetSize() ) // there is no BPMSegment at the current beat + { + // create a new BPMSegment + m_pSong->AddBPMSegment( BPMSegment(GAMESTATE->m_fSongBeat, fNewBPM) ); + } + else // BPMSegment being modified is m_BPMSegments[i] + { + if( i > 0 && fabsf(m_pSong->m_BPMSegments[i-1].m_fBPM - fNewBPM) < 0.025f ) + m_pSong->m_BPMSegments.RemoveAt( i ); + else + m_pSong->m_BPMSegments[i].m_fBPM = fNewBPM; + } + } + break; + case DIK_F9: + case DIK_F10: + { + float fFreezeDelta; + switch( DeviceI.button ) + { + case DIK_F9: fFreezeDelta = -0.020f; break; + case DIK_F10: fFreezeDelta = +0.020f; break; + default: ASSERT(0); + } + switch( type ) + { + case IET_SLOW_REPEAT: fFreezeDelta *= 10; break; + case IET_FAST_REPEAT: fFreezeDelta *= 40; break; + } + + for( int i=0; im_StopSegments.GetSize(); i++ ) + { + if( m_pSong->m_StopSegments[i].m_fStartBeat == GAMESTATE->m_fSongBeat ) + break; + } + + if( i == m_pSong->m_StopSegments.GetSize() ) // there is no BPMSegment at the current beat + { + // create a new StopSegment + if( fFreezeDelta > 0 ) + m_pSong->AddStopSegment( StopSegment(GAMESTATE->m_fSongBeat, fFreezeDelta) ); + } + else // StopSegment being modified is m_StopSegments[i] + { + m_pSong->m_StopSegments[i].m_fStopSeconds += fFreezeDelta; + if( m_pSong->m_StopSegments[i].m_fStopSeconds <= 0 ) + m_pSong->m_StopSegments.RemoveAt( i ); + } + } + break; + case DIK_F11: + case DIK_F12: + { + float fOffsetDelta; + switch( DeviceI.button ) + { + case DIK_F11: fOffsetDelta = -0.020f; break; + case DIK_F12: fOffsetDelta = +0.020f; break; + default: ASSERT(0); + } + switch( type ) + { + case IET_SLOW_REPEAT: fOffsetDelta *= 10; break; + case IET_FAST_REPEAT: fOffsetDelta *= 40; break; + } + + m_pSong->m_fBeat0OffsetInSeconds += fOffsetDelta; + } + break; + case DIK_M: + MUSIC->Load( m_pSong->GetMusicPath() ); + MUSIC->Play( false, m_pSong->m_fMusicSampleStartSeconds, m_pSong->m_fMusicSampleLengthSeconds ); + break; + case DIK_F1: + case DIK_F2: + { + float fOffsetDelta; + switch( DeviceI.button ) + { + case DIK_F1: fOffsetDelta = -0.025f; break; + case DIK_F2: fOffsetDelta = +0.025f; break; + default: ASSERT(0); + } + switch( type ) + { + case IET_SLOW_REPEAT: fOffsetDelta *= 10; break; + case IET_FAST_REPEAT: fOffsetDelta *= 40; break; + } + + m_pSong->m_fMusicSampleStartSeconds += fOffsetDelta; + } + break; + case DIK_SUBTRACT: + case DIK_ADD: + { + float fDelta; + switch( DeviceI.button ) + { + case DIK_SUBTRACT: fDelta = -0.025f; break; + case DIK_ADD: fDelta = +0.025f; break; + default: ASSERT(0); + } + switch( type ) + { + case IET_SLOW_REPEAT: fDelta *= 10; break; + case IET_FAST_REPEAT: fDelta *= 40; break; + } + + m_pSong->m_fMusicSampleLengthSeconds += fDelta; + } + break; } } @@ -910,6 +1007,41 @@ void ScreenEdit::InputRecord( const DeviceInput& DeviceI, const InputEventType t } } +void ScreenEdit::InputMenu( const DeviceInput& DeviceI, const InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI ) +{ + if( DeviceI.device != DEVICE_KEYBOARD ) + return; + + switch( DeviceI.button ) + { + case DIK_UP: + MenuItemLoseFocus( m_iMenuSelection ); + m_iMenuSelection = (m_iMenuSelection-1+NUM_MENU_ITEMS) % NUM_MENU_ITEMS; + printf( "%d\n", m_iMenuSelection ); + MenuItemGainFocus( m_iMenuSelection ); + break; + case DIK_DOWN: + MenuItemLoseFocus( m_iMenuSelection ); + m_iMenuSelection = (m_iMenuSelection+1) % NUM_MENU_ITEMS; + printf( "%d\n", m_iMenuSelection ); + MenuItemGainFocus( m_iMenuSelection ); + break; + case DIK_RETURN: + case DIK_ESCAPE: + m_EditMode = MODE_EDITING; + m_rectRecordBack.BeginTweening( 0.5f ); + m_rectRecordBack.SetTweenDiffuseColor( D3DXCOLOR(0,0,0,0) ); + MenuItemLoseFocus( m_iMenuSelection ); + if( DeviceI.button == DIK_RETURN ) + { + SOUND->PlayOnceStreamed( THEME->GetPathTo("Sounds","menu start") ); + int iMenuKey = MENU_ITEM_KEY[m_iMenuSelection]; + InputEdit( DeviceInput(DEVICE_KEYBOARD,iMenuKey), IET_FIRST_PRESS, GameInput(), MenuInput(), StyleInput() ); + } + break; + } +} + void ScreenEdit::InputPlay( const DeviceInput& DeviceI, const InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI ) { if( type != IET_FIRST_PRESS ) @@ -980,3 +1112,16 @@ void ScreenEdit::OnSnapModeChange() int iStepIndexHangover = iStepIndex % iElementsPerNoteType; GAMESTATE->m_fSongBeat -= NoteRowToBeat( iStepIndexHangover ); } + +void ScreenEdit::MenuItemGainFocus( int iItemIndex ) +{ + m_textMenu[iItemIndex].SetEffectCamelion( 2.5, D3DXCOLOR(1,1,1,1), D3DXCOLOR(0,1,0,1) ); + m_textMenu[iItemIndex].SetZoom( 0.7f ); + SOUND->PlayOnceStreamed( THEME->GetPathTo("Sounds","edit menu change") ); +} + +void ScreenEdit::MenuItemLoseFocus( int iItemIndex ) +{ + m_textMenu[iItemIndex].SetEffectNone(); + m_textMenu[iItemIndex].SetZoom( 0.5f ); +} diff --git a/stepmania/src/ScreenEdit.h b/stepmania/src/ScreenEdit.h index 3047dd5b0e..c02c8b941e 100644 --- a/stepmania/src/ScreenEdit.h +++ b/stepmania/src/ScreenEdit.h @@ -22,6 +22,9 @@ #include "SnapDisplay.h" +const int NUM_MENU_ITEMS = 19; + + class ScreenEdit : public Screen { public: @@ -31,6 +34,7 @@ public: virtual void DrawPrimitives(); virtual void Input( const DeviceInput& DeviceI, const InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI ); void InputEdit( const DeviceInput& DeviceI, const InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI ); + void InputMenu( const DeviceInput& DeviceI, const InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI ); void InputRecord( const DeviceInput& DeviceI, const InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI ); void InputPlay( const DeviceInput& DeviceI, const InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI ); virtual void HandleScreenMessage( const ScreenMessage SM ); @@ -39,9 +43,10 @@ public: protected: void OnSnapModeChange(); + void MenuItemGainFocus( int iItemIndex ); + void MenuItemLoseFocus( int iItemIndex ); - - enum EditMode { MODE_EDITING, MODE_RECORDING, MODE_PLAYING }; + enum EditMode { MODE_EDITING, MODE_MENU, MODE_RECORDING, MODE_PLAYING }; EditMode m_EditMode; Song* m_pSong; @@ -55,6 +60,7 @@ protected: BitmapText m_textInfo; // status information that changes BitmapText m_textHelp; + BitmapText m_textShortcuts; // keep track of where we are and what we're doing float m_fTrailingBeat; // this approaches GAMESTATE->m_fSongBeat, which is the actual beat @@ -71,7 +77,6 @@ protected: // for MODE_RECORD - Quad m_rectRecordBack; NoteField m_NoteFieldRecord; GrayArrowRow m_GrayArrowRowRecord; @@ -81,8 +86,11 @@ protected: // for MODE_RECORD and MODE_PLAY + Quad m_rectRecordBack; RageSoundStream m_soundMusic; - bool m_bLayingAHold[MAX_NOTE_TRACKS]; + + int m_iMenuSelection; + BitmapText m_textMenu[NUM_MENU_ITEMS]; }; diff --git a/stepmania/src/ScreenEditMenu.cpp b/stepmania/src/ScreenEditMenu.cpp index c619a7fb86..d1c8b65330 100644 --- a/stepmania/src/ScreenEditMenu.cpp +++ b/stepmania/src/ScreenEditMenu.cpp @@ -179,7 +179,7 @@ void ScreenEditMenu::HandleScreenMessage( const ScreenMessage SM ) // Set the current Style, then let ScreenEdit infer the desired // NotesType from that Style. NotesType nt = GetSelectedNotesType(); - Style style = GAMEMAN->GetStyleThatPlaysNotesType( nt ); + Style style = GAMEMAN->GetEditStyleThatPlaysNotesType( nt ); GAMESTATE->m_CurStyle = style; GAMESTATE->m_CurGame = GAMEMAN->GetStyleDefForStyle(style)->m_Game; @@ -358,7 +358,7 @@ void ScreenEditMenu::MenuStart( const PlayerNumber p ) // find the first style that matches this notes type GameDef* pGameDef = GAMESTATE->GetCurrentGameDef(); - GAMESTATE->m_CurStyle = GAMEMAN->GetStyleThatPlaysNotesType( GetSelectedNotesType() ); + GAMESTATE->m_CurStyle = GAMEMAN->GetEditStyleThatPlaysNotesType( GetSelectedNotesType() ); GAMESTATE->m_pCurNotes[PLAYER_1] = GetSelectedNotes(); m_soundSelect.PlayRandom(); diff --git a/stepmania/src/ScreenSelectStyle.cpp b/stepmania/src/ScreenSelectStyle.cpp index e14608075b..a6983fb550 100644 --- a/stepmania/src/ScreenSelectStyle.cpp +++ b/stepmania/src/ScreenSelectStyle.cpp @@ -53,7 +53,7 @@ ScreenSelectStyle::ScreenSelectStyle() GAMESTATE->m_CurStyle = STYLE_NONE; GAMESTATE->m_bPlayersCanJoin = true; - GAMEMAN->GetStylesForGame( GAMESTATE->m_CurGame, m_aPossibleStyles ); + GAMEMAN->GetGameplayStylesForGame( GAMESTATE->m_CurGame, m_aPossibleStyles ); m_iSelection = 0; for( int i=0; iDoesThemeExist( THEME->GetCurThemeName() ) ) { - CStringArray asThemeNames; - THEME->GetThemeNamesForCurGame( asThemeNames ); - THEME->SwitchTheme( asThemeNames[0] ); + CString sGameName = GAMESTATE->GetCurrentGameDef()->m_szName; + if( THEME->DoesThemeExist( sGameName ) ) + { + THEME->SwitchTheme( sGameName ); + } + else + { + CStringArray asThemeNames; + THEME->GetThemeNamesForCurGame( asThemeNames ); + THEME->SwitchTheme( asThemeNames[0] ); + } } + m_sprBG.Load( THEME->GetPathTo("Graphics","title menu background") ); m_sprBG.StretchTo( CRect(0,0,SCREEN_WIDTH,SCREEN_HEIGHT) ); this->AddSubActor( &m_sprBG ); diff --git a/stepmania/src/SnapDisplay.cpp b/stepmania/src/SnapDisplay.cpp index 759222bc1f..ec55ac8d10 100644 --- a/stepmania/src/SnapDisplay.cpp +++ b/stepmania/src/SnapDisplay.cpp @@ -36,7 +36,7 @@ SnapDisplay::SnapDisplay() m_iNumCols = 0; } -void SnapDisplay::Load() +void SnapDisplay::Load( PlayerNumber pn ) { m_iNumCols = GAMESTATE->GetCurrentStyleDef()->m_iColsPerPlayer; diff --git a/stepmania/src/SnapDisplay.h b/stepmania/src/SnapDisplay.h index eb114d8561..89532addb6 100644 --- a/stepmania/src/SnapDisplay.h +++ b/stepmania/src/SnapDisplay.h @@ -24,7 +24,7 @@ class SnapDisplay : public ActorFrame public: SnapDisplay(); - void Load(); + void Load( PlayerNumber pn ); bool PrevSnapMode(); bool NextSnapMode(); diff --git a/stepmania/src/Song.cpp b/stepmania/src/Song.cpp index afbd9a5896..aff6598d96 100644 --- a/stepmania/src/Song.cpp +++ b/stepmania/src/Song.cpp @@ -1315,6 +1315,55 @@ void Song::SaveToSMFile( CString sPath ) fclose( fp ); } +void Song::SaveToSMAndDWIFile() +{ + LOG->Trace( "Song::SaveToSMAndDWIFile()" ); + + SaveToSMFile(); + + CString sPath = GetSongFilePath(); + sPath.Replace( ".sm", ".dwi" ); + + + FILE* fp = fopen( sPath, "w" ); + if( fp == NULL ) + throw RageException( "Error opening song file '%s' for writing.", sPath ); + + fprintf( fp, "#TITLE:%s;\n", GetFullTitle() ); + fprintf( fp, "#ARTIST:%s;\n", m_sArtist ); + ASSERT( m_BPMSegments[0].m_fStartBeat == 0 ); + fprintf( fp, "#BPM:%.2f;\n", m_BPMSegments[0].m_fBPM ); + fprintf( fp, "#GAP:%d;\n", -roundf( m_fBeat0OffsetInSeconds*1000 ) ); + + fprintf( fp, "#FREEZE:" ); + for( int i=0; iWriteDWINotesTag( fp ); + + fclose( fp ); +} + Grade Song::GetGradeForDifficultyClass( NotesType nt, DifficultyClass dc ) { CArray aNotes; diff --git a/stepmania/src/Style.h b/stepmania/src/Style.h index 31623f0896..d0db70b6c0 100644 --- a/stepmania/src/Style.h +++ b/stepmania/src/Style.h @@ -17,6 +17,7 @@ enum Style STYLE_DANCE_DOUBLE, STYLE_DANCE_COUPLE, STYLE_DANCE_SOLO, + STYLE_DANCE_EDIT_COUPLE, STYLE_PUMP_SINGLE, STYLE_PUMP_VERSUS, STYLE_PUMP_DOUBLE, diff --git a/stepmania/src/StyleDef.h b/stepmania/src/StyleDef.h index 6eed2fdf47..f04f07d215 100644 --- a/stepmania/src/StyleDef.h +++ b/stepmania/src/StyleDef.h @@ -35,10 +35,12 @@ class GameDef; class StyleDef { public: - Game m_Game; // Game this style is active under + Game m_Game; // Which Game is this Style used with? + bool m_bUsedForGameplay; // Can be used only for gameplay? + bool m_bUsedForEdit; // Can be used for editing? char m_szName[60]; - NotesType m_NotesType; // the notes format that this style reads. - // For example, the "dance versus" reads the Notes with the tag "dance-single". + NotesType m_NotesType; // the notes format that this style reads. + // For example, the "dance versus" reads the Notes with the tag "dance-single". enum StyleType { ONE_PLAYER_ONE_CREDIT, // e.g. single diff --git a/stepmania/src/song.h b/stepmania/src/song.h index 18073592b5..e7e82be334 100644 --- a/stepmania/src/song.h +++ b/stepmania/src/song.h @@ -57,6 +57,7 @@ public: void TidyUpData(); // call after loading to clean up invalid data void SaveToSMFile( CString sPath = "" ); // no path means save to SongFilePath + void SaveToSMAndDWIFile(); // saves SM, then saves DWI so that the SM is the master copy and NoteTypes not supported by DWI are not lost void SaveToCacheFile(); CString GetSongFilePath();